public T Receive() { if (Task.CurrentId == null) { throw new InvalidOperationException("Tried to receive from a non-Task context"); } if (Task.CurrentId.Value != ownerActorInfo.task.Id) { throw new InvalidOperationException("Only the owner can receive from a Mailbox"); } if (mailbox.Count <= 0) { Safety.Assert(waiter == null); waiter = runtime.GetCurrentActorInfo(); Safety.Assert(waiter.enabled); waiter.enabled = false; } runtime.Schedule(OpType.RECEIVE); Safety.Assert(mailbox.Count > 0); Safety.Assert(waiter == null); var res = mailbox[0]; mailbox.RemoveAt(0); return(res); }
private void WaitHelper(ActorInfo actorInfo, ActorInfo otherInfo) { if (!otherInfo.terminated) { actorInfo.enabled = false; otherInfo.terminateWaiters.Add(actorInfo); } Schedule(OpType.JOIN); Safety.Assert(otherInfo.terminated); }
public void Send(T msg) { runtime.Schedule(OpType.SEND); LogSend(msg); mailbox.Add(msg); if (waiter != null) { Safety.Assert(!waiter.enabled); waiter.enabled = true; waiter = null; } }
public void Schedule(OpType opType, ActorInfo currentActor = null) { if (currentActor == null) { currentActor = GetCurrentActorInfo(); } if (CheckTerminated(opType)) { return; } currentActor.currentOp = opType; ActorInfo nextActor = scheduler.GetNext(actorList, currentActor); if (nextActor == null) { foreach ( var waiter in actorList.Where(info => info.waitingForDeadlock)) { waiter.waitingForDeadlock = false; waiter.enabled = true; } nextActor = scheduler.GetNext(actorList, currentActor); } if (nextActor == null) { // Deadlock terminated = true; ActivateAllActors(); CheckTerminated(opType); return; } if (nextActor == currentActor) { return; } Safety.Assert(currentActor.active); currentActor.active = false; lock (nextActor.mutex) { Safety.Assert(nextActor.enabled); Safety.Assert(!nextActor.active); nextActor.active = true; Monitor.PulseAll(nextActor.mutex); } lock (currentActor.mutex) { if (currentActor.terminated && opType == OpType.END) { return; } while (!currentActor.active) { Monitor.Wait(currentActor.mutex); } if (CheckTerminated(opType)) { return; } Safety.Assert(currentActor.enabled); Safety.Assert(currentActor.active); } }
public static T ActorBody <T>( Func <T> func, TestingActorRuntime runtime, bool mainThread, ActorInfo info = null) { if (info == null) { info = runtime.GetCurrentActorInfo(); } lock (info.mutex) { Safety.Assert(info.active); info.currentOp = OpType.START; if (!mainThread) { info.active = false; Monitor.PulseAll(info.mutex); while (!info.active) { Monitor.Wait(info.mutex); } } } try { return(func()); } catch (OperationCanceledException ex) { lock (info.mutex) { if (info.cts.Token == ex.CancellationToken && info.cts.IsCancellationRequested) { info.cancelled = true; } info.exceptions.Add(ex); } throw; } catch (ActorTerminatedException ex) { if (mainThread && runtime.error == null) { runtime.error = new Exception("Main actor did not terminate.", ex); } } catch (Exception ex) { runtime.error = ex; runtime.terminated = true; runtime.ActivateAllActors(); } finally { try { if (!runtime.terminated) { runtime.Schedule(OpType.END, info); lock (info.mutex) { info.enabled = false; info.terminated = true; foreach (var waiter in info.terminateWaiters) { waiter.enabled = true; } info.terminateWaiters.Clear(); } runtime.Schedule(OpType.END, info); } } catch (ActorTerminatedException) { } finally { lock (info.mutex) { info.terminated = true; } } } return(default(T)); }