From 82f2e8ee9873720258287ac4cb49e9e3392ff2ee Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 12 Mar 2024 12:32:50 +0000 Subject: [PATCH] actors: better facet stop tracing --- src/syndicate/actors.nim | 120 +++++++++++++++++++++-------------- src/syndicate/dataspaces.nim | 2 +- src/syndicate/relays.nim | 2 +- syndicate.nimble | 2 +- 4 files changed, 75 insertions(+), 51 deletions(-) diff --git a/src/syndicate/actors.nim b/src/syndicate/actors.nim index 9a39f16..40e2d88 100644 --- a/src/syndicate/actors.nim +++ b/src/syndicate/actors.nim @@ -122,18 +122,17 @@ using proc labels(f: Facet): string = proc catLabels(f: Facet; labels: var string) = - labels.add ':' if not f.parent.isNil: catLabels(f.parent, labels) labels.add ':' - when tracing: labels.add $f.id result.add f.actor.name catLabels(f, result) +proc `$`*(f: Facet): string = + "" + when tracing: - proc `$`*(f: Facet): string = - "" proc `$`*(r: Cap): string = "" @@ -162,6 +161,13 @@ proc nextHandle(facet: Facet): Handle = result = succ(facet.actor.handleAllocator[]) facet.actor.handleAllocator[] = result +template recallFacet(turn: var Turn; body: untyped): untyped = + let facet = turn.facet + block: + body + assert facet.actor == turn.facet.actor + turn.facet = facet + proc queueWork*(turn: var Turn; facet: Facet; act: TurnAction) = assert not facet.isNil turn.work.addLast((facet, act,)) @@ -401,18 +407,12 @@ proc isInert(facet): bool = noOutboundHandles = facet.outbound.len == 0 isRootFacet = facet.parent.isNil noInertCheckPreventers = facet.inertCheckPreventers == 0 - noKids and (noOutboundHandles or isRootFacet) and noInertCheckPreventers + result = noKids and (noOutboundHandles or isRootFacet) and noInertCheckPreventers -proc preventInertCheck*(facet): (proc()) {.discardable.} = - var armed = true - inc facet.inertCheckPreventers - proc disarm() = - if armed: - armed = false - dec facet.inertCheckPreventers - result = disarm +proc preventInertCheck*(turn: Turn) = + inc turn.facet.inertCheckPreventers -proc terminate(actor; turn; reason: ref Exception) +proc terminateActor(turn; reason: ref Exception) proc terminate(facet; turn: var Turn; orderly: bool) = if facet.isAlive: @@ -432,37 +432,44 @@ proc terminate(facet; turn: var Turn; orderly: bool) = if parent.isInert: parent.terminate(turn, true) else: - terminate(facet.actor, turn, nil) + terminateActor(turn, nil) when tracing: var act = ActionDescription(orKind: ActionDescriptionKind.facetStop) act.facetstop.path = facet.path turn.desc.actions.add act +proc inertCheck(turn: var Turn) = + if (not turn.facet.parent.isNil and + (not turn.facet.parent.isAlive)) or + turn.facet.isInert: + when tracing: + var act = ActionDescription(orKind: ActionDescriptionKind.facetStop) + act.facetstop.path = facet.path + act.facetstop.reason = FacetStopReason.inert + turn.desc.actions.add act + stop(turn) + proc stopIfInertAfter(action: TurnAction): TurnAction = - # TODO: verify this - proc wrapper(turn: var Turn) = - action(turn) - queueEffect(turn, turn.facet) do (turn: var Turn): - if (not turn.facet.parent.isNil and - (not turn.facet.parent.isAlive)) or - turn.facet.isInert: - stop(turn) - wrapper + proc work(turn: var Turn) = + queueWork(turn, turn.facet, action) + queueEffect(turn, turn.facet, inertCheck) + work proc newFacet(turn: var Turn): Facet = newFacet(turn.facet.actor, turn.facet) -proc inFacet*(turn: var Turn; bootProc: TurnAction): Facet = +#[ +proc inFacet(turn: var Turn; bootProc: TurnAction): Facet = result = newFacet(turn) - let facet = turn.facet - turn.facet = result - when tracing: - var act = ActionDescription(orKind: ActionDescriptionKind.facetstart) - act.facetstart.path.add result.path - turn.desc.actions.add act - stopIfInertAfter(bootProc)(turn) - turn.facet = facet + recallFacet turn: + turn.facet = result + when tracing: + var act = ActionDescription(orKind: ActionDescriptionKind.facetstart) + act.facetstart.path.add result.path + turn.desc.actions.add act + stopIfInertAfter(bootProc)(turn) +]# -proc facet(turn: var Turn; bootProc: TurnAction): Facet {.deprecated.} = inFacet(turn, bootProc) +# proc facet(turn: var Turn; bootProc: TurnAction): Facet {.deprecated.} = inFacet(turn, bootProc) proc newActor(name: string; parent: Facet): Actor = result = Actor( @@ -539,7 +546,8 @@ proc newInertCap*(): Cap = proc atExit*(actor; action) = actor.exitHooks.add action -proc terminate(actor; turn; reason: ref Exception) = +proc terminateActor(turn; reason: ref Exception) = + let actor = turn.actor if not actor.exiting: actor.exiting = true actor.exitReason = reason @@ -549,7 +557,13 @@ proc terminate(actor; turn; reason: ref Exception) = act.stop.status = ExitStatus(orKind: ExitStatusKind.Error) act.stop.status.error.message = reason.msg trace(actor, act) - for hook in actor.exitHooks: hook(turn) + while actor.exitHooks.len > 0: + var hook = actor.exitHooks.pop() + try: hook(turn) + except CatchableError as err: + if reason.isNil: + terminateActor(turn, err) + return proc finish(turn: var Turn) = assert not actor.root.isNil, actor.name actor.root.terminate(turn, reason.isNil) @@ -558,14 +572,7 @@ proc terminate(actor; turn; reason: ref Exception) = proc terminate*(facet; e: ref Exception) = run(facet.actor.root) do (turn: var Turn): - facet.actor.terminate(turn, e) - -template recallFacet(turn: var Turn; body: untyped): untyped = - let facet = turn.facet - block: - body - assert facet.actor == turn.facet.actor - turn.facet = facet + terminateActor(turn, e) proc stopNow(turn: var Turn) = let caller = turn.facet @@ -583,6 +590,11 @@ proc stop*(turn: var Turn, facet: Facet) = queueEffect(turn, facet, stopNow) proc stop*(turn: var Turn) = + when tracing: + var act = ActionDescription(orKind: ActionDescriptionKind.facetStop) + act.facetstop.path = facet.path + act.facetstop.reason = FacetStopReason.explicitAction + turn.desc.actions.add act stop(turn, turn.facet) proc onStop*(facet: Facet; act: TurnAction) = @@ -596,7 +608,12 @@ proc onStop*(turn: var Turn; act: TurnAction) = proc stop*(actor: Actor) = queueTurn(actor.root) do (turn: var Turn): assert(not turn.facet.isNil) - stop(turn) + when tracing: + var act = ActionDescription(orKind: ActionDescriptionKind.facetStop) + act.facetstop.path = facet.path + act.facetstop.reason = FacetStopReason.actorStopping + turn.desc.actions.add act + stop(turn, turn.facet) proc stopActor*(facet: Facet) = stop(facet.actor) @@ -655,9 +672,16 @@ proc run* = while turnQueue.len > 0: var turn = turnQueue.popFirst() # TODO: check if actor is still valid - run turn + try: run(turn) + except CatchableError as err: + stderr.writeLine("actor ", turn.actor.name, " threw an error during a turn") + terminateActor(turn, err) ioqueue.poll(ready) if ready.len == 0: break while ready.len > 0: - discard trampoline: - ready.pop() + try: + discard trampoline: + ready.pop() + except CatchableError as err: + stderr.writeLine "ioqueue continuation threw an error" + raise err diff --git a/src/syndicate/dataspaces.nim b/src/syndicate/dataspaces.nim index 477535a..4f39992 100644 --- a/src/syndicate/dataspaces.nim +++ b/src/syndicate/dataspaces.nim @@ -42,7 +42,7 @@ type DeprecatedBootProc = proc (ds: Cap; turn: var Turn) {.closure.} proc bootDataspace*(name: string; bootProc: BootProc): Actor = bootActor(name) do (turn: var Turn): - discard turn.facet.preventInertCheck() + turn.preventInertCheck() bootProc(turn, newDataspace(turn)) proc bootDataspace*(name: string; bootProc: DeprecatedBootProc): Actor {.deprecated.} = diff --git a/src/syndicate/relays.nim b/src/syndicate/relays.nim index 8c4f9ae..dc612a2 100644 --- a/src/syndicate/relays.nim +++ b/src/syndicate/relays.nim @@ -262,12 +262,12 @@ type proc spawnRelay(name: string; turn: var Turn; opts: RelayActorOptions; setup: RelaySetup) = spawnLink(name, turn) do (turn: var Turn): + turn.preventInertCheck() let relay = Relay( facet: turn.facet, packetWriter: opts.packetWriter, wireBuf: newBufferedDecoder(0), ) - discard relay.facet.preventInertCheck() if not opts.initialCap.isNil: var exported: seq[WireSymbol] discard rewriteCapOut(relay, opts.initialCap, exported) diff --git a/syndicate.nimble b/syndicate.nimble index 2a5522f..42bf4ff 100644 --- a/syndicate.nimble +++ b/syndicate.nimble @@ -1,6 +1,6 @@ # Package -version = "20240311" +version = "20240312" author = "Emery Hemingway" description = "Syndicated actors for conversational concurrency" license = "Unlicense"