Example #1
0
 // Seems like a kind of weird way to do this piece.
 public void InjectState(RCBot bot)
 {
     foreach (Type type in _modules)
     {
         bot.PutModule(type);
     }
 }
Example #2
0
        public void Report(RCClosure closure, Exception ex)
        {
            RCBot bot = GetBot(closure.Bot);

            bot.ChangeFiberState(closure.Fiber, "reported");
            RCSystem.Log.Record(closure, "fiber", closure.Fiber, "reported", ex);
            ++_exceptionCount;
        }
Example #3
0
        protected RCValue Run(RCClosure root, bool restoreStateOnError)
        {
            lock (_queueLock)
            {
                if (_root == null)
                {
                    _root = root;
                    RCBot rootBot = GetBot(_root.Bot);
                    // keeping this inside the lock because it should happen before the call to
                    // Enqueue.
                    // But only during the very first call to run for this runner.
                    // Log.Record (this, root, root.BotId, "bot", root.BotId, "start", root.Code);
                    rootBot.ChangeFiberState(root.Fiber, "start");
                    RCSystem.Log.Record(root, "fiber", root.Fiber, "start", root.Code);
                }
                _queue.Enqueue(root);
            }
            // Trigger a worker (don't care which) to take it.
            _wait.Set();
            // Wait for the work to be completed.
            _done.WaitOne();
            // If an exception was thrown, rethrow it on this thread.
            if (_exception != null)
            {
                Exception exception = _exception;
                _exception = null;
                if (restoreStateOnError)
                {
                    // Make the successfully computed values into the effective state of the
                    // environment
                    RCClosure top      = _exceptionClosure;
                    RCClosure underTop = null;
                    while (top.Parent != null && top.Parent.Parent != null)
                    {
                        underTop = top;
                        top      = top.Parent;
                    }
                    if (underTop != null && top.Code.IsOperator)
                    {
                        top = underTop;
                    }
                    _state = RCBlock.Append(_state, top.Result);
                }
                _runnerUnhandled = true;
                throw exception;
            }
            // The final result is assigned by the worker in Finish ().
            RCValue result = _result;

            _result = null;
            return(result);
        }
Example #4
0
 public RCRunner(long workers)
 {
     _ctorThread             = Thread.CurrentThread;
     _bots[0]                = new RCBot(this, 0);
     _output[0]              = new Queue <RCAsyncState> ();
     _parser                 = new RCLParser(RCSystem.Activator);
     Console.CancelKeyPress += HandleConsoleCancelKeyPress;
     for (int i = 0; i < workers; ++i)
     {
         Thread worker = new Thread(Work);
         worker.IsBackground = true;
         _workers.Write(worker);
         worker.Start();
     }
 }
Example #5
0
        public static RCClosure FiberClosure(RCBot bot, long fiber, RCClosure closure, RCValue code)
        {
            // First create a clone of the parent closure for the current operator,
            // with the new fiber operator on it.  This ensures that that when tail
            // calls are eliminated the next closure will have the correct child fiber
            // number, not the fiber number of the parent.
            // Update July 12, 2014.
            // This additional clone of the parent closure no longer seems necessary for tail
            // calls.
            // In addition it was found to cause certain fibers to give the wrong result on
            // completion.
            // TestTryWaitKill5 is the repro for this.

            /*
             * RCClosure parent = null;
             * if (closure.Parent != null)
             * {
             *  parent = new RCClosure (
             *    //bot,
             *    //fiber,
             *    closure.Parent.Bot,
             *    closure.Parent.Fiber,
             *    closure.Parent.Locks,
             *    closure.Parent.Parent,
             *    closure.Parent.Code,
             *    closure.Parent.Left,
             *    closure.Parent.Result,
             *    closure.Parent.Index);
             * }
             */

            RCClosure clone = new RCClosure(bot.Id,
                                            fiber,
                                            closure.Locks,
                                            closure.Parent,
                                            closure.Code,
                                            closure.Left,
                                            closure.Result,
                                            closure.Index,
                                            closure.UserOp,
                                            closure.UserOpContext,
                                            noClimb: false,
                                            noResolve: false);

            RCClosure next = new RCClosure(clone, bot.Id, code, clone.Left, RCBlock.Empty, 0);

            return(next);
        }
Example #6
0
        protected long DoFiber(RCRunner runner, RCClosure closure, RCValue code)
        {
            long      fiber = Interlocked.Increment(ref _fiber);
            RCBot     bot   = runner.GetBot(closure.Bot);
            RCClosure next  = FiberClosure(bot, fiber, closure, code);

            bot.ChangeFiberState(fiber, "start");
            RCSystem.Log.Record(closure, "fiber", fiber, "start", "");

            // This creates a separate stream of execution (fiber) from the
            // one that called this method.
            // When it is done it will naturally try to return its result
            // back to the original calling fiber.  But the Next method on the
            // fiber operator will see this happening and call FiberDone instead.
            runner.Continue(null, next);
            return(fiber);
        }
Example #7
0
        // Previous is the closure that will be removed from the pending set.
        // Next is the closure that will be added to the queue.
        // This is done in an atomic fashion so that all fibers will be
        // represented in _pending or _queue at all times.
        // previous will be null in cases where Continue is used to retry or fork streams of
        // execution.
        // next will be null in cases where the executing fiber is finished and all
        // that remains is to remove it from _pending.
        public void Continue(RCClosure previous, RCClosure next)
        {
            bool live = false;

            lock (_queueLock)
            {
                if (previous != null)
                {
                    Dictionary <long, RCClosure> pending = null;
                    if (_pending.TryGetValue(previous.Bot, out pending))
                    {
                        RCClosure c = null;
                        if (pending.TryGetValue(previous.Fiber, out c))
                        {
                            pending.Remove(previous.Fiber);
                            if (pending.Count == 0)
                            {
                                _pending.Remove(previous.Bot);
                            }
                            live = true;
                        }
                    }
                }
                else
                {
                    live = true;
                }
                if (live)
                {
                    if (next != null)
                    {
                        _queue.Enqueue(next);
                        _wait.Set();
                    }
                }
                else
                {
                    // This will internally take the _botLock.
                    // This should be ok but given that it is just a log write
                    // I would like to move this outside.
                    RCBot bot = GetBot(previous.Bot);
                    bot.ChangeFiberState(previous.Fiber, "dead");
                    RCSystem.Log.Record(previous, "fiber", previous.Fiber, "dead", "");
                }
            }
        }
