Udostępnij za pośrednictwem


Cooperative Fiber Mode Sample - Day 10

In this article we’re going to look at the implementation of Abort and RudeAbort.  In the last article I mentioned that a typical host wouldn’t need to expose these to managed code.  Why is that?  If you have a fiber mode scheduler typically Thread.Abort will be sufficient.  Your scheduler will eventually schedule the task, and the task will then be aborted.

 

But in the CoopFiber sample we don’t have a scheduler.  Therefore a user could call Thread.Abort on a switched out fiber, and it would never get scheduled to be aborted.  What’s worse is that the call into ICLRTask::Abort will block until the thread gets scheduled again.  

 

To handle this peculiarity when an Abort request comes in the Fiber class first determines whether the task is running or not.  If it is already running then we’ll go ahead and abort it right away.  Otherwise we’ll set a bit to notify that on the next switch we should abort the task.  Here’s the Fiber.Abort implementation:

 

bool fAbortNeeded = false;

lock (m_syncObj)

{

      m_FiberStates |= FiberStates.AbortRequested;

      if ((m_FiberStates & FiberStates.Running) != 0 && (m_FiberStates & FiberStates.Switching) == 0)

      {

            //the current fiber is aborted, so we can initiate the abort now.

            fAbortNeeded = true;

      }

}

if (fAbortNeeded)

{

      InternalAbort(m_fiberAddr);

}

InternalAbort will just turn around and call ICLRTask::Abort on our already switched in task.  In our last article we saw our calls to CheckForAbort during task switch in.  That code simply looks like:

 

// Next see if the user requested an abort on this thread.

if ((m_FiberStates & FiberStates.AbortRequested) != 0)

{

Abort();

}

else if ((m_FiberStates & FiberStates.RudeAbortRequested) != 0)

{

      RudeAbort();

}

           

We simply call back to Abort or RudeAbort, which will then call into InternalAbort to finally Abort/RudeAbort the task.  The task is now switched in and running so we’ll call into the host to perform the actual abort (which now won’t block because the task is running).

 

At this point you may be asking yourself “What is this Rude Abort thing?”  Rude aborts are actually a new Whidbey feature, and can be accessed one of several ways.  The only difference between a rude abort and a normal thread abort is that the rude abort will not execute your catch/finally blocks.  In addition to being exposed directly through the hosting APIs rude abort’s can also occur due to escalation policy (also configured via the hosting APIs).  That’ll have to be saved for another blog entry…

 

CoopFiber’s Rude Abort implementation is essentially identical to the Abort implementation.  The only difference is that we’ve replaced the work Abort with RudeAbort everywhere.

 

So that’s it for the Abort/Rude Abort implementation.  We’ve almost reached the end of this serious, but there’s one last API that’s worth covering on the managed size: Fiber.Exit.  I’ll go over that implementation next article.