Cooperative Fiber Mode Sample - Day 7

At this point we’ve covered nearly all the major components of the unmanaged host.  The one remaining detail is the interface that’s used between the managed fiber mode implementation and the unmanaged host.  This is all implemented in callbacks.cpp.  We essentially expose an API for all the major operations we allow the fiber API to do.  These include creating fibers, switching fibers in, aborting fibers, and exiting the current fiber.

 

The creation of a fiber differs from the CreateTask API we covered before in that we aren’t creating a new thread for this fiber.  This fiber is newly created and won’t run until a user switches it in.  Aborting fibers is exactly like aborting a thread, but a fiber will need to be switched in to be properly aborted. 

 

Switching in fibers is interesting.  Here you’ll find no “SwitchOut” API like the internal unmanaged SwitchOut method on CHostTask.  This is because we cannot run managed code on a “switched out” task.  It has to have some task to run on!  Instead CoopFiber exposes one API for switching in a new task that also switches out the current task.

 

All of these methods are merely thin wrappers over the functionality we’ve already covered.  Two interesting examples of the several functions include InternalCreateFiber and InternalSwitchIn.

 

First let’s look at InternalCreateFiber:

 

      __declspec(dllexport) PVOID InternalCreateFiber(PVOID startAddr)

    {

            CHostTask *tmp = CHostTask::CreateTask();

            if (tmp == NULL)

            {

                  _ASSERTE(FALSE && "Out of memory in CreateTask!");

                  return NULL;

            }

            tmp->SetManagedStart(reinterpret_cast<LPTHREAD_START_ROUTINE>(startAddr));

           

            tmp->AddRef();

            tmp->SetFiberAddress(::CreateFiber(0,(LPFIBER_START_ROUTINE )CHostFiberProc,(PVOID)tmp));

            return(tmp);

      }

This function creates a new CHostTask, sets the start address (which is a delegate passed from managed code), and create a new fiber for the task.  We return the task back to managed code which now holds the only reference to it.

 

The interesting thing to note is the management of the lifetime of the CHostTask.  We have 1 reference to it from the managed code.  As we’ll see later the managed code uses a new Whidbey feature called SafeHandle.  This ensures that when the managed Fiber object is collected our InternalReleaseFiber method will be called.

 

Next let’s look at InternalSwitchIn:

 

      __declspec(dllexport) void InternalSwitchIn(CHostTask *task)

      {

            CHostTask *curTask = CHostTask::GetCurrentTask();

            _ASSERTE(curTask && task);

            curTask->SwitchOut();

            task->SwitchIn();

      }

 

Here we get the current task, switch it out, and switch in the task passed in.  Again, we have another simple thin wrapper over the APIs we’ve already seen.  All of the other callbacks are thin wrapper as well.

 

So we’ve now covered nearly all the main principals of the unmanaged code.  Soon we can start to discuss what the host is going to expose to the managed code author!