Last week we went over the Abort and RudeAbort APIs.  This week we’ll go over Fiber.Exit.  This API provides a way for you to terminate a running fiber, and demonstrates a use of the unmanaged ICLRTask::ExitTask API.   The ExitTask API can only be called on a fiber that is currently switched in which gives us a similar problem to what we had in Abort/RudeAbort.  But because the ExitTask call will not block for a long period of time we handle it a little differently than Abort and RudeAbort.

 

After checking & updating our state like we did in Abort and RudeAbort, the ExitTask API does:

 

if (this == Fiber.CurrentFiber)

{

      // exiting a running task is easy

      InternalExitTaskAndThread(fiberAddr);

}

else

{

      // only tasks that are running can call ICLRTask::ExitTask.

      // We need to switch the task in, call ExitTask, and then

      // switch back to our current fiber.

      InternalExitTaskAndSwitch(fiberAddr, Fiber.CurrentFiber.m_fiberAddr);

}

 

Here you can see we take one of two actions.  Either we call InternalExitTaskAndTherad() which will cause both the current thread and fiber to exit, or we call into InternalExitTaskAndSwitch. 

 

The first call is pretty self-explanatory.  We’re the current thread, we want to let the whole thing die off – this is exactly the same to calling DeleteFiber on the currently running thread.

 

The second call is a little different.  Here we have a fiber that is currently switched out.  We want to re-schedule the fiber we’re asking to exit, call ExitTask on it, and then switch back to our previously running fiber.   Here we go back to the code in SwitchIn that we looked at in article 4:

 

if(curTask->FlagCheck(TASK_FLAG_EXITING))

{

       _ASSERTE(curTask->GetSwitchingTo());

       curTask->ExitTask();

       curTask->GetSwitchingTo()->SwitchIn();

}

 

The task has been requested to exit, we call ICLRTask::Exit on it, and then we switch back to the previously running task having completed the work the user requested.

 

One note worthy point here is that like the DeleteFiber APIs, the ExitTask API is potentially unsafe.  This is because we’re exiting the thread with code higher us still on the stack.  This code may have resources to free or other state to clean up.  Typically a host would only call ExitTask after all managed code has left the stack. 

 

That brings us to the end of the CoopFiber series.  We’ve gone over the smallest set of APIs that are required for implementing fiber mode.  We’ve then exposed the APIs to the managed code author to allow them to be in control of the scheduling.  To implement a scheduler on top of this would require updating the synchronization primitives so they’d select new tasks and switch them in instead of blocking the thread.  And hopefully you’ve walked away from all of this with a better understanding of the interactions between the CLR and the host when running in fiber mode.