/// <summary> /// Create a message fiber instance /// </summary> public MessageFiberBase() { RunInternalWaitCallback = RunInternal; m_SyncContext = new FiberSyncContext(this); tail = lastTale = new MessageNodeBase() { Next = Blocked }; }
internal void EnqueueInternal(MessageNodeBase newTail) { var oldTail = Atomic.Swap(ref tail, newTail); //if oldtail is null or tailing is failed if (!TryTail(oldTail, newTail)) { //statis is a single object in heap, no further allocation with object[] ThreadPool.QueueUserWorkItem(RunInternalWaitCallback, newTail); } }
void RunInternal(object obj) { var messageNode = (MessageNodeBase)obj; //because it's thread specific value, we dont need to set //null everytime. CurrentIFiber = this; var cachedContext = SynchronizationContext.Current; SynchronizationContext.SetSynchronizationContext(m_SyncContext); do { //restore blocked, let it can be recycle lastTale.PushToPool(); //remember last tale to be continued lastTale = messageNode; try { InvokeMessage(messageNode); } catch (Exception e) { HandleException(e); } //if next is null, then it successfully replace it's Next to Blocked //otherwise messagenode is what recently trytail'ed messageNode = GetNext(messageNode); }while (messageNode != null); SynchronizationContext.SetSynchronizationContext(cachedContext); //now we're done is this thread pool thread, CurrentIFiber = null; }
internal override void InvokeMessage(MessageNodeBase message) { message.Invoke(); }
internal abstract void InvokeMessage(MessageNodeBase message);
//get next node and mark it as blocked //if it's not null, we dont need to execute exchange function static MessageNodeBase GetNext(MessageNodeBase prev) { return(Atomic.Swap(ref prev.Next, Blocked)); }
//if next is already blocked, then previous actions are already executed. static bool TryTail(MessageNodeBase prev, MessageNodeBase next) { return(Atomic.SwapIfSame(ref prev.Next, next, null)); }