Skip to content

Commit 073fafb

Browse files
authored
Merge pull request ARMmbed#2 from geky/autochunking
Adopt specialized autochunking allocator to support dynamic allocation
2 parents f83507a + 186cbde commit 073fafb

File tree

2 files changed

+112
-92
lines changed

2 files changed

+112
-92
lines changed

events.c

Lines changed: 99 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,33 @@
11
#include "events.h"
22

33
#include <stdlib.h>
4-
#include <stddef.h>
4+
#include <string.h>
55

66

7-
// internal callback callback
8-
struct ecallback {
9-
void (*cb)(void*);
10-
void *data;
11-
};
12-
13-
static void ecallback_dispatch(void *p) {
14-
struct ecallback *e = (struct ecallback*)p;
15-
e->cb(e->data);
16-
}
17-
18-
// equeue functions
19-
static inline struct event *equeue_event(struct equeue *q, unsigned i) {
20-
return (struct event*)((char*)q->buffer + i*q->size);
21-
}
22-
23-
static inline unsigned equeue_size(unsigned size) {
24-
if (size < sizeof(struct ecallback)) {
25-
size = sizeof(struct ecallback);
26-
}
27-
28-
unsigned alignment = offsetof(struct { char c; struct event e; }, e);
29-
size += sizeof(struct event);
30-
return (size + alignment-1) & ~(alignment-1);
31-
}
32-
33-
int equeue_create(struct equeue *q, unsigned count, unsigned size) {
34-
void *buffer = malloc(count * equeue_size(size));
7+
int equeue_create(struct equeue *q, unsigned size) {
8+
void *buffer = malloc(size);
359
if (!buffer) {
3610
return -1;
3711
}
3812

39-
return equeue_create_inplace(q, count, size, buffer);
13+
int err = equeue_create_inplace(q, size, buffer);
14+
q->buffer = buffer;
15+
return err;
4016
}
4117

42-
int equeue_create_inplace(struct equeue *q,
43-
unsigned count, unsigned size, void *buffer) {
44-
q->size = equeue_size(size);
45-
q->buffer = buffer;
46-
q->free = (struct event*)buffer;
18+
int equeue_create_inplace(struct equeue *q, unsigned size, void *buffer) {
19+
q->slab.size = size;
20+
q->slab.data = buffer;
21+
q->chunks = 0;
22+
q->buffer = 0;
23+
4724
q->queue = 0;
4825
q->next_id = 42;
4926
q->break_ = (struct event){
5027
.id = 0,
5128
.period = -1,
5229
};
5330

54-
if (q->free) {
55-
for (unsigned i = 0; i < count-1; i++) {
56-
equeue_event(q, i)->next = equeue_event(q, i+1);
57-
}
58-
equeue_event(q, count-1)->next = 0;
59-
}
60-
6131
int err;
6232
err = events_sema_create(&q->eventsema);
6333
if (err < 0) {
@@ -84,56 +54,108 @@ void equeue_destroy(struct equeue *q) {
8454
free(q->buffer);
8555
}
8656

87-
// equeue mem functions
88-
static int equeue_next_id(struct equeue *q) {
57+
// equeue allocation functions
58+
static void *equeue_alloc(struct equeue *q, unsigned size) {
59+
size = size + sizeof(unsigned);
60+
size = (size + sizeof(unsigned)-1) & ~(sizeof(unsigned)-1);
61+
if (size < sizeof(struct equeue_chunk)) {
62+
size = sizeof(struct equeue_chunk);
63+
}
64+
65+
events_mutex_lock(&q->freelock);
66+
67+
for (struct equeue_chunk **p = &q->chunks; *p; p = &(*p)->nchunk) {
68+
if ((*p)->size >= size) {
69+
struct equeue_chunk *c = *p;
70+
if (c->next) {
71+
*p = c->next;
72+
(*p)->nchunk = c->nchunk;
73+
} else {
74+
*p = c->nchunk;
75+
}
76+
events_mutex_unlock(&q->freelock);
77+
return (unsigned *)c + 1;
78+
}
79+
}
80+
81+
if (q->slab.size >= size) {
82+
struct equeue_chunk *c = (struct equeue_chunk *)q->slab.data;
83+
q->slab.data += size;
84+
q->slab.size -= size;
85+
c->size = size;
86+
events_mutex_unlock(&q->freelock);
87+
return (unsigned *)c + 1;
88+
}
89+
90+
events_mutex_unlock(&q->freelock);
91+
return 0;
92+
}
93+
94+
static void equeue_dealloc(struct equeue *q, void *e) {
95+
struct equeue_chunk *c = (struct equeue_chunk *)((unsigned *)e - 1);
96+
97+
events_mutex_lock(&q->freelock);
98+
99+
struct equeue_chunk **p = &q->chunks;
100+
while (*p && (*p)->size < c->size) {
101+
p = &(*p)->nchunk;
102+
}
103+
104+
if (*p && (*p)->size == c->size) {
105+
c->next = *p;
106+
c->nchunk = (*p)->nchunk;
107+
} else {
108+
c->next = 0;
109+
c->nchunk = *p;
110+
}
111+
*p = c;
112+
113+
events_mutex_unlock(&q->freelock);
114+
}
115+
116+
// event allocation functions
117+
static inline int event_next_id(struct equeue *q) {
89118
int id = q->next_id++;
90119
if (q->next_id < 0) {
91120
q->next_id = 42;
92121
}
93122
return id;
94123
}
95124

96-
static struct event *equeue_alloc(struct equeue *q) {
97-
struct event *e = 0;
98-
99-
events_mutex_lock(&q->freelock);
100-
if (!q->free) {
101-
events_mutex_unlock(&q->freelock);
125+
void *event_alloc(struct equeue *q, unsigned size) {
126+
struct event *e = equeue_alloc(q, sizeof(struct event) + size);
127+
if (!e) {
102128
return 0;
103129
}
104130

105-
e = q->free;
106-
q->free = e->next;
107-
events_mutex_unlock(&q->freelock);
108-
109-
e->id = equeue_next_id(q);
131+
e->id = event_next_id(q);
110132
e->target = 0;
111133
e->period = -1;
112134
e->dtor = 0;
113-
return e;
135+
136+
return e + 1;
114137
}
115138

116-
static void equeue_dealloc(struct equeue *q, struct event *e) {
139+
void event_dealloc(struct equeue *q, void *p) {
140+
struct event *e = (struct event*)p - 1;
141+
117142
if (e->dtor) {
118143
e->dtor(e+1);
119144
}
120145

121-
events_mutex_lock(&q->freelock);
122-
e->next = q->free;
123-
q->free = e;
124-
events_mutex_unlock(&q->freelock);
146+
equeue_dealloc(q, e);
125147
}
126148

127149
// equeue scheduling functions
128-
static inline int tickdiff(unsigned a, unsigned b) {
150+
static inline int equeue_tickdiff(unsigned a, unsigned b) {
129151
return (int)(a - b);
130152
}
131153

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

135157
struct event **p = &q->queue;
136-
while (*p && tickdiff((*p)->target, e->target) <= 0) {
158+
while (*p && equeue_tickdiff((*p)->target, e->target) <= 0) {
137159
p = &(*p)->next;
138160
}
139161

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

171193
if (e) {
172-
equeue_dealloc(q, e);
194+
event_dealloc(q, e+1);
173195
}
174196
}
175197

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

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

220242
if (e->period < 0) {
221-
equeue_dealloc(q, e);
243+
event_dealloc(q, e+1);
222244
}
223245
}
224246

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

229251
// event functions
230-
void *event_alloc(struct equeue *q, unsigned size) {
231-
if (size > q->size - sizeof(struct event)) {
232-
return 0;
233-
}
234-
235-
struct event *e = equeue_alloc(q);
236-
if (!e) {
237-
return 0;
238-
}
239-
240-
return e + 1;
241-
}
242-
243-
void event_dealloc(struct equeue *q, void *p) {
244-
struct event *e = (struct event*)p - 1;
245-
equeue_dealloc(q, e);
246-
}
247-
248-
// configuring events
249252
void event_delay(void *p, int ms) {
250253
struct event *e = (struct event*)p - 1;
251254
e->target = ms;
@@ -273,7 +276,17 @@ void event_cancel(struct equeue *q, int id) {
273276
return equeue_cancel(q, id);
274277
}
275278

276-
// event helper functions
279+
// simple callbacks
280+
struct ecallback {
281+
void (*cb)(void*);
282+
void *data;
283+
};
284+
285+
static void ecallback_dispatch(void *p) {
286+
struct ecallback *e = (struct ecallback*)p;
287+
e->cb(e->data);
288+
}
289+
277290
int event_call(struct equeue *q, void (*cb)(void*), void *data) {
278291
struct ecallback *e = event_alloc(q, sizeof(struct ecallback));
279292
if (!e) {

events.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,20 @@ struct event {
2727
};
2828

2929
struct equeue {
30-
unsigned size;
3130
struct event *queue;
32-
struct event *free;
33-
void *buffer;
3431
int next_id;
3532

33+
void *buffer;
34+
struct equeue_chunk {
35+
unsigned size;
36+
struct equeue_chunk *next;
37+
struct equeue_chunk *nchunk;
38+
} *chunks;
39+
struct equeue_slab {
40+
unsigned size;
41+
unsigned char *data;
42+
} slab;
43+
3644
struct event break_;
3745

3846
events_sema_t eventsema;
@@ -43,9 +51,8 @@ struct equeue {
4351
// Queue operations
4452
//
4553
// Creation results in negative value on failure.
46-
int equeue_create(struct equeue*, unsigned count, unsigned size);
47-
int equeue_create_inplace(struct equeue*,
48-
unsigned count, unsigned size, void *buffer);
54+
int equeue_create(struct equeue*, unsigned size);
55+
int equeue_create_inplace(struct equeue*, unsigned size, void *buffer);
4956
void equeue_destroy(struct equeue*);
5057

5158
// Dispatch events

0 commit comments

Comments
 (0)