Skip to content
This repository was archived by the owner on Aug 19, 2021. It is now read-only.

Commit 186cbde

Browse files
committed
Moved to unbounded chunk-lists
The previous allocator used a finite set of chunk-lists. This had the nice garuntee of strict constant allocation cost, but incurred unnecessary fragmentation once the set was exceeded. By using a linked-list of chunk-lists, this fragmentation can be avoided and the chunk-list scan potenially short-circuited, at the downside of introducing the quantity of different allocation sizes as a variable in the allocation cost.
1 parent d8bdcdf commit 186cbde

File tree

2 files changed

+41
-34
lines changed

2 files changed

+41
-34
lines changed

events.c

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "events.h"
22

33
#include <stdlib.h>
4-
#include <stddef.h>
54
#include <string.h>
65

76

@@ -19,7 +18,7 @@ int equeue_create(struct equeue *q, unsigned size) {
1918
int equeue_create_inplace(struct equeue *q, unsigned size, void *buffer) {
2019
q->slab.size = size;
2120
q->slab.data = buffer;
22-
memset(q->chunks, 0, EVENT_CHUNK_LISTS*sizeof(struct event*));
21+
q->chunks = 0;
2322
q->buffer = 0;
2423

2524
q->queue = 0;
@@ -56,53 +55,61 @@ void equeue_destroy(struct equeue *q) {
5655
}
5756

5857
// equeue allocation functions
59-
static inline unsigned equeue_size(unsigned size) {
60-
size += sizeof(struct event);
61-
unsigned alignment = offsetof(struct { char c; struct event e; }, e);
62-
return (size + alignment-1) & ~(alignment-1);
63-
}
64-
65-
static struct event *equeue_alloc(struct equeue *q, unsigned size) {
66-
size = equeue_size(size);
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+
}
6764

6865
events_mutex_lock(&q->freelock);
6966

70-
for (int i = 0; i < EVENT_CHUNK_LISTS; i++) {
71-
if (q->chunks[i] && q->chunks[i]->size >= size) {
72-
struct event *e = q->chunks[i];
73-
q->chunks[i] = e->next;
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+
}
7476
events_mutex_unlock(&q->freelock);
75-
return e;
77+
return (unsigned *)c + 1;
7678
}
7779
}
7880

7981
if (q->slab.size >= size) {
80-
struct event *e = (struct event *)q->slab.data;
82+
struct equeue_chunk *c = (struct equeue_chunk *)q->slab.data;
8183
q->slab.data += size;
8284
q->slab.size -= size;
83-
e->size = size;
85+
c->size = size;
8486
events_mutex_unlock(&q->freelock);
85-
return e;
87+
return (unsigned *)c + 1;
8688
}
8789

8890
events_mutex_unlock(&q->freelock);
8991
return 0;
9092
}
9193

92-
static void equeue_dealloc(struct equeue *q, struct event *e) {
93-
int i = 0;
94+
static void equeue_dealloc(struct equeue *q, void *e) {
95+
struct equeue_chunk *c = (struct equeue_chunk *)((unsigned *)e - 1);
9496

9597
events_mutex_lock(&q->freelock);
9698

97-
for (; i < EVENT_CHUNK_LISTS-1; i++) {
98-
if (q->chunks[i+1] && q->chunks[i+1]->size >= e->size) {
99-
break;
100-
}
99+
struct equeue_chunk **p = &q->chunks;
100+
while (*p && (*p)->size < c->size) {
101+
p = &(*p)->nchunk;
101102
}
102103

103-
e->next = q->chunks[i];
104-
q->chunks[i] = e;
105-
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+
106113
events_mutex_unlock(&q->freelock);
107114
}
108115

@@ -116,7 +123,7 @@ static inline int event_next_id(struct equeue *q) {
116123
}
117124

118125
void *event_alloc(struct equeue *q, unsigned size) {
119-
struct event *e = equeue_alloc(q, size);
126+
struct event *e = equeue_alloc(q, sizeof(struct event) + size);
120127
if (!e) {
121128
return 0;
122129
}

events.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,8 @@ extern "C" {
1414
#include "sys/events_sema.h"
1515

1616

17-
// Number of free-chunk lists per equeue
18-
#define EVENT_CHUNK_LISTS 4
19-
2017
// Event/queue structures
2118
struct event {
22-
unsigned size;
2319
struct event *next;
2420
int id;
2521
unsigned target;
@@ -35,8 +31,12 @@ struct equeue {
3531
int next_id;
3632

3733
void *buffer;
38-
struct event *chunks[EVENT_CHUNK_LISTS];
39-
struct {
34+
struct equeue_chunk {
35+
unsigned size;
36+
struct equeue_chunk *next;
37+
struct equeue_chunk *nchunk;
38+
} *chunks;
39+
struct equeue_slab {
4040
unsigned size;
4141
unsigned char *data;
4242
} slab;

0 commit comments

Comments
 (0)