Big issue with IOCP vs. poll variants is that the overlapped
structures have a longer lifetime than intermediate state needed
for epoll. One cannot free overlapped structures after closing a
handle/socket, like one can do with any intermediate state when using
readiness-based IO.
Any references exclusively held by a weak table may be collected
without the programmer needing to free references manually. A table
can be setup to have weak keys, weak values, or both.
Make more use of the built in GC code for abstracts to
be sure things are more correct. Issue before was streams could
be freed before IOCP events arrived.
After the UB was fixed in value.c, I tried running the build again and encoutered another instance of UB in gc.c. With this fixed I can now build janet with ubsan enabled, meaning there's no more UB encountered in janet_boot during the build.
When new fibers are scheduled on the event loop, this new_channel
receives the newly created fibers. This lets a fiber track which fibers
have been added and let's a user implement a supervisor.
Fix formatting.
Supervisor channels are a simple concept to more efficiently
enable dynamic, structure concurrency. When a top-level fiber
completes (or errors), it will push itself to it's supervisor
channel if it has one (instead of printing a stacktrace). This
let's another fiber poll a channel and "supervise" a set of fibers.
Rather than trying to be clever with pinning/unpinning, always
mark the root fiber and that should serve as thei singular common root in almost
all cases.
Lazy verification makes it easier to not leave funcenvs
in an invalid state, as well as be more precise with the validation.
We needed to verify the FuncEnvs actually pointed to a stack frame if
they were of the "on-stack" variant. There was some minor checking
before, but it was not enough to prevent func envs from pointing to
memory that was off of the fiber stack, overlapping stack frames, etc.
Using a bitset to indicate which stack values are upvalues, we
can more accurately track when a reference to a stack value
persists after the stack frame exits.
If possible, this will reduce the need to marshal fibers
in many cases. Also add this logic to the GC so holding a closure
that originally came from a fiber that crashed does not cause that fiber
to hang around forever.
This way we can support fewer build configurations. Also, remove
all undefined behavior due to use of memcpy with NULL pointers. GCC
was exploiting this to remove NULL checks in some builds.