Age | Commit message (Collapse) | Author |
|
This used to only happen on __WIN32__ builds, but in preparation
of supporting checking if a fiber is running a specific thunk,
make this unconditional.
|
|
It's useful to be able to wipe out a pulp instance but reuse its
allocations as a fresh pulp instance.
This also fixes a context leak in pulp_free() by making it call
pulp_reset(). (only relevant to win32 where destroy_context()
does something)
|
|
Sometimes it's inconvenient for the caller to do anything useful
with the delay value and will simply be running another tick as
soon as possible.
I see no point in interfering with this usage by requiring the
caller to store the variable it won't be making use of anyways.
So make next_tick_delay_us optional; when NULL this will be
ignored.
|
|
This function doesn't need to know the pulp instance, and it's
awkward in scenarios involving multiple pulp instances.
The mailbox api is entirely compatible with passing messages
between fibers across disparate pulp instances. In such
scenarios, it's unobvious which pulp instance you'd supply to
this function - the sender or the recipient's? Well, neither!
This way you just supply the destination/recipient's fiber, and
it returns the mailslot if the fiber accepts mail.
|
|
Rather than having pulp_tick() on win32 always fiberize/unfiberize the
thread at the start/end of the tick, just fiberize once at library
initialization time.
The old approach was problematic with nested pulp instances. As in,
when a fiber called pulp_tick() on another pulp_t, in scenarios where
the programmer has arranged for a fiber heirarchy of sorts, the nested
pulp_tick() would once again fiberize the already fiberized thread,
then unfiberize, and poof the magic smoke comes out.
Rather than maintaining some kind of reference count and transparently
fiberize vs. getcurrentfiber in pulp_tick(), I'm just introducing the
explicit initialization to address this limitation. This way
pulp_tick() can just always get the current fiber for the calling
context on win32.
The initializer currently does nothing on *nix/ucontext.h systems,
this is just a win32 issue.
|
|
|
|
This needs to be tested, though its use in the example is contrived.
|
|
|
|
|
|
In cases where the run queue was empty, the trampoline context would
immediately enter the caller context. Then the trampoline would be
reused again without being re-setup.
This seemed to work fine on Linux but was causing bus errors on OSX.
So instead now enter_context never used and contexts are always
swapped to preserve the state of the context being left, which
seems to have fixed the problem on OSX.
|
|
I don't have an OSX system to test with, but after some digging
this looks like it might suffice.
|
|
|
|
This adds a rudimentary win32 implementation based on the
fibers system API. It seems to work reasonably under wine when
built w/mingw32.
|
|
Forgot to update the example when adding the mailbox feature.
Thanks Phil!
|
|
The sleep functions, which are few, and the only current means for
fibers to block/enter the scheduler, now take an optional
pulp_mailbox_t * parameter.
When supplied, other fibers may communicate with the sleeping fiber
via pulp_fiber_get_mailslot(). This function checks the destination
fiber for a mailbox and verifies there's space available. On success,
it returns a pointer to the next available mailslot while advancing
the mailboxes mail count.
The caller may then use this mailslot pointer to write directly to the
void * it references in the mailbox. If the receiving fiber took care
to populate its mailbox with slots referencing external memory, the
sender could dereference the mailslot's value to find the external
memory and write larger messages without needing to allocate new space
itself only for the reciever to have to free it shortly.
It's also possible to not do anything at all with the mailslot. Simply
successfully getting a mailslot communicates _something_ to the
recipient by virtue of the count advancing.
The returned mailslot can only be considered valid by the calling
fiber until it sleeps, after that the slot must be treated as
reclaimed from the perspective of the fiber that called
pulp_fiber_get_mailslot().
When the sleeping fiber wakes and returns from its mailbox-enabled
sleep call, it simply looks at the count member of the mailbox to see
if any mail was received. It's up to the implementation what is done
with the contents of the mailbox.
The mailbox count is always reset to 0 automatically at the start of a
mailbox-enabled sleep.
|
|
Analogous to pthread_self()
|
|
Expiring alarms of sleeping fibers in pulp_schedule() has the potential
to prevent pulp_tick() from ever returning if there's always another
fiber expiring @ schedule.
In order to allow simple integration with external event loops, pulp_tick()
is supposed to operate on what is essentially a slice of runnable fibers
then immediately return control to the caller.
|
|
Let the user of pulp.h control how they get at this struct,
our libthunk submodule fulfills our implementation needs but
the caller's build architecture should be free to fulfill this
type however it wants - there may be no thunk.h at all but
they still would include pulp.h.
|
|
|
|
libpulp is a very basic cooperatively-scheduled userspace threading
library. It refers to the userspace threads as fibers, and uses my
other little library libthunk to bind the functions and their calling
environment into tidy little structures having a uniform calling
convention.
At this time there's no build system or anything of the sort, it's
early days and I'll probably be submoduling this into another project
for direct inclusion and compilation.
|