Skip to content

Commit 2a61147

Browse files
committed
Added a queue implementation. Properly use memhook instead of plain free in stack.
1 parent 86a9466 commit 2a61147

File tree

13 files changed

+486
-9
lines changed

13 files changed

+486
-9
lines changed

Lib/public/module/queue.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#pragma once
2+
3+
#include "module_cmn.h"
4+
5+
/** Queue interface **/
6+
7+
typedef enum {
8+
QUEUE_WRONG_PARAM = -4,
9+
QUEUE_MISSING,
10+
QUEUE_ERR,
11+
QUEUE_OMEM,
12+
QUEUE_OK
13+
} queue_ret_code;
14+
15+
/* Callback for queue_iterate */
16+
typedef queue_ret_code (*queue_cb)(void *, void *);
17+
18+
/* Fn for queue_set_dtor */
19+
typedef void (*queue_dtor)(void *);
20+
21+
/* Incomplete struct declaration for queue */
22+
typedef struct _queue queue_t;
23+
24+
/* Incomplete struct declaration for queue iterator */
25+
typedef struct _queue_itr queue_itr_t;
26+
27+
#ifdef __cplusplus
28+
extern "C"{
29+
#endif
30+
31+
_public_ queue_t *queue_new(const queue_dtor fn);
32+
_public_ queue_itr_t *queue_itr_new(const queue_t *q);
33+
_public_ queue_itr_t *queue_itr_next(queue_itr_t *itr);
34+
_public_ void *queue_itr_get_data(const queue_itr_t *itr);
35+
_public_ queue_ret_code queue_itr_set_data(const queue_itr_t *itr, void *value);
36+
_public_ queue_ret_code queue_iterate(const queue_t *q, const queue_cb fn, void *userptr);
37+
_public_ queue_ret_code queue_enqueue(queue_t *q, void *data);
38+
_public_ void *queue_dequeue(queue_t *q);
39+
_public_ void *queue_peek(const queue_t *q);
40+
_public_ queue_ret_code queue_clear(queue_t *q);
41+
_public_ queue_ret_code queue_free(queue_t *q);
42+
_public_ ssize_t queue_length(const queue_t *q);
43+
44+
#ifdef __cplusplus
45+
}
46+
#endif

Lib/pubsub.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,4 +256,4 @@ module_ret_code module_poisonpill(const self_t *self, const self_t *recipient) {
256256
MOD_PARAM_ASSERT(module_is(recipient, RUNNING));
257257

258258
return tell_system_pubsub_msg(recipient->mod, c, MODULE_POISONPILL, &mod->self, NULL);
259-
}
259+
}

