Cooperative Fiber Mode Sample - Day 9

The managed Fiber class exists in its own directory in the SDK sample appropriately called Fiber.  The Fiber class is designed to be vaguely similar to the managed Thread class.  For example, like the Thread has ThreadState the fiber has FiberStates.

 

The managed fiber class exposes a few significant APIs:

· public static Fiber CreateFiber(FiberStart fs)

· public static Fiber CurrentFiber

· public void SwitchTo()

· public void Abort()

· public void RudeAbort()

· public void Exit()

· public FiberStates FiberState

 

The CreateFiber API should be obvious.  It takes a FiberStart delegate and passes it into the unmanaged InternalCreateFiber API we previously looked at.

 

CurrentFiber is nearly just as obvious: We store the current fiber in managed thread local storage (or in our case it’s really fiber local storage) so we can easily fetch it.  If we haven’t created a managed Fiber object for this fiber yet we’ll get it from the host via a P/Invoke into the InternalGetCurrentFiber API. This simply gets the currently executing CHostTask, AddRef’s it, and returns it.  The managed half simply sticks this into our SafeHandle to ensure it’s properly cleaned up.

 

The last trivial method here is FiberState.  This just returns m_FiberStates which the managed Fiber class maintains as the fibers switch through various states.

 

The interesting APIs here though are actually SwitchTo, Abort, and RudeAbort.  We’ll start at looking at SwitchTo.

 

The first thing we watch out for in the managed implementation is that we don’t try and switch a fiber in on 2 threads:

 

Fiber curFiber = CurrentFiber;

lock (m_syncObj)

{

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

      {

            throw new FiberStateException("Attempt to switch to a fiber that is running or already switching!");

      }

      m_FiberStates &= (~FiberStates.Unstarted);

      m_FiberStates |= FiberStates.Running;

}

If the fiber was already running, or is currently involved in a switch, then we’ll throw an exception that you cannot currently switch.  We’ll then update the fiber we’re trying to switch in so it’s now officially running (this will prevent anyone else from switching it in).

 

Next we need to make sure that no one races in and tries switching in the fiber we’re switching away from. 

 

lock (curFiber.m_syncObj)

{

      m_FiberStates |= FiberStates.Switching;

}

// we've marked us as switching, do one last check to see if someone wanted to abort us.

// Anyone after this will get us aborted on our next switch in.

CheckForAbort();

So we update its state to mark that it’s currently switching out.  You’ll also notice we’re checking to see if we need to abort a thread.  We’ll cover this more in-depth in the next article where I discuss the Abort & RudeAbort implementation.

 

      m_prevFiber = curFiber;

      // switch in the fiber the user requested

      InternalSwitchIn(m_fiberAddr);

      curFiber.OnFiberSwitchIn();

Next we mark what the previous fiber was (we’ll need to update it to remove the Running & Switching bits), and then call back into the unmanaged host to perform the actual switch.  This goes into the API that we looked at in Article 7 – we simply switch out the current task, and switch in the new one that we passed in.

 

Finally we call OnFiberSwitchIn.  Again this is another place where we have both a top-half before the switch, and a bottom-half after we’ve switched away and switched back.  When we do the switch in if it’s the 1st time a task has been scheduled we’ll end up back at RealFiberStart. If this task has already switched out once, we’ll end up at the curFiber.OnFiberSwitchIn line, but we’ll be on a different fiber (we’ll be on curFiber).  In either case we’ll set the state on the previous fiber so that it’ll be schedulable again, and we’ll check the newly switched in fiber to see if it should be aborted.

 

And that’s how we switch fibers.  You first create a fiber, and then you call SwitchTo on the newly created fiber.  We largely just do some book keeping, and then call directly into the host to do the switch.  It’s that simple. 

 

That takes us through nearly all the basic mechanisms of the fiber mode host.  In the next article I’m going to discuss how the Fiber class exposes Abort and RudeAbort APIs.  A typical host wouldn’t expose these to managed code, but the CoopFiber sample has it’s reasons for doing so…

 

[9/16 8:00PM - Fixed grammer]