Cooperative Fiber Mode Sample - Day 1

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 blog entries 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.

Comments

  • Anonymous
    August 17, 2004
    The comment has been removed
  • Anonymous
    August 17, 2004
    Mark,

    You have several options, for the most part they're the same options you use to interop between native / managed code. And there's also been some work in Whidbey to try and make this easy for the host.

    P/Invoke: You can P/Invoke directly into your host (the coop fiber mode sample does this from the managed Fiber class). You can even pass a delegate from managed code into your host that you can call right back into (just make sure to keep a reference to the delegate so it doesn't get collected). Again, this is something the coop fiber sample does for the starting point of newly created fibers. This is best if you don't have a whole lot of calls into the host.

    COM Interop: You can create COM objects in your host and hand them into the runtime, and return managed objects that implement COM interfaces back to the host. In Whidbey one new feature is the AppDomainManager (which the Coop Fiber sample doesn't use). You give the runtime an AppDomainManager assembly & type, and it loads that object (which inherits from AppDomainManager) into every app domain. The host then gets a callback where it's handed the AppDomainManager IUnknown. If you implement a COM interface on it you can QueryInterface it for your interface. You can hand yourself COM objects in the same manner using P/Inovke. If you're going to get deep into COM Interop check out Adam Nathan's .NET and COM book.

    Third option is MC++. You could do this instead of hosting (keeping most of the existing unmanaged, writing new code in managed C++) or with hosting. You could write your interop code in MC++, and have it be the gateway between your unmanaged code and managed code.

    I don't really have any links on this handy, but I think a search on any 1 of those 3 will yield you more information.
  • Anonymous
    June 08, 2009
    PingBack from http://insomniacuresite.info/story.php?id=4644