Well it’s been a while since I’ve blogged… There’ve been a few distractions, starting with Beta 1, then vacation, and now things are back to normal. So it seems reasonable to blog about something that we’ve just shipped in Whidbey Beta 1: The cooperative fiber mode sample that’s been included in the SDK. You can get the freely downloadable SDK here. If you load up the documentation, go to the Contents, and select Samples->Application Samples->Cooperative Fiber Mode Application Sample you’ll be able to get to the code.
This sample shows how to write an extremely simple fiber mode host. But it does so with a twist. Instead of scheduling the tasks in a cooperative, automatic, and transparent fashion this sample exposes the concept of fibers to managed code. This allows the managed code author to use fibers as the unmanaged code author would. This results in an implementation that for the most part relies upon native threads. The only time fibers are actually used is when the user explicitly chooses to use them. This closely matches the experience you’d have programming with fibers in the unmanaged world. More sophisticated hosts would want to implement their own synchronization primitives that would schedule other tasks while blocking.
Over the next several blogentries I plan to give a walk through of the new fiber mode sample. During this blog I’ll start with loading the runtime and getting bootstrapped into managed code. But first let me give a brief warning. Fiber mode is complex and hard to get right. You probably don’t want to implement fiber mode into your application on a whim. Weigh your other options carefully before jumping into running in fiber mode.
Loading the runtime hasn’t changed in a significant fashion from v1.0 and v1.1. We start with a call that should be familiar to anyone who has written code to host the runtime before:
// load up the runtime
HRESULT hr = CorBindToRuntimeEx(
NULL, // version of the runtime to request
NULL, // flavor of the runtime to request
0, // runtime startup flags
CLSID_CLRRuntimeHost, // clsid of ICLRRuntimeHost
IID_ICLRRuntimeHost, // IID of ICLRRuntimeHost
(PVOID*)&pClrHost); // a pointer to our punk that we get
The only difference you may notice is that we’re asking for a different interface. Previously we asked for CLSID_CorRuntimeHost and IID_ICorRuntimeHost. In Whidbey we have a brand new interface that let you do much more.
Next, we have a new call:
hr = pClrHost->SetHostControl(static_cast<IHostControl *>(&hostControl));
This new command is handing off to the runtime our IHostControl interface. It’s not a required call for hosting the runtime, but it’s the mechanism through which we provide our threading managers (so it is required for fiber mode). One callback on this API is GetHostManager which when called by the runtime allows the host to provide a manager. The host managers provide threading, memory, assembly loading, or other low level functionality to the runtime. Throughout the next couple of articles I’ll be strictly focused on the threading managers.
After we hand off our host control we’re back to familiar territory again:
hr = pClrHost->Start();
Now the runtime has been started and we can start executing managed code. And the way we start doing this has changed in Whidbey. There are a few different mechanisms, and I’ll mention 2 of them. The first is the app domain manager. This allows a host to have an assembly loaded into every domain, including the default domain. Once this assembly is loaded the host can start running managed code directly from it. The other option is a sample call to execute an assembly passing it a string of arguments. This sample uses the 2nd method as it’s simpler and sufficient for our purposes:
hr = pClrHost->ExecuteInDefaultAppDomain(
curDir, // directory to assembly
L"Microsoft.Samples.FiberBootstrap",// Type name to load
L"EntryPoint", // Method name to execute
bootstrapArgs, // Arguments to be passed in
&retVal); // return value of function
The executed function exists in a separate managed DLL (FiberBootstrap.dll). It simply parses the string and then calls AppDomain.ExecuteAssembly on the current domain. This allows the sample to run any managed assembly you pass to it. This EXE that gets loaded then can interact with the fiber mode APIs.
At this point we’ve loaded the runtime, loaded an assembly into the default domain and executed managed code. That’s really all there is to getting started. If you were a simpler host you wouldn’t even need the SetHostControl call! In the next article I’ll discuss what that SetHostControl call is setting up for us.