15.4 Synchronizable Events
A synchronizable event is an object that can be used with Evt.sync to wait until it is ready for synchronization. Synchronizing a ready event may have a side effect and an associated value. For example, synchronizing on a Semaphore is the same as using Semaphore.wait, so it decrements the semaphore’s count.
annotation | |
The Evt annotation interface-like in the sense that every Evt supports the Evt.sync method.
The Evt.never synchronizable event is never ready for synchronization.
method | ||||||
|
> Evt.always.sync()
Evt.always
#false
> Evt.never.sync(Evt.always)
Evt.always
> Evt.always.wrap(fun (_): "done").sync()
"done"
"also"
"done"
2
> Evt.always.wrap(fun (_): values(1, 2)).wrap(fun (u, v): u+v).sync()
3
If return is #'no_break, then wrapf is called with breaks (in the sense of Thread.break) disabled.
If return is #'tail, then wrapf is called in tail position with respect to a synchronization request via Evt.sync. When the Evt produced by Evt.wrap is wrapped by another Evt.wrap with #'no_break, however, this tail-call behavior is disabled.
> // loop runs in contsant space
| "done"
| Evt.always.wrap(fun (_): loop(i+1), ~return: #'tail).sync()
"done"
The number of arguments accepted by replacef must match the number of values for the synchronization result of evt.
> Evt.always.replace(fun (_): Evt.always.wrap(fun (_): "replaced")).sync()
"replaced"
> Evt.always.replace(fun (_): "done").sync()
ReplaceEvt(...)
The result guard of Evt.guard generates an event when guard is used with Evt.sync (or whenever it is part of a Evt.choice event used with Evt.sync, etc.), where the generated event is the result of calling make. The make function may be called by Evt.sync at most once for a given call to Evt.sync, but make may not be called if a ready event is chosen before guard is even considered.
Evt.always.wrap(fun (_): c))
0
1
#false
> Evt.system_idle.sync()
Evt.system_idle
> state
0
> // might try `g`, or might immediately succeed with `Evt.always`
Evt.always
> Evt.system_idle.sync()
Evt.system_idle
> state
0
> def g = Evt.poll_guard(fun (is_poll):
Evt.always.wrap(fun (_): to_string(is_poll)))
"#true"
"#false"
In other words, supplying the result of Evt.choice to Evt.sync is the same as supplying all of the individual evts to the same Evt.sync.
> // result could be either:
Evt.choice(Evt.always.wrap(fun (_): "left"),
Evt.always.wrap(fun (_): "right"))
"right"
> Evt.alarm(system.milliseconds() + 1).sync()
Evt.alarm(...)
> Evt.alarm(measure.real_milliseconds() + 1, ~monotonic: #true).sync()
Evt.alarm(...)
value | |
The Evt.system_idle event is intended primarily for use in tests where all concurrency is known.
annotation | |
| |
annotation | |
A CommitEvt is used in combination with a ProgressEvt for Port.Input.Progress.commit. A CommitEvt is either a Semaphore, channel-put event, channel, semaphore-peek event, Evt.always, or Evt.never.
interface | |
The interface has a single abstract method:
as_evt() —
produces an synchronizable event that can be used in Evt.sync.