std/loop
The event loop waits for many things at once and runs a callback for each as it happens, one at a time: a callback runs to its end before another starts. It waits on timers, signals, processes, and watched files; network connections come next.
import "std/loop"
Timer clock = every(1000, func() do
print("tick")
end)
after(3500, func() do
cancel(clock)
end)
run_loop() // tick, tick, tick, and then it returns| Function | Result |
|---|---|
run_loop() |
runs callbacks as they become due, until nothing is left to wait for or stop_loop() is called |
stop_loop() |
makes run_loop return once the callback running now ends |
run_once(timeout_ms) |
runs what is due, or waits up to timeout_ms for something to be, for a program that drives the loop itself; says whether anything is left |
loop_time() |
the loop's time in milliseconds, on a clock that never goes back, as it was when the running callbacks became due |
after(ms, callback) |
a Timer that runs callback once, ms milliseconds from now |
every(ms, callback) |
a Timer that runs callback every ms milliseconds |
cancel(timer) |
stops a timer |
reschedule(timer, ms) |
makes a timer run ms milliseconds from now, also one that already ran |
unref(timer) |
lets the loop end while the timer waits |
call_soon(callback) |
runs callback right after the callback running now |
on_idle(callback) |
runs callback once, the next time the loop has nothing else to do |
An every timer counts from when it started, not from when each callback
ran, so it does not drift; a time the loop was too busy for is skipped.
Rescheduling a timer each time something happens makes a debounce: its
callback runs once, after the last of them. While it waits, the loop sleeps
until the next timer is due, so it uses no processor time. A runtime error
in a callback ends the program with its trace, as anywhere else.
Signals
on_signal(name, callback) runs callback each time the program gets a
signal, instead of what the signal would do, such as ending the program, so
a server can finish its work on Ctrl+C:
on_signal("interrupt", func() do
print("saving before leaving")
stop_loop()
end)The signals are "interrupt" (Ctrl+C), "terminate", "hangup",
"user1", "user2", "child", "window_change", and "pipe". A
callback for a signal does not keep the loop running by itself.
ignore_signal(name) makes the program take no notice of one and forgets
its callbacks, and send_signal(pid, name) sends one to a process, giving a
Result; process_id() is this program's id.
On Windows, interrupt comes from Ctrl+C and Ctrl+Break, also to a program
that was started ignoring Ctrl+C, as Windows lets a program pass that on to
those it starts; hangup comes when the console window is closed, and
terminate when the user logs off or the system shuts down, which leaves
the program a few seconds for its callbacks; the other signals never come
there. Windows can send interrupt only to a
process started in a process group of its own, as Ctrl+Break, and terminate,
which ends the process at once; sending another gives an ERROR of kind
"unsupported".