When I last left off we went over the host control. The host control hands off our task and synchronization managers. Now it’s time to take a look at the two host-implemented managers, starting with the task manager.
I’m going to skip over the minor details such as constructors, destructors, etc… and only focus in on the details of the APIs that communicate with the CLR. The APIs we care about the most are GetCurrentTask and CreateTask. A fiber mode host with it’s own scheduler would pay more attention to APIs like Sleep (where we merely call the OS API), SwitchToTask (which is a NOP in CoopFiber), and the other APIs. Because CoopFiber doesn’t have a scheduler we aren’t concerned with these APIs. So if we look at GetCurrentTask:
CHostTask *curTask = CHostTask::GetCurrentTask(false);
// 0x1E00 - value returned by GetCurrentFiber when not a fiber
curTask = CHostTask::CreateTask(ConvertThreadToFiber(NULL),TASK_FLAG_RUNNING);
curTask = CHostTask::CreateTask(GetCurrentFiber(),TASK_FLAG_RUNNING);
*pTask = (IHostTask *)curTask;
We simply check to see if the current task has been created. If it hasn’t we create a new task. Depending on whether or not we’re already running on a fiber (by some chance) we’ll re-use the fiber, otherwise we’ll create a new fiber. Here we choose to allow any random threads that enter into the CLR to be converted to fibers. A host could also deny these threads entrance by returning HOST_E_INVALIDOPERATION.
The other interesting API is CreateTask:
CHostTask *tmp = CHostTask::CreateTask();
if (tmp == NULL)
_ASSERTE(FALSE && "Out of memory in CreateTask!");
*ppTask = (IHostTask *)tmp;
This isn’t really doing anything too fancy. We’re just creating out internal task implementation which implements IHostTask. We’re handing that off to the runtime. Later the runtime will call Start on it and it’ll kick off the running of a new task. We’ll look at the IHostTask implementation next time.