Skip to content

Commit ceb5160

Browse files
committed
Added a stack implementation to be used for each module become/unbecome functions, that are finally useful. Stack is public too.
1 parent 6a96810 commit ceb5160

File tree

17 files changed

+357
-20
lines changed

17 files changed

+357
-20
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required (VERSION 3.3.2)
22

3-
project(module VERSION 3.1.1 LANGUAGES C CXX)
3+
project(module VERSION 3.2.0 LANGUAGES C CXX)
44

55
if(NOT CMAKE_BUILD_TYPE)
66
set(CMAKE_BUILD_TYPE Release)

Lib/map.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -254,14 +254,10 @@ bool map_has_key(const map_t *m, const char *key) {
254254
map_ret_code map_iterate(map_t *m, const map_cb fn, void *userptr) {
255255
MOD_ASSERT(m, "NULL map.", MAP_WRONG_PARAM);
256256
MOD_ASSERT(fn, "NULL callback.", MAP_WRONG_PARAM);
257-
258-
/* On empty hashmap, return immediately */
259-
if (map_length(m) <= 0) {
260-
return MAP_MISSING;
261-
}
257+
MOD_ASSERT(map_length(m) > 0, "Empty map.", MAP_MISSING);
262258

263259
/* Linear probing */
264-
int status = MAP_OK;
260+
map_ret_code status = MAP_OK;
265261
for (int i = 0; i < m->table_size && status == MAP_OK; i++) {
266262
if (m->data[i].in_use) {
267263
void *data = m->data[i].data;

Lib/module.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ module_ret_code module_register(const char *name, const char *ctx_name, const se
113113
mod->state = IDLE;
114114
mod->fds = NULL;
115115
mod->subscriptions = map_new();
116+
mod->recvs = stack_new();
116117
*self = memhook._malloc(sizeof(self_t));
117118
self_t *s = (self_t *)*self;
118119
*((module **)&s->mod) = mod;
@@ -144,6 +145,7 @@ module_ret_code module_deregister(const self_t **self) {
144145
destroy_ctx(tmp->ctx);
145146
}
146147
map_free(mod->subscriptions);
148+
stack_free(mod->recvs);
147149
memhook._free((self_t *)*self);
148150
*self = NULL;
149151
mod->self = NULL;
@@ -181,8 +183,19 @@ module_ret_code module_become(const self_t *self, const recv_cb new_recv) {
181183
MOD_PARAM_ASSERT(new_recv);
182184
GET_MOD_IN_STATE(self, RUNNING);
183185

184-
mod->hook.recv = new_recv;
185-
return MOD_OK;
186+
if (stack_push(mod->recvs, new_recv, false) == STACK_OK) {
187+
return MOD_OK;
188+
}
189+
return MOD_ERR;
190+
}
191+
192+
module_ret_code module_unbecome(const self_t *self) {
193+
GET_MOD_IN_STATE(self, RUNNING);
194+
195+
if (stack_pop(mod->recvs) == STACK_OK) {
196+
return MOD_OK;
197+
}
198+
return MOD_ERR;
186199
}
187200

188201
module_ret_code module_log(const self_t *self, const char *fmt, ...) {

Lib/module_priv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <stdlib.h>
22
#include "map.h"
3+
#include "stack.h"
34

45
#ifndef NDEBUG
56
#define MOD_ASSERT(cond, msg, ret) if (!(cond)) { fprintf(stderr, "%s\n", msg); return ret; }
@@ -59,6 +60,7 @@ typedef struct _poll_t {
5960
/* Struct that holds data for each module */
6061
typedef struct {
6162
userhook hook; // module's user defined callbacks
63+
stack_t *recvs;
6264
const void *userdata; // module's user defined data
6365
enum module_states state; // module's state
6466
const char *name; // module's name

Lib/modules.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,13 @@ module_ret_code modules_ctx_loop_events(const char *ctx_name, const int max_even
8484
*(fd_msg_t **)&msg.fd_msg = &fd_msg;
8585
}
8686

87-
mod->hook.recv(&msg, mod->userdata);
87+
/* If module is using some different receive function, honor it. */
88+
recv_cb cb = stack_peek(mod->recvs);
89+
if (!cb) {
90+
/* Fallback to module default receive */
91+
cb = mod->hook.recv;
92+
}
93+
cb(&msg, mod->userdata);
8894

8995
/* Properly free pubsub msg */
9096
if (p->fd == mod->pubsub_fd[0]) {

Lib/public/module/module.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ _public_ module_ret_code module_stop(const self_t *self);
2323

2424
/* Module generic functions */
2525
_public_ module_ret_code module_become(const self_t *self, const recv_cb new_recv);
26+
_public_ module_ret_code module_unbecome(const self_t *self);
2627
_public_ module_ret_code module_log(const self_t *self, const char *fmt, ...);
2728
_public_ module_ret_code module_set_userdata(const self_t *self, const void *userdata);
2829
_public_ module_ret_code module_register_fd(const self_t *self, const int fd, const bool autoclose, const void *userptr);

Lib/public/module/module_easy.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static void _ctor2_ module_pre_start(void)
2828
#define m_resume() module_resume(_self)
2929
#define m_stop() module_stop(_self)
3030
#define m_become(x) module_become(_self, receive_##x)
31-
#define m_unbecome() module_become(_self, receive)
31+
#define m_unbecome() module_unbecome(_self)
3232
#define m_set_userdata(userdata) module_set_userdata(_self, userdata)
3333
#define m_register_fd(fd, autoclose, data) module_register_fd(_self, fd, autoclose, data)
3434
#define m_deregister_fd(fd) module_deregister_fd(_self, fd)

Lib/public/module/stack.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#pragma once
2+
3+
#include "module_cmn.h"
4+
5+
/** Stack interface **/
6+
7+
typedef enum {
8+
STACK_WRONG_PARAM = -4,
9+
STACK_MISSING,
10+
STACK_ERR,
11+
STACK_OMEM,
12+
STACK_OK
13+
} stack_ret_code;
14+
15+
/* Callback for stack_iterate */
16+
typedef stack_ret_code (*stack_cb)(void *, void *);
17+
18+
/* Incomplete struct declaration for stack */
19+
typedef struct _stack stack_t;
20+
21+
#ifdef __cplusplus
22+
extern "C"{
23+
#endif
24+
25+
_public_ stack_t *stack_new(void);
26+
_public_ stack_ret_code stack_iterate(const stack_t *s, const stack_cb fn, void *userptr);
27+
_public_ stack_ret_code stack_push(stack_t *s, void *data, bool autofree);
28+
_public_ void *stack_pop(stack_t *s);
29+
_public_ void *stack_peek(const stack_t *s);
30+
_public_ stack_ret_code stack_free(stack_t *s);
31+
_public_ int stack_length(const stack_t *s);
32+
33+
#ifdef __cplusplus
34+
}
35+
#endif

Lib/stack.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include "poll_priv.h"
2+
3+
typedef struct _elem {
4+
void *userptr;
5+
bool autofree;
6+
struct _elem *prev;
7+
} stack_elem;
8+
9+
struct _stack {
10+
int len;
11+
stack_elem *data;
12+
};
13+
14+
stack_t *stack_new(void) {
15+
stack_t *s = memhook._malloc(sizeof(stack_t));
16+
if (s) {
17+
s->len = 0;
18+
s->data = NULL;
19+
}
20+
return s;
21+
}
22+
23+
stack_ret_code stack_iterate(const stack_t *s, const stack_cb fn, void *userptr) {
24+
MOD_ASSERT(s, "NULL stack.", STACK_WRONG_PARAM);
25+
MOD_ASSERT(fn, "NULL cb.", STACK_WRONG_PARAM);
26+
MOD_ASSERT(stack_length(s) > 0, "Empty stack.", STACK_MISSING);
27+
28+
stack_ret_code status = STACK_OK;
29+
stack_elem *elem = s->data;
30+
while (elem && status == STACK_OK) {
31+
status = fn(userptr, elem->userptr);
32+
elem = elem->prev;
33+
}
34+
return status;
35+
}
36+
37+
stack_ret_code stack_push(stack_t *s, void *data, bool autofree) {
38+
MOD_ASSERT(s, "NULL stack.", STACK_WRONG_PARAM);
39+
MOD_ASSERT(data, "NULL data.", STACK_WRONG_PARAM);
40+
41+
stack_elem *elem = memhook._malloc(sizeof(stack_elem));
42+
if (elem) {
43+
s->len++;
44+
elem->userptr = data;
45+
elem->prev = s->data;
46+
elem->autofree = autofree;
47+
s->data = elem;
48+
return STACK_OK;
49+
}
50+
return STACK_OMEM;
51+
}
52+
53+
void *stack_pop(stack_t *s) {
54+
MOD_ASSERT(s, "NULL stack.", NULL);
55+
MOD_ASSERT(stack_length(s) > 0, "Empty stack.", NULL);
56+
57+
stack_elem *elem = s->data;
58+
s->data = s->data->prev;
59+
void *data = elem->userptr;
60+
memhook._free(elem);
61+
s->len--;
62+
return data;
63+
}
64+
65+
void *stack_peek(const stack_t *s) {
66+
MOD_ASSERT(s, "NULL stack.", NULL);
67+
MOD_ASSERT(stack_length(s) > 0, "Empty stack.", NULL);
68+
69+
return s->data->userptr; // return most recent element data
70+
}
71+
72+
stack_ret_code stack_free(stack_t *s) {
73+
MOD_ASSERT(s, "NULL stack.", STACK_WRONG_PARAM);
74+
75+
stack_elem *elem = NULL;
76+
while ((elem = s->data) && s->len > 0) {
77+
const bool autofree = elem->autofree;
78+
void *data = stack_pop(s);
79+
if (autofree) {
80+
memhook._free(data);
81+
}
82+
}
83+
free(s);
84+
return STACK_OK;
85+
}
86+
87+
int stack_length(const stack_t *s) {
88+
MOD_ASSERT(s, "NULL stack.", STACK_WRONG_PARAM);
89+
90+
return s->len;
91+
}

TODO.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 3.2.0
2-
- [ ] Actually implement a stack for module_become/unbecome
3-
- [ ] Expose stack through a stack.h public header
2+
- [x] Actually implement a stack for module_become/unbecome
3+
- [x] Expose stack through a stack.h public header
4+
- [x] Add test + doc for stack
45

56
## 4.0.0 (?)
67
- [ ] Prevent other modules from using a module's self_t (as received eg from a PubSub message)

0 commit comments

Comments
 (0)