// It is possible to have multiple concurrent observers. // However each value will only be returned to one of the observers. // It is hard to see a reason to create multiple observers but there // are multiple potential problems with implementing the constraint that there // be only one. public void Watch(RCClosure closure, long bot) { RCBlock result; lock (_botLock) { Queue <RCAsyncState> output = _output[bot]; if (output.Count == 0) { Queue <RCClosure> watchers; if (!_watchers.TryGetValue(bot, out watchers)) { watchers = new Queue <RCClosure> (); _watchers[bot] = watchers; } watchers.Enqueue(closure); return; } RCBlock values = RCBlock.Empty; Stack <RCClosure> parts = new Stack <RCClosure> (); RCArray <RCSymbolScalar> names = new RCArray <RCSymbolScalar> (output.Count); while (output.Count > 0) { RCAsyncState state = output.Dequeue(); RCClosure parent = state.Closure; RCSymbolScalar name = new RCSymbolScalar(null, parent.Fiber); while (parent != null) { if (parent.Parent.Bot != parent.Bot || parent.Parent.Fiber != parent.Fiber) { break; } parts.Push(parent); parent = parent.Parent; } while (parts.Count > 0) { RCClosure top = parts.Pop(); if (top.Code.IsBlock) { RCBlock code = (RCBlock)top.Code; string part = code.GetName(top.Index).Name; if (part != "") { name = new RCSymbolScalar(name, part); } else { name = new RCSymbolScalar(name, (long)top.Index); } } } if (name != null) { RCValue val = (RCValue)state.Other; values = new RCBlock(values, "", ":", val); names.Write(name); } } result = new RCBlock(null, "names", ":", new RCSymbol(names)); result = new RCBlock(result, "values", ":", values); } Yield(closure, result); }
public Wakeup(RCAsyncState state, long resetCount) { _state = state; _resetCount = resetCount; }
public void Wait(RCClosure closure, RCLong timeout, RCLong fibers) { // At some point I want this to work for multiple fibers, // but the current version will only wait on a single fiber. if (fibers.Count == 1) { Fiber fiber; lock (_botLock) { fiber = (Fiber)_bots[fibers[0]].GetModule(typeof(Fiber)); } RCValue result = null; lock (fiber._fiberLock) { if (fiber._fiberResults.Count == fiber._fibers.Count) { fiber._fiberResults.TryGetValue(0, out result); } } if (result == null) { lock (_botLock) { Queue <RCClosure> waiters; if (_botWaiters.TryGetValue(fibers[0], out waiters)) { waiters.Enqueue(closure); } else { waiters = new Queue <RCClosure> (); waiters.Enqueue(closure); _botWaiters.Add(fibers[0], waiters); } RCAsyncState state = new RCAsyncState(this, closure, fibers); Wakeup wakeup = new Wakeup(state, _reset); Timer timer = new Timer(wakeup.ContinueBot); timer.Change(timeout[0], Timeout.Infinite); } } else { SafeYieldFromWait(closure, result); } } else if (fibers.Count == 2) { RCValue result = null; Fiber fiber; lock (_botLock) { fiber = (Fiber)_bots[fibers[0]].GetModule(typeof(Fiber)); } lock (fiber._fiberLock) { if (!fiber._fiberResults.TryGetValue(fibers[1], out result)) { Queue <RCClosure> waiters; if (fiber._fiberWaiters.TryGetValue(fibers[1], out waiters)) { waiters.Enqueue(closure); } else { waiters = new Queue <RCClosure> (); waiters.Enqueue(closure); fiber._fiberWaiters.Add(fibers[1], waiters); } RCAsyncState state = new RCAsyncState(this, closure, fibers); Wakeup wakeup = new Wakeup(state, _reset); Timer timer = new Timer(wakeup.ContinueFiber); timer.Change(timeout[0], Timeout.Infinite); } } if (result != null) { SafeYieldFromWait(closure, result); } } else { throw new Exception(); } }