moonbitlang/async need an event loop to perform asynchronous IO.
However, some programs, such as GUI programs, have their own event loop,
and that event loop sometimes must be run in the main thread.
In this case, moonbitlang/async supports running its event loop
in a dedicated thread internally and integrate with the user-provided loop.
ExternalEventLoop is an abstraction for such user-provided event loop.
An implementation of ExternalEventLoop represent an event loop instance.
The required methods for the user-provided event loop are:
- evloop.poll(timeout?): the main wait function of the user-provided loop.
poll should block the program until any interested event occur or timeout expired.
After waking up, poll should process main loop specific events and return,
moonbitlang/async will handle its own events and invoke poll again for the next loop.When handling main loop specific events, poll SHOULD NOT perform heavy work directly.
Instead, it is recommended to send the event back to async code via @async.CondVar
or @async.Queue. This way, main loop events can integrate with moonbitlang/async
code better.poll must support three timeout modes:
- if timeout is Some(0), poll MUST NOT enter waiting state.
Instead, poll should simply check for immediately available events
and return immediately
- otherwise, if timeout is Some(t) (in this case it is guaranteed that t > 0),
poll should wait for no more than t milliseconds.
If some event occur before t, poll should return immediately.
Slight delay is allowed on timeout, but the delay will affect timer precision
of moonbitlang/async
- if timeout is None, poll should wait indefinitely for events
- evloop.get_wakeup_callback_for_foreign_thread() should return a callback function
for waking up the user-provided loop. moonbitlang/async will use this callback
to wake up the main loop when moonbitlang/async specific events occur.When the callback returned by evloop.get_wakeup_callback_for_foreign_thread()
is invoked, it MUST wake up the blocked poll wait, if poll is currently running.
If poll is not running when the callback is invoked,
the callback should make the next poll should return immediately.
MISSED WAKEUP MAY RESULT IN PROGRAM DEAD LOCK.If the wakeup callback event is implemented via some form of special event,
that event itself can be ignored in poll. moonbitlang/async will
check for its own events unconditionally after poll returns.IMPORTANT CORRECTNESS NOTE: the returned wakeup callback will be invoked
in a dedicated thread, so the callback MUST NOT do anything other than
invoking a C FFI function directly, and that invoked C FFI function MUST NOT
perform any MoonBit reference counting operation.
- terminate will be invoked when the main loop exit.
Cleanup code for the user-provided event loop should be placed here.
Notice that moonbitlang/async need to perform some additional cleanup
after async fn main returns. So event loop cleanup should not be performed
inside async fn main.