summaryrefslogtreecommitdiff
path: root/src/pulp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulp.c')
-rw-r--r--src/pulp.c69
1 files changed, 64 insertions, 5 deletions
diff --git a/src/pulp.c b/src/pulp.c
index 4166dc5..140a5f4 100644
--- a/src/pulp.c
+++ b/src/pulp.c
@@ -57,6 +57,7 @@ typedef struct pulp_fiber_t {
union {
struct {
pulp_usec_t alarm;
+ pulp_mailbox_t *mailbox; /* non-NULL if fiber receives mail */
} sleep;
} state;
@@ -409,10 +410,15 @@ pulp_fiber_t * pulp_self(pulp_t *pulp)
/* sleep for the supplied number of microseconds (not public) */
-static void pulp_usleep(pulp_t *pulp, unsigned useconds)
+/* if mailbox is non-NULL it may be used to receive mail while sleeping via pulp_fiber_get_mailslot() */
+static void pulp_usleep(pulp_t *pulp, unsigned useconds, pulp_mailbox_t *mailbox)
{
assert(pulp);
+ pulp->current->state.sleep.mailbox = mailbox;
+ if (mailbox)
+ mailbox->count = 0;
+
pulp->current->state.sleep.alarm = pulp->now + useconds;
put_current_fiber(pulp, &pulp->fibers.sleep);
pulp_schedule(pulp);
@@ -420,20 +426,22 @@ static void pulp_usleep(pulp_t *pulp, unsigned useconds)
/* sleep for the supplied number of milliseconds */
-void pulp_msleep(pulp_t *pulp, unsigned milliseconds)
+/* if mailbox is non-NULL it may be used to receive mail while sleeping via pulp_fiber_get_mailslot() */
+void pulp_msleep(pulp_t *pulp, unsigned milliseconds, pulp_mailbox_t *mailbox)
{
assert(pulp);
- return pulp_usleep(pulp, milliseconds * PULP_USECS_PER_MSEC);
+ return pulp_usleep(pulp, milliseconds * PULP_USECS_PER_MSEC, mailbox);
}
/* sleep for the supplied number of seconds */
-void pulp_sleep(pulp_t *pulp, unsigned seconds)
+/* if mailbox is non-NULL it may be used to receive mail while sleeping via pulp_fiber_get_mailslot() */
+void pulp_sleep(pulp_t *pulp, unsigned seconds, pulp_mailbox_t *mailbox)
{
assert(pulp);
- return pulp_usleep(pulp, seconds * PULP_USECS_PER_SEC);
+ return pulp_usleep(pulp, seconds * PULP_USECS_PER_SEC, mailbox);
}
@@ -447,6 +455,57 @@ pulp_usec_t pulp_now(pulp_t *pulp)
}
+/* Get a mailslot in a destination fiber's mailbox.
+ * If the fiber has no mailbox, -ENOENT is returned.
+ * If the mailbox is full, -ENOSPC is returned.
+ * On success 0 is returned and the mailslot pointer is stored @ *res_mailslot.
+ *
+ * The mailslot can only be treated as valid until the calling fiber sleeps,
+ * after sleeping the receiving fiber may execute, then free, or clear and
+ * reuse its mailbox.
+ *
+ * This interface returns a pointer to the slot rather than accepting something
+ * like a void * value to store at the slot to allow a greater variety of data
+ * passing models. If your fibers are creating mailboxes having slots filled
+ * with pointers to valid memory, then the sender may dereference the
+ * mailslot's pointer to the space for storing the message rather than having
+ * to allocate space for passing messages larger than a pointer.
+ *
+ * Of course, if your scenario is simple enough, you can always simply write to
+ * the mailslot's void * worth of space. There's also the possibility of not
+ * writing anything at all; if the only thing needed is a basic signal - the
+ * mailbox count will be advanced wether you do anything with the mailslot or
+ * not. It's up to you to define the contract for your fibers to agree on.
+ */
+int pulp_fiber_get_mailslot(pulp_t *pulp, pulp_fiber_t *fiber, void ***res_mailslot)
+{
+ assert(pulp);
+ assert(fiber);
+ assert(res_mailslot);
+
+ /* XXX: this doesn't currently implement any blocking - if the mailbox
+ * is full or the fiber isn't receiving mail (no mailbox), we simply return
+ * failure. It seems trivial to make this fiber go to sleep when the
+ * mailbox is full then retrying when it comes back though. We'll see if
+ * that's desirable (reliable delivery). What I'm expecting is that mailboxes
+ * should just be sized to never experience blocking.
+ */
+
+ /* TODO: nothing is sanity checked at this time, I assume the supplied fiber
+ * is valid and sleeping.
+ */
+ if (!fiber->state.sleep.mailbox)
+ return -ENOENT;
+
+ if (fiber->state.sleep.mailbox->count >= fiber->state.sleep.mailbox->size)
+ return -ENOSPC;
+
+ *res_mailslot = &fiber->state.sleep.mailbox->slots[fiber->state.sleep.mailbox->count++];
+
+ return 0;
+}
+
+
/* TODO: interfaces for idling/waking fibers */
/* TODO: interfaces for synchronization across fibers */
/* all these are left to be implemented as their needs arise */
© All Rights Reserved