Interruption API
This problem isn’t new to fibers. On the thread domain the usual approaches are:
-
(Windows) Every time you block on a thread, do it using
WaitForMultipleObjects
so another thread might signal you to stop your activity and exit earlier. It’s verbose and boring and error-prone and also require extra non-standard communcation protocols/idioms between every spawned thread and the killer thread.Bad as it is, this style hasn’t died. Go’s approach to killing goroutines is conceptually equivalent to Windows approach, but syntactically less ugly and with a more standardized protocol/idiom.
-
(POSIX) Send an
INTR
signal to the thread. -
POSIX Thread cancellation API.
-
Rust has no answer. And this is funny given the public appraisal for Rust threading capabilities. Still worse is Rust getting in your way (no good threading, no good fibers).
-
Java’s
Thread.interrupt()
API is similar to POSIX Thread cancellation API and it is one of the few approaches that has not been deprecated because of bad design. However, Java design isn’t free from problems either. The state machine is too complicated and requires sharing too much knowledge between target thread and killer thread. -
Boost.Thread also mirrors POSIX Thread cancellation API, but takes conventions from Java API to C++-ify the API (e.g. name
interrupt()
insteadcancel()
, …) and shoots a few ideas of its own.
I’ve spent long hours researching before settling down on a single design. The chosen design mainly borrows from POSIX thread cancellation API and Boost.Thread.
Other inspirations, even if minimal, were:
-
Python’s trio
cancelled_caught()
method served as an inspirational name forinterruption_caught()
. -
Giacomo Tesio’s awake syscall idea was an inspiration to
this_fiber.interrupter
field.
As for the interrupter traits (used in this_fiber.with_intr()
), I didn’t allow
a stateful trait object because this object would be moved across the stages of
the async operation and the user would stay unable to extract this info at the
fiber wakeup anyway. If the user will have to resort to heap usage one way or
another, he might just as well use fiber local storage and at least reuse these
memory regions across async calls.
Fiber local storage
Boost.Fiber interface was not considered. Boost.Fiber just mirrors Boost.Thread
interface. However Boost.Thread interface is meant for portability on platforms
that lack support for thread-local. If the implementation is not constrained to
rely solely on pthread_key_create
/tss_create
then there is no reason to
follow Boost.Thread design.
IOFiber design is similar to Facebook’s Folly. The difference is support for user types that have no default constructors.