Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adopt specialized autochunking allocator to support dynamic allocation #2

Merged
merged 2 commits into from
Jun 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 99 additions & 86 deletions events.c
Original file line number Diff line number Diff line change
@@ -1,63 +1,33 @@
#include "events.h"

#include <stdlib.h>
#include <stddef.h>
#include <string.h>


// internal callback callback
struct ecallback {
void (*cb)(void*);
void *data;
};

static void ecallback_dispatch(void *p) {
struct ecallback *e = (struct ecallback*)p;
e->cb(e->data);
}

// equeue functions
static inline struct event *equeue_event(struct equeue *q, unsigned i) {
return (struct event*)((char*)q->buffer + i*q->size);
}

static inline unsigned equeue_size(unsigned size) {
if (size < sizeof(struct ecallback)) {
size = sizeof(struct ecallback);
}

unsigned alignment = offsetof(struct { char c; struct event e; }, e);
size += sizeof(struct event);
return (size + alignment-1) & ~(alignment-1);
}

int equeue_create(struct equeue *q, unsigned count, unsigned size) {
void *buffer = malloc(count * equeue_size(size));
int equeue_create(struct equeue *q, unsigned size) {
void *buffer = malloc(size);
if (!buffer) {
return -1;
}

return equeue_create_inplace(q, count, size, buffer);
int err = equeue_create_inplace(q, size, buffer);
q->buffer = buffer;
return err;
}

int equeue_create_inplace(struct equeue *q,
unsigned count, unsigned size, void *buffer) {
q->size = equeue_size(size);
q->buffer = buffer;
q->free = (struct event*)buffer;
int equeue_create_inplace(struct equeue *q, unsigned size, void *buffer) {
q->slab.size = size;
q->slab.data = buffer;
q->chunks = 0;
q->buffer = 0;

q->queue = 0;
q->next_id = 42;
q->break_ = (struct event){
.id = 0,
.period = -1,
};

if (q->free) {
for (unsigned i = 0; i < count-1; i++) {
equeue_event(q, i)->next = equeue_event(q, i+1);
}
equeue_event(q, count-1)->next = 0;
}

int err;
err = events_sema_create(&q->eventsema);
if (err < 0) {
Expand All @@ -84,56 +54,108 @@ void equeue_destroy(struct equeue *q) {
free(q->buffer);
}

// equeue mem functions
static int equeue_next_id(struct equeue *q) {
// equeue allocation functions
static void *equeue_alloc(struct equeue *q, unsigned size) {
size = size + sizeof(unsigned);
size = (size + sizeof(unsigned)-1) & ~(sizeof(unsigned)-1);
if (size < sizeof(struct equeue_chunk)) {
size = sizeof(struct equeue_chunk);
}

events_mutex_lock(&q->freelock);

for (struct equeue_chunk **p = &q->chunks; *p; p = &(*p)->nchunk) {
if ((*p)->size >= size) {
struct equeue_chunk *c = *p;
if (c->next) {
*p = c->next;
(*p)->nchunk = c->nchunk;
} else {
*p = c->nchunk;
}
events_mutex_unlock(&q->freelock);
return (unsigned *)c + 1;
}
}

if (q->slab.size >= size) {
struct equeue_chunk *c = (struct equeue_chunk *)q->slab.data;
q->slab.data += size;
q->slab.size -= size;
c->size = size;
events_mutex_unlock(&q->freelock);
return (unsigned *)c + 1;
}

events_mutex_unlock(&q->freelock);
return 0;
}

static void equeue_dealloc(struct equeue *q, void *e) {
struct equeue_chunk *c = (struct equeue_chunk *)((unsigned *)e - 1);

events_mutex_lock(&q->freelock);

struct equeue_chunk **p = &q->chunks;
while (*p && (*p)->size < c->size) {
p = &(*p)->nchunk;
}

if (*p && (*p)->size == c->size) {
c->next = *p;
c->nchunk = (*p)->nchunk;
} else {
c->next = 0;
c->nchunk = *p;
}
*p = c;

events_mutex_unlock(&q->freelock);
}

// event allocation functions
static inline int event_next_id(struct equeue *q) {
int id = q->next_id++;
if (q->next_id < 0) {
q->next_id = 42;
}
return id;
}

static struct event *equeue_alloc(struct equeue *q) {
struct event *e = 0;

events_mutex_lock(&q->freelock);
if (!q->free) {
events_mutex_unlock(&q->freelock);
void *event_alloc(struct equeue *q, unsigned size) {
struct event *e = equeue_alloc(q, sizeof(struct event) + size);
if (!e) {
return 0;
}

e = q->free;
q->free = e->next;
events_mutex_unlock(&q->freelock);

e->id = equeue_next_id(q);
e->id = event_next_id(q);
e->target = 0;
e->period = -1;
e->dtor = 0;
return e;

return e + 1;
}

static void equeue_dealloc(struct equeue *q, struct event *e) {
void event_dealloc(struct equeue *q, void *p) {
struct event *e = (struct event*)p - 1;

if (e->dtor) {
e->dtor(e+1);
}

events_mutex_lock(&q->freelock);
e->next = q->free;
q->free = e;
events_mutex_unlock(&q->freelock);
equeue_dealloc(q, e);
}

// equeue scheduling functions
static inline int tickdiff(unsigned a, unsigned b) {
static inline int equeue_tickdiff(unsigned a, unsigned b) {
return (int)(a - b);
}

static int equeue_enqueue(struct equeue *q, struct event *e, int ms) {
e->target = events_tick() + (unsigned)ms;

struct event **p = &q->queue;
while (*p && tickdiff((*p)->target, e->target) <= 0) {
while (*p && equeue_tickdiff((*p)->target, e->target) <= 0) {
p = &(*p)->next;
}

Expand Down Expand Up @@ -169,7 +191,7 @@ static void equeue_cancel(struct equeue *q, int id) {
events_mutex_unlock(&q->queuelock);

if (e) {
equeue_dealloc(q, e);
event_dealloc(q, e+1);
}
}

Expand All @@ -194,7 +216,7 @@ void equeue_dispatch(struct equeue *q, int ms) {
break;
}

deadline = tickdiff(q->queue->target, events_tick());
deadline = equeue_tickdiff(q->queue->target, events_tick());
if (deadline > 0) {
events_mutex_unlock(&q->queuelock);
break;
Expand All @@ -218,7 +240,7 @@ void equeue_dispatch(struct equeue *q, int ms) {
e->cb(e + 1);

if (e->period < 0) {
equeue_dealloc(q, e);
event_dealloc(q, e+1);
}
}

Expand All @@ -227,25 +249,6 @@ void equeue_dispatch(struct equeue *q, int ms) {
}

// event functions
void *event_alloc(struct equeue *q, unsigned size) {
if (size > q->size - sizeof(struct event)) {
return 0;
}

struct event *e = equeue_alloc(q);
if (!e) {
return 0;
}

return e + 1;
}

void event_dealloc(struct equeue *q, void *p) {
struct event *e = (struct event*)p - 1;
equeue_dealloc(q, e);
}

// configuring events
void event_delay(void *p, int ms) {
struct event *e = (struct event*)p - 1;
e->target = ms;
Expand Down Expand Up @@ -273,7 +276,17 @@ void event_cancel(struct equeue *q, int id) {
return equeue_cancel(q, id);
}

// event helper functions
// simple callbacks
struct ecallback {
void (*cb)(void*);
void *data;
};

static void ecallback_dispatch(void *p) {
struct ecallback *e = (struct ecallback*)p;
e->cb(e->data);
}

int event_call(struct equeue *q, void (*cb)(void*), void *data) {
struct ecallback *e = event_alloc(q, sizeof(struct ecallback));
if (!e) {
Expand Down
19 changes: 13 additions & 6 deletions events.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,20 @@ struct event {
};

struct equeue {
unsigned size;
struct event *queue;
struct event *free;
void *buffer;
int next_id;

void *buffer;
struct equeue_chunk {
unsigned size;
struct equeue_chunk *next;
struct equeue_chunk *nchunk;
} *chunks;
struct equeue_slab {
unsigned size;
unsigned char *data;
} slab;

struct event break_;

events_sema_t eventsema;
Expand All @@ -43,9 +51,8 @@ struct equeue {
// Queue operations
//
// Creation results in negative value on failure.
int equeue_create(struct equeue*, unsigned count, unsigned size);
int equeue_create_inplace(struct equeue*,
unsigned count, unsigned size, void *buffer);
int equeue_create(struct equeue*, unsigned size);
int equeue_create_inplace(struct equeue*, unsigned size, void *buffer);
void equeue_destroy(struct equeue*);

// Dispatch events
Expand Down