summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pulp.c69
-rw-r--r--src/pulp.h11
2 files changed, 73 insertions, 7 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 */
diff --git a/src/pulp.h b/src/pulp.h
index 6111c80..c7edd0f 100644
--- a/src/pulp.h
+++ b/src/pulp.h
@@ -24,14 +24,21 @@ typedef struct pulp_t pulp_t;
typedef uint64_t pulp_usec_t;
typedef struct thunk_t thunk_t;
+/* for conveniences like trivial stack allocation, this is public */
+typedef struct pulp_mailbox_t {
+ unsigned size, count;
+ void *slots[];
+} pulp_mailbox_t;
+
pulp_t * pulp_new(void);
void pulp_free(pulp_t *pulp);
int pulp_tick(pulp_t *pulp, unsigned *next_tick_delay_us);
void pulp_run(pulp_t *pulp);
pulp_fiber_t * pulp_fiber_new(pulp_t *pulp, unsigned delay_ms, thunk_t *thunk);
-void pulp_msleep(pulp_t *pulp, unsigned milliseconds);
-void pulp_sleep(pulp_t *pulp, unsigned seconds);
+void pulp_msleep(pulp_t *pulp, unsigned milliseconds, pulp_mailbox_t *mailbox);
+void pulp_sleep(pulp_t *pulp, unsigned seconds, pulp_mailbox_t *mailbox);
pulp_usec_t pulp_now(pulp_t *pulp);
pulp_fiber_t * pulp_self(pulp_t *pulp);
+int pulp_fiber_get_mailslot(pulp_t *pulp, pulp_fiber_t *fiber, void ***res_mailslot);
#endif
© All Rights Reserved