diff --git a/src/syndicate/actors/Tupfile b/src/syndicate/actors/Tupfile new file mode 100644 index 0000000..73621ca --- /dev/null +++ b/src/syndicate/actors/Tupfile @@ -0,0 +1,3 @@ +include_rules +NIM_FLAGS += --path:$(TUP_CWD)/../.. +: foreach *.nim |> !nim_check |> diff --git a/src/syndicate/actors/timers.nim b/src/syndicate/actors/timers.nim new file mode 100644 index 0000000..480fac8 --- /dev/null +++ b/src/syndicate/actors/timers.nim @@ -0,0 +1,34 @@ +# SPDX-FileCopyrightText: ☭ Emery Hemingway +# SPDX-License-Identifier: Unlicense + +import std/[asyncdispatch, monotimes, times] +import preserves +import syndicate, syndicate/actors + +import ../protocols/timer +from syndicate/protocols/dataspace import Observe + +export timer + +type Observe = dataspace.Observe[Ref] + +proc now: float64 = getTime().toUnixFloat() + +proc spawnTimers*(turn: var Turn; ds: Ref) = + ## Spawn a timer actor. + spawn("timer", turn) do (turn: var Turn): + + during(turn, ds, ?Observe(pattern: !LaterThan) ?? {0: grabLit()}) do (seconds: float64): + let period = seconds - now() + if period < 0.001: + discard publish(turn, ds, LaterThan(seconds: seconds)) + else: + let facet = turn.facet + addTimer(int(period * 1_000), oneshot = true) do (fd: AsyncFD) -> bool: + run(facet) do (turn: var Turn): + discard publish(turn, ds, LaterThan(seconds: seconds)) + +template after*(turn: var Turn; ds: Ref; dur: Duration; act: untyped) = + ## Execute `act` after some duration of time. + let later = now() + dur.inMilliseconds.float64 * 1_000.0 + onPublish(turn, ds, ?LaterThan(seconds: later), act) diff --git a/src/syndicate/drivers/timers.nim b/src/syndicate/drivers/timers.nim deleted file mode 100644 index 4b9aac3..0000000 --- a/src/syndicate/drivers/timers.nim +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-FileCopyrightText: 2021 ☭ Emery Hemingway -# SPDX-License-Identifier: Unlicense - -import std/[asyncdispatch, monotimes, times] -import preserves, preserves/records -import syndicate, syndicate/assertions -import ../../syndicate/protocols/schemas/timer - -syndicate timerDriver: - - spawn "timer": - during(observe(laterThan(?msecs))) do (msecs: float64): - let - now = getTime().toUnixFloat() * 1_000.0 - period = msecs - now - if period > 0: - getCurrentFacet().beginExternalTask() - addTimer(period.int, oneshot = true) do (fd: AsyncFD) -> bool: - react: publish: laterThan(deadline) - getCurrentFacet().endExternalTask() - true - else: - react: publish: prsTimeLaterThan(deadline) diff --git a/tests/test_timers.nim b/tests/test_timers.nim new file mode 100644 index 0000000..cd039b0 --- /dev/null +++ b/tests/test_timers.nim @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: ☭ Emery Hemingway +# SPDX-License-Identifier: Unlicense + +import std/[asyncdispatch, os, times] +import preserves, syndicate, syndicate/actors/timers + +proc now: float64 = getTime().toUnixFloat() + +proc testTimers(turn: var Turn; ds: Ref) = + onPublish(turn, ds, ?LaterThan(seconds: now()+1.0)) do: + stderr.writeLine "slept one second once" + onPublish(turn, ds, ?LaterThan(seconds: now()+1.0)) do: + stderr.writeLine "slept one second twice" + onPublish(turn, ds, ?LaterThan(seconds: now()+1.0)) do: + stderr.writeLine "slept one second thrice" + quit() + spawnTimers(turn, ds) + +type Args {.preservesDictionary.} = object + dataspace: Ref + +proc asInferior: bool = + commandLineParams() == @["--inferior"] + +if asInferior(): + stderr.writeLine "connect stdio" + runActor("test_timers") do (root: Ref; turn: var Turn): + connectStdio(root, turn) + during(turn, root, ?Args) do (ds: Ref): + testTimers(turn, ds) +else: + stderr.writeLine "use local dataspace" + discard bootDataspace("test_timers") do (ds: Ref; turn: var Turn): + testTimers(turn, ds) + + for i in 0..10: poll()