Lib/queue.c

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
#include "poll_priv.h"
2+
#include "queue.h"
3+
4+
#define QUEUE_PARAM_ASSERT(cond) MOD_RET_ASSERT(cond, QUEUE_WRONG_PARAM);
5+
6+
typedef struct _elem {
7+
void *userptr;
8+
struct _elem *prev;
9+
} queue_elem;
10+
11+
struct _queue {
12+
size_t len;
13+
queue_dtor dtor;
14+
queue_elem *head;
15+
queue_elem *tail;
16+
};
17+
18+
struct _queue_itr {
19+
queue_elem *elem;
20+
};
21+
22+
/** Public API **/
23+
24+
queue_t *queue_new(const queue_dtor fn) {
25+
queue_t *q = memhook._calloc(1, sizeof(queue_t));
26+
if (q) {
27+
q->dtor = fn;
28+
}
29+
return q;
30+
}
31+
32+
queue_itr_t *queue_itr_new(const queue_t *q) {
33+
MOD_RET_ASSERT(queue_length(q) > 0, NULL);
34+
35+
queue_itr_t *itr = memhook._malloc(sizeof(queue_itr_t));
36+
if (itr) {
37+
itr->elem = q->head;
38+
}
39+
return itr;
40+
}
41+
42+
queue_itr_t *queue_itr_next(queue_itr_t *itr) {
43+
MOD_RET_ASSERT(itr, NULL);
44+
45+
itr->elem = itr->elem->prev;
46+
if (!itr->elem) {
47+
memhook._free(itr);
48+
itr = NULL;
49+
}
50+
return itr;
51+
}
52+
53+
void *queue_itr_get_data(const queue_itr_t *itr) {
54+
MOD_RET_ASSERT(itr, NULL);
55+
56+
return itr->elem->userptr;
57+
}
58+
59+
queue_ret_code queue_itr_set_data(const queue_itr_t *itr, void *value) {
60+
QUEUE_PARAM_ASSERT(itr);
61+
QUEUE_PARAM_ASSERT(value);
62+
63+
itr->elem->userptr = value;
64+
return QUEUE_OK;
65+
}
66+
67+
queue_ret_code queue_iterate(const queue_t *q, const queue_cb fn, void *userptr) {
68+
QUEUE_PARAM_ASSERT(fn);
69+
MOD_RET_ASSERT(queue_length(q) > 0, QUEUE_MISSING);
70+
71+
queue_elem *elem = q->head;
72+
while (elem) {
73+
queue_ret_code rc = fn(userptr, elem->userptr);
74+
if (rc < QUEUE_OK) {
75+
/* Stop right now with error */
76+
return rc;
77+
}
78+
if (rc > QUEUE_OK) {
79+
/* Stop right now with MAP_OK */
80+
return QUEUE_OK;
81+
}
82+
elem = elem->prev;
83+
}
84+
return QUEUE_OK;
85+
}
86+
87+
queue_ret_code queue_enqueue(queue_t *q, void *data) {
88+
QUEUE_PARAM_ASSERT(q);
89+
QUEUE_PARAM_ASSERT(data);
90+
91+
queue_elem *elem = memhook._calloc(1, sizeof(queue_elem));
92+
if (elem) {
93+
q->len++;
94+
elem->userptr = data;
95+
if (q->tail) {
96+
q->tail->prev = elem;
97+
}
98+
q->tail = elem;
99+
if (!q->head) {
100+
q->head = q->tail;
101+
}
102+
return QUEUE_OK;
103+
}
104+
return QUEUE_OMEM;
105+
}
106+
107+
void *queue_dequeue(queue_t *q) {
108+
MOD_RET_ASSERT(queue_length(q) > 0, NULL);
109+
110+
queue_elem *elem = q->head;
111+
if (q->tail == q->head) {
112+
q->tail = NULL;
113+
}
114+
q->head = q->head->prev;
115+
116+
void *data = elem->userptr;
117+
memhook._free(elem);
118+
q->len--;
119+
return data;
120+
}
121+
122+
void *queue_peek(const queue_t *q) {
123+
MOD_RET_ASSERT(queue_length(q) > 0, NULL);
124+
125+
return q->head->userptr;
126+
}
127+
128+
queue_ret_code queue_clear(queue_t *q) {
129+
QUEUE_PARAM_ASSERT(q);
130+
131+
queue_elem *elem = NULL;
132+
while ((elem = q->head) && q->len > 0) {
133+
void *data = queue_dequeue(q);
134+
if (q->dtor) {
135+
q->dtor(data);
136+
}
137+
}
138+
return QUEUE_OK;
139+
}
140+
141+
queue_ret_code queue_free(queue_t *q) {
142+
queue_ret_code ret = queue_clear(q);
143+
if (ret == QUEUE_OK) {
144+
memhook._free(q);
145+
}
146+
return ret;
147+
}
148+
149+
ssize_t queue_length(const queue_t *q) {
150+
QUEUE_PARAM_ASSERT(q);
151+
152+
return q->len;
153+
}
154+

Lib/stack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ stack_ret_code stack_clear(stack_t *s) {
130130
stack_ret_code stack_free(stack_t *s) {
131131
stack_ret_code ret = stack_clear(s);
132132
if (ret == STACK_OK) {
133-
free(s);
133+
memhook._free(s);
134134
}
135135
return ret;
136136
}

TODO.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ conversely to module_stop that should stop module right away freeing all its enq
5252
- [x] Set autofree in stack_new()
5353
- [x] Drop stack_set_dtor
5454

55+
### Queue
56+
- [x] Add queue API
57+
- [x] Add doc
58+
5559
### Generic
5660
- [x] Add some diagnostic API, eg: module_dump() (to dump each module's state)
5761
- [x] Add a module_load/unload function, to load a module from a compiled object at runtime
@@ -111,3 +115,4 @@ conversely to module_stop that should stop module right away freeing all its enq
111115

112116
## Ideas
113117
- [ ] Akka-persistence like message store? (ie: store all messages and replay them)
118+
- [ ] module_msg_ref/unref to forcefully keep an autofree message alive?

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Welcome to libmodule's documentation!
2020
src/modules
2121
src/map
2222
src/stack
23+
src/queue
2324

2425
Indices and tables
2526
==================

docs/src/map.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Where not specified, these functions return a map_ret_code.
6262

6363
.. c:function:: map_itr_next(itr)
6464
65-
Get next iterator. If next iterator is past last element, iterator will be automatically freed for you.
65+
Get next iterator. If next iterator is past last element, iterator will be automatically freed.
6666

6767
:param itr: pointer to map_itr_t
6868
:type itr: :c:type:`map_itr_t *`

docs/src/module.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ Again, where not specified, these functions return a :ref:`module_ret_code <modu
464464
:type autofree: :c:type:`const bool`
465465
:type global: :c:type:`const bool`
466466

467-
.. c:macro:: module_poisonpill(self, recipient)
467+
.. c:function:: module_poisonpill(self, recipient)
468468
469469
Enqueue a POISONPILL message to recipient. This allows to stop another module after it flushes its pubsub messages.
470470

0 commit comments

Comments
 (0)