public static void DoYield(RCRunner runner, RCClosure closure, RCValue result) { if (result == null) { throw new ArgumentNullException("result"); } // Check to see if this fiber was killed before moving on RCBot bot = runner.GetBot(closure.Bot); if (bot.IsFiberDone(closure.Fiber)) { runner.Continue(closure, null); return; } // Do not permit any further changes to result or its children values. result.Lock(); RCClosure next = closure.Code.Next(runner, closure, closure, result); if (next == null) { result = closure.Code.Finish(runner, closure, result); bot.ChangeFiberState(closure.Fiber, "done"); RCSystem.Log.Record(closure, "fiber", closure.Fiber, "done", ""); if (closure.Fiber == 0 && closure.Bot == 0) { runner.Finish(closure, result); } // This will handle fibers that wake up from some suspended state // without realizing that they have been killed. else { bot.FiberDone(runner, closure.Bot, closure.Fiber, result); } // Remove closure from the pending queue. runner.Continue(closure, null); } else { runner.Continue(closure, next); } }
public void Finish(RCClosure closure, Exception exception, long status) { RCValue result = null; RCClosure parent = closure; RCBot bot = GetBot(closure.Bot); while (parent != null && parent.Bot == closure.Bot && parent.Fiber == closure.Fiber) { if (parent.InCodeEval) { RCClosure next = parent.Code.Handle(this, parent, exception, status, out result); if (result != null && next == null) { string state = status == 1 ? "caught" : "killed"; bot.ChangeFiberState(closure.Fiber, state); RCSystem.Log.Record(closure, "fiber", closure.Fiber, state, exception); if (closure.Fiber == 0 && closure.Bot == 0) { Finish(closure, result); } else { bot.FiberDone(this, closure.Bot, closure.Fiber, result); } return; } else { Continue(null, next); } if (result != null) { bot.ChangeFiberState(closure.Fiber, "caught"); RCSystem.Log.Record(closure, "fiber", closure.Fiber, "caught", exception); ++_exceptionCount; return; } } parent = parent.Parent; } // This means it was not handled in the while loop. if (result == null) { string state = status == 1 ? "failed" : "killed"; bot.ChangeFiberState(closure.Fiber, state); SafeLogRecord(closure, "fiber", state, exception); ++_exceptionCount; if (closure.Fiber == 0 && closure.Bot == 0) { _exception = exception; _exceptionClosure = closure; _done.Set(); } else { // I think this is sort of mostly the correct think to do. // We need to record the fact that the fiber finished. // But stuffing an exception inside a Native to do so seems wrong. // Need more work on controlling the lifecycle of fibers. // Also I want to get rid of RCNative I think this is the only place // where I still need it. bot.FiberDone(this, closure.Bot, closure.Fiber, new RCNative(exception)); } } }