Example #8
0
        public long Bot(RCClosure closure, RCBlock right)
        {
            RCClosure next;
            long      id;
            RCBot     bot;

            lock (_botLock)
            {
                id          = _bot++;
                bot         = new RCBot(this, id);
                _output[id] = new Queue <RCAsyncState> ();
                _bots[id]   = bot;
                next        = Fiber.FiberClosure(bot, 0, closure, right);
            }
            bot.ChangeFiberState(0, "start");
            RCSystem.Log.Record(next, "fiber", 0, "start", "");
            Continue(null, next);
            return(id);
        }
Example #9
0
        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);
            }
        }
Example #10
0
 public void Reset()
 {
     // Should I take the locks here? One or both? Both.
     lock (_queueLock)
     {
         lock (_botLock)
         {
             _parser           = new RCLParser(RCSystem.Activator);
             _root             = null;
             _result           = null;
             _exception        = null;
             _exceptionClosure = null;
             _exceptionCount   = 0;
             _queue            = new Queue <RCClosure> ();
             _pending          = new Dictionary <long, Dictionary <long, RCClosure> > ();
             _bot       = 1;
             _bots      = new Dictionary <long, RCBot> ();
             _bots[0]   = new RCBot(this, 0);
             _output[0] = new Queue <RCAsyncState> ();
             ++_reset;
         }
     }
 }
Example #11
0
        public void Start(RCValue program)
        {
            if (program == null)
            {
                throw new Exception("program may not be null");
            }
            RCClosure root = null;

            lock (_queueLock)
            {
                if (_root != null)
                {
                    throw new Exception("Runner has already started.");
                }
                RCBot rootBot = _bots[0];
                root = new RCClosure(rootBot.Id, program);
                rootBot.ChangeFiberState(root.Fiber, "start");
                RCSystem.Log.Record(root, "fiber", root.Fiber, "start", root.Code);
                _root = root;
                _queue.Enqueue(root);
            }
            _wait.Set();
        }
Example #12
0
        public void Invoke(RCRunner runner, RCClosure closure, string name, object left, object right)
        {
            OverloadValue overload;
            Type          ltype = left.GetType();
            Type          rtype = right.GetType();
            Type          ctype = right.GetType();

            try
            {
                if (_dispatch.TryGetValue(new OverloadKey(name, ctype, ltype, rtype), out overload))
                {
                    RCBot  bot   = runner.GetBot(closure.Bot);
                    object state = bot.GetModule(overload.Module);
                    overload.Implementation.Invoke(state, new object[] { runner, closure, left, right });
                }
                else if (_dispatch.TryGetValue(new OverloadKey(name, typeof(object), ltype, rtype),
                                               out overload))
                {
                    RCBot  bot   = runner.GetBot(closure.Bot);
                    object state = bot.GetModule(overload.Module);
                    overload.Implementation.Invoke(state, new object[] { runner, closure, left, right });
                }
                else if (_dispatch.TryGetValue(new OverloadKey(name,
                                                               typeof(object),
                                                               typeof(object),
                                                               rtype),
                                               out overload))
                {
                    RCBot  bot   = runner.GetBot(closure.Bot);
                    object state = bot.GetModule(overload.Module);
                    overload.Implementation.Invoke(state, new object[] { runner, closure, left, right });
                }
                else if (_dispatch.TryGetValue(new OverloadKey(name,
                                                               typeof(object),
                                                               ltype,
                                                               typeof(object)),
                                               out overload))
                {
                    RCBot  bot   = runner.GetBot(closure.Bot);
                    object state = bot.GetModule(overload.Module);
                    overload.Implementation.Invoke(state, new object[] { runner, closure, left, right });
                }
                else if (_dispatch.TryGetValue(new OverloadKey(name,
                                                               typeof(object),
                                                               typeof(object),
                                                               typeof(object)),
                                               out overload))
                {
                    RCBot  bot   = runner.GetBot(closure.Bot);
                    object state = bot.GetModule(overload.Module);
                    overload.Implementation.Invoke(state, new object[] { runner, closure, left, right });
                }
                else if (_dispatch.TryGetValue(new OverloadKey(name,
                                                               typeof(object),
                                                               ltype,
                                                               typeof(RCOperator)),
                                               out overload))
                {
                    RCBot  bot   = runner.GetBot(closure.Bot);
                    object state = bot.GetModule(overload.Module);
                    overload.Implementation.Invoke(state, new object[] { runner, closure, left, right });
                }
                else
                {
                    throw RCException.Overload(closure, name, left, right);
                }
            }
            catch (TargetInvocationException tiex)
            {
                Exception ex = tiex.GetBaseException();
                if (ex is RCException)
                {
                    throw ex;
                }
                else
                {
                    // You have to pass the tiex, not ex here so that the interior stack trace will
                    // be
                    // preserved when/if it is rethrown.
                    throw new RCException(closure, tiex, RCErrors.Native, ThrowMessage(name, ex));
                }
            }
        }
Example #13
0
        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));
                }
            }
        }