Skip to content

Commit

Permalink
equeue: add user allocated event support
Browse files Browse the repository at this point in the history
Allow posting events allocated outside queue memory
  • Loading branch information
maciejbocianski committed Aug 27, 2019
1 parent e4e6c64 commit 4fa864a
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 19 deletions.
6 changes: 3 additions & 3 deletions events/equeue.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ void equeue_event_dtor(void *event, void (*dtor)(void *));
// Post an event onto the event queue
//
// The equeue_post function takes a callback and a pointer to an event
// allocated by equeue_alloc. The specified callback will be executed in the
// context of the event queue's dispatch loop with the allocated event
// as its argument.
// allocated by equeue_alloc or allocated by user. The specified callback will
// be executed in the context of the event queue's dispatch loop with
// the allocated event as its argument.
//
// The equeue_post function is irq safe and can act as a mechanism for
// moving events out of irq contexts.
Expand Down
67 changes: 51 additions & 16 deletions events/source/equeue.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
#include <stdint.h>
#include <string.h>

// check if the event is allocaded by user - event address is outside queues internal buffer address range
#define IS_USER_ALLOCATED_EVENT(e) (((unsigned int)(e) < (unsigned int)q->buffer) || ((unsigned int)(e) > ((unsigned int)q->slab.data)))
// for user allocated events set id as its address with first bit set
#define MAKE_USER_ALLOCATED_EVENT_ID(e) ((int)(((unsigned int)e) | 1))
#define IS_USER_ALLOCATED_EVENT_ID(id) (((id) & 1) == 1)

// calculate the relative-difference between absolute times while
// correctly handling overflow conditions
static inline int equeue_tickdiff(unsigned a, unsigned b)
Expand Down Expand Up @@ -220,15 +226,16 @@ void equeue_dealloc(equeue_t *q, void *p)
e->dtor(e + 1);
}

equeue_mem_dealloc(q, e);
if (!IS_USER_ALLOCATED_EVENT(e)) {
equeue_mem_dealloc(q, e);
}
}


// equeue scheduling functions
static int equeue_enqueue(equeue_t *q, struct equeue_event *e, unsigned tick)
{
// setup event and hash local id with buffer offset for unique id
int id = (e->id << q->npw2) | ((unsigned char *)e - q->buffer);
int id = IS_USER_ALLOCATED_EVENT(e) ? MAKE_USER_ALLOCATED_EVENT_ID(e) : ((e->id << q->npw2) | ((unsigned char *)e - q->buffer));
e->target = tick + equeue_clampdiff(e->target, tick);
e->generation = q->generation;

Expand Down Expand Up @@ -275,14 +282,29 @@ static int equeue_enqueue(equeue_t *q, struct equeue_event *e, unsigned tick)

static struct equeue_event *equeue_unqueue(equeue_t *q, int id)
{
// decode event from unique id and check that the local id matches
struct equeue_event *e = (struct equeue_event *)
&q->buffer[id & ((1 << q->npw2) - 1)];

equeue_mutex_lock(&q->queuelock);
if (e->id != id >> q->npw2) {
equeue_mutex_unlock(&q->queuelock);
return 0;
struct equeue_event *e = 0;
if (IS_USER_ALLOCATED_EVENT_ID(id)) {
equeue_mutex_lock(&q->queuelock);
struct equeue_event *cur = q->queue;
while (cur) {
if (MAKE_USER_ALLOCATED_EVENT_ID(cur) == id) {
e = cur;
break;
}
cur = cur->next;
}
if (!e) {
equeue_mutex_unlock(&q->queuelock);
return 0;
}
} else {
// decode event from unique id and check that the local id matches
e = (struct equeue_event *)&q->buffer[id & ((1 << q->npw2) - 1)];
equeue_mutex_lock(&q->queuelock);
if (e->id != id >> q->npw2) {
equeue_mutex_unlock(&q->queuelock);
return 0;
}
}

// clear the event and check if already in-flight
Expand Down Expand Up @@ -311,7 +333,9 @@ static struct equeue_event *equeue_unqueue(equeue_t *q, int id)
}
}

equeue_incid(q, e);
if (!IS_USER_ALLOCATED_EVENT_ID(id)) {
equeue_incid(q, e);
}
equeue_mutex_unlock(&q->queuelock);

return e;
Expand Down Expand Up @@ -394,11 +418,22 @@ int equeue_timeleft(equeue_t *q, int id)
return -1;
}

// decode event from unique id and check that the local id matches
struct equeue_event *e = (struct equeue_event *)
&q->buffer[id & ((1 << q->npw2) - 1)];

struct equeue_event *e = 0;
equeue_mutex_lock(&q->queuelock);
if (IS_USER_ALLOCATED_EVENT_ID(id)) {
struct equeue_event *cur = q->queue;
while (cur) {
if (MAKE_USER_ALLOCATED_EVENT_ID(cur) == id) {
e = cur;
break;
}
cur = cur->next;
}
} else {
// decode event from unique id and check that the local id matches
e = (struct equeue_event *)&q->buffer[id & ((1 << q->npw2) - 1)];
}

if (e->id == id >> q->npw2) {
ret = equeue_clampdiff(e->target, equeue_tick());
}
Expand Down

0 comments on commit 4fa864a

Please sign in to comment.