From 262a8d74522ae5a9899e9b5fcfb4595fd7ffc646 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Fri, 9 Jul 2021 11:38:53 +0200 Subject: [PATCH] Track external tasks that will drive dataspace --- src/syndicate.nim | 2 ++ src/syndicate/dataspaces.nim | 41 +++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/syndicate.nim b/src/syndicate.nim index c575f1f..1af72e1 100644 --- a/src/syndicate.nim +++ b/src/syndicate.nim @@ -14,7 +14,9 @@ export dataspaces.`==` export dataspaces.addEndpoint export dataspaces.addStartScript export dataspaces.addStopScript +export dataspaces.beginExternalTask export dataspaces.defineObservableProperty +export dataspaces.endExternalTask export dataspaces.generateId export dataspaces.hash export dataspaces.recordDamage diff --git a/src/syndicate/dataspaces.nim b/src/syndicate/dataspaces.nim index 002b210..b7b10df 100644 --- a/src/syndicate/dataspaces.nim +++ b/src/syndicate/dataspaces.nim @@ -92,6 +92,8 @@ type dataspace: Dataspace stopHandlers: seq[StopHandler] future: Future[void] + externalTaskCount: int + stepScheduled: bool ParentFacet = Option[Facet] @@ -524,16 +526,39 @@ proc stop*(facet; continuation: Script[void] = nil) = proc addStopHandler*(g: Ground; h: StopHandler) = g.stopHandlers.add(h) -proc step(g: Ground) = - if g.dataspace.runTasks(): +proc step(g: Ground) {.gcsafe.} + +proc scheduleStep(g: Ground) = + if not g.stepScheduled: + g.stepScheduled = true asyncdispatch.callSoon: step(g) + +proc beginExternalTask*(facet) = + ## Inform the ``Ground`` dataspace of a pending external task. + ## The dataspace will continue to operate until all internal + ## and external tasks have completed. See ``endExternalTask``. + inc facet.actor.dataspace.ground.externalTaskCount + +proc endExternalTask*(facet) = + ## Inform the ``Ground`` dataspace that an external task has completed. + # TODO: automatically do this when the facet stops? + let g = facet.actor.dataspace.ground + dec g.externalTaskCount + scheduleStep g + +proc step(g: Ground) = + # TODO: backgroundtasks + g.stepScheduled = false + if g.dataspace.runTasks(): + scheduleStep g else: - for actor in g.dataspace.actors.values: - terminate(actor, false) - for sh in g.stopHandlers: - sh(g.dataspace) - reset g.stopHandlers - complete(g.future) + if g.externalTaskCount < 1: + for actor in g.dataspace.actors.values: + terminate(actor, false) + for sh in g.stopHandlers: + sh(g.dataspace) + reset g.stopHandlers + complete(g.future) proc bootModule*(name: string; bootProc: ActivationScript): Future[void] = # TODO: better integration with the async dispatcher