Skip to content

Commit

Permalink
Added a stack implementation to be used for each module become/unbeco…
Browse files Browse the repository at this point in the history
…me functions, that are finally useful. Stack is public too.
  • Loading branch information
FedeDP committed Nov 24, 2018
1 parent 6a96810 commit ceb5160
Show file tree
Hide file tree
Showing 17 changed files with 357 additions and 20 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 3.3.2)

project(module VERSION 3.1.1 LANGUAGES C CXX)
project(module VERSION 3.2.0 LANGUAGES C CXX)

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
Expand Down
8 changes: 2 additions & 6 deletions Lib/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,10 @@ bool map_has_key(const map_t *m, const char *key) {
map_ret_code map_iterate(map_t *m, const map_cb fn, void *userptr) {
MOD_ASSERT(m, "NULL map.", MAP_WRONG_PARAM);
MOD_ASSERT(fn, "NULL callback.", MAP_WRONG_PARAM);

/* On empty hashmap, return immediately */
if (map_length(m) <= 0) {
return MAP_MISSING;
}
MOD_ASSERT(map_length(m) > 0, "Empty map.", MAP_MISSING);

/* Linear probing */
int status = MAP_OK;
map_ret_code status = MAP_OK;
for (int i = 0; i < m->table_size && status == MAP_OK; i++) {
if (m->data[i].in_use) {
void *data = m->data[i].data;
Expand Down
17 changes: 15 additions & 2 deletions Lib/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ module_ret_code module_register(const char *name, const char *ctx_name, const se
mod->state = IDLE;
mod->fds = NULL;
mod->subscriptions = map_new();
mod->recvs = stack_new();
*self = memhook._malloc(sizeof(self_t));
self_t *s = (self_t *)*self;
*((module **)&s->mod) = mod;
Expand Down Expand Up @@ -144,6 +145,7 @@ module_ret_code module_deregister(const self_t **self) {
destroy_ctx(tmp->ctx);
}
map_free(mod->subscriptions);
stack_free(mod->recvs);
memhook._free((self_t *)*self);
*self = NULL;
mod->self = NULL;
Expand Down Expand Up @@ -181,8 +183,19 @@ module_ret_code module_become(const self_t *self, const recv_cb new_recv) {
MOD_PARAM_ASSERT(new_recv);
GET_MOD_IN_STATE(self, RUNNING);

mod->hook.recv = new_recv;
return MOD_OK;
if (stack_push(mod->recvs, new_recv, false) == STACK_OK) {
return MOD_OK;
}
return MOD_ERR;
}

module_ret_code module_unbecome(const self_t *self) {
GET_MOD_IN_STATE(self, RUNNING);

if (stack_pop(mod->recvs) == STACK_OK) {
return MOD_OK;
}
return MOD_ERR;
}

module_ret_code module_log(const self_t *self, const char *fmt, ...) {
Expand Down
2 changes: 2 additions & 0 deletions Lib/module_priv.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include "map.h"
#include "stack.h"

#ifndef NDEBUG
#define MOD_ASSERT(cond, msg, ret) if (!(cond)) { fprintf(stderr, "%s\n", msg); return ret; }
Expand Down Expand Up @@ -59,6 +60,7 @@ typedef struct _poll_t {
/* Struct that holds data for each module */
typedef struct {
userhook hook; // module's user defined callbacks
stack_t *recvs;
const void *userdata; // module's user defined data
enum module_states state; // module's state
const char *name; // module's name
Expand Down
8 changes: 7 additions & 1 deletion Lib/modules.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,13 @@ module_ret_code modules_ctx_loop_events(const char *ctx_name, const int max_even
*(fd_msg_t **)&msg.fd_msg = &fd_msg;
}

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

/* Properly free pubsub msg */
if (p->fd == mod->pubsub_fd[0]) {
Expand Down
1 change: 1 addition & 0 deletions Lib/public/module/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ _public_ module_ret_code module_stop(const self_t *self);

/* Module generic functions */
_public_ module_ret_code module_become(const self_t *self, const recv_cb new_recv);
_public_ module_ret_code module_unbecome(const self_t *self);
_public_ module_ret_code module_log(const self_t *self, const char *fmt, ...);
_public_ module_ret_code module_set_userdata(const self_t *self, const void *userdata);
_public_ module_ret_code module_register_fd(const self_t *self, const int fd, const bool autoclose, const void *userptr);
Expand Down
2 changes: 1 addition & 1 deletion Lib/public/module/module_easy.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static void _ctor2_ module_pre_start(void)
#define m_resume() module_resume(_self)
#define m_stop() module_stop(_self)
#define m_become(x) module_become(_self, receive_##x)
#define m_unbecome() module_become(_self, receive)
#define m_unbecome() module_unbecome(_self)
#define m_set_userdata(userdata) module_set_userdata(_self, userdata)
#define m_register_fd(fd, autoclose, data) module_register_fd(_self, fd, autoclose, data)
#define m_deregister_fd(fd) module_deregister_fd(_self, fd)
Expand Down
35 changes: 35 additions & 0 deletions Lib/public/module/stack.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include "module_cmn.h"

/** Stack interface **/

typedef enum {
STACK_WRONG_PARAM = -4,
STACK_MISSING,
STACK_ERR,
STACK_OMEM,
STACK_OK
} stack_ret_code;

/* Callback for stack_iterate */
typedef stack_ret_code (*stack_cb)(void *, void *);

/* Incomplete struct declaration for stack */
typedef struct _stack stack_t;

#ifdef __cplusplus
extern "C"{
#endif

_public_ stack_t *stack_new(void);
_public_ stack_ret_code stack_iterate(const stack_t *s, const stack_cb fn, void *userptr);
_public_ stack_ret_code stack_push(stack_t *s, void *data, bool autofree);
_public_ void *stack_pop(stack_t *s);
_public_ void *stack_peek(const stack_t *s);
_public_ stack_ret_code stack_free(stack_t *s);
_public_ int stack_length(const stack_t *s);

#ifdef __cplusplus
}
#endif
91 changes: 91 additions & 0 deletions Lib/stack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include "poll_priv.h"

typedef struct _elem {
void *userptr;
bool autofree;
struct _elem *prev;
} stack_elem;

struct _stack {
int len;
stack_elem *data;
};

stack_t *stack_new(void) {
stack_t *s = memhook._malloc(sizeof(stack_t));
if (s) {
s->len = 0;
s->data = NULL;
}
return s;
}

stack_ret_code stack_iterate(const stack_t *s, const stack_cb fn, void *userptr) {
MOD_ASSERT(s, "NULL stack.", STACK_WRONG_PARAM);
MOD_ASSERT(fn, "NULL cb.", STACK_WRONG_PARAM);
MOD_ASSERT(stack_length(s) > 0, "Empty stack.", STACK_MISSING);

stack_ret_code status = STACK_OK;
stack_elem *elem = s->data;
while (elem && status == STACK_OK) {
status = fn(userptr, elem->userptr);
elem = elem->prev;
}
return status;
}

stack_ret_code stack_push(stack_t *s, void *data, bool autofree) {
MOD_ASSERT(s, "NULL stack.", STACK_WRONG_PARAM);
MOD_ASSERT(data, "NULL data.", STACK_WRONG_PARAM);

stack_elem *elem = memhook._malloc(sizeof(stack_elem));
if (elem) {
s->len++;
elem->userptr = data;
elem->prev = s->data;
elem->autofree = autofree;
s->data = elem;
return STACK_OK;
}
return STACK_OMEM;
}

void *stack_pop(stack_t *s) {
MOD_ASSERT(s, "NULL stack.", NULL);
MOD_ASSERT(stack_length(s) > 0, "Empty stack.", NULL);

stack_elem *elem = s->data;
s->data = s->data->prev;
void *data = elem->userptr;
memhook._free(elem);
s->len--;
return data;
}

void *stack_peek(const stack_t *s) {
MOD_ASSERT(s, "NULL stack.", NULL);
MOD_ASSERT(stack_length(s) > 0, "Empty stack.", NULL);

return s->data->userptr; // return most recent element data
}

stack_ret_code stack_free(stack_t *s) {
MOD_ASSERT(s, "NULL stack.", STACK_WRONG_PARAM);

stack_elem *elem = NULL;
while ((elem = s->data) && s->len > 0) {
const bool autofree = elem->autofree;
void *data = stack_pop(s);
if (autofree) {
memhook._free(data);
}
}
free(s);
return STACK_OK;
}

int stack_length(const stack_t *s) {
MOD_ASSERT(s, "NULL stack.", STACK_WRONG_PARAM);

return s->len;
}
5 changes: 3 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## 3.2.0
- [ ] Actually implement a stack for module_become/unbecome
- [ ] Expose stack through a stack.h public header
- [x] Actually implement a stack for module_become/unbecome
- [x] Expose stack through a stack.h public header
- [x] Add test + doc for stack

## 4.0.0 (?)
- [ ] Prevent other modules from using a module's self_t (as received eg from a PubSub message)
Expand Down
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
copyright = '2018, Federico Di Pierro'
author = 'Federico Di Pierro'

version = '3.1.1'
release = '3.1.1'
version = '3.2.0'
release = '3.2.0'

highlight_language = "c"

Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Welcome to libmodule's documentation!
src/module
src/modules
src/map
src/stack

Indices and tables
==================
Expand Down
8 changes: 4 additions & 4 deletions docs/src/map.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<br />

Libmodule Map API
==============
=================

Libmodule offers an easy to use hashmap implementation, provided by <module/map.h> header. |br|
It is used internally to store context's modules and modules' subscriptions/topics. |br|
Expand All @@ -22,7 +22,7 @@ Map structures
MAP_OK
} map_ret_code;
/* Callback for module_map_iterate */
/* Callback for map_iterate */
typedef map_ret_code (*map_cb)(void *, void *);
/* Incomplete struct declaration for hashmap */
Expand All @@ -41,7 +41,7 @@ Where not specified, these functions return a map_ret_code.

.. c:function:: map_iterate(m, fn, userptr)
Iterate an hashmap until MAP_OK is returned (or end of hashmap is reached). Returns MAP_MISSING if map is NULL.
Iterate an hashmap calling cb on each element until MAP_OK is returned (or end of hashmap is reached). Returns MAP_MISSING if map is NULL.

:param m: pointer to map_t
:param fn: callback to be called
Expand Down Expand Up @@ -105,4 +105,4 @@ Where not specified, these functions return a map_ret_code.

:param m: pointer to map_t
:type m: :c:type:`map_t *`
:returns: map length or a module_map_code if any error happens (map_t is null).
:returns: map length or a map_ret_code if any error happens (map_t is null).
93 changes: 93 additions & 0 deletions docs/src/stack.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
.. |br| raw:: html

<br />

Libmodule Stack API
===================

Libmodule offers an easy to use stack implementation, provided by <module/stack.h> header. |br|
It is used internally to store module's stack for become/unbecome methods. |br|

Stack structures
----------------

.. code::
typedef enum {
STACK_WRONG_PARAM = -4,
STACK_MISSING,
STACK_ERR,
STACK_OMEM,
STACK_OK
} stack_ret_code;
/* Callback for stack_iterate */
typedef stack_ret_code (*stack_cb)(void *, void *);
/* Incomplete struct declaration for stack */
typedef struct _stack stack_t;
Stack API
---------

Where not specified, these functions return a stack_ret_code.

.. c:function:: stack_new()
Create a new stack_t object.

:returns: pointer to newly allocated stack_t.

.. c:function:: stack_iterate(s, fn, userptr)
Iterate a stack calling cb on each element until STACK_OK is returned (or end of stack is reached). Returns STACK_MISSING if stack is NULL.

:param s: pointer to stack_t
:param fn: callback to be called
:param userptr: userdata to be passed to callback as first parameter
:type s: :c:type:`stack_t *`
:type fn: :c:type:`const stack_cb`
:type userptr: :c:type:`void *`

.. c:function:: stack_push(s, val, autofree)
Push a value on top of stack. Note that if autofree is true, data willbe automatically freed when calling stack_free() on the stack.

:param s: pointer to stack_t
:param val: value to be put inside stack
:param autofree: whether to autofree val on stack_free
:type s: :c:type:`stack_t *`
:type val: :c:type:`void *`
:type autofree: :c:type:`const bool`

.. c:function:: stack_pop(s)
Pop a value from top of stack, removing it from stack.

:param s: pointer to stack_t
:type s: :c:type:`stack_t *`
:returns: void pointer to value, on NULL on error.

.. c:function:: stack_peek(s)
Return top-of-stack element, without removing it.

:param s: pointer to stack_t
:type s: :c:type:`stack_t *`
:returns: void pointer to value, on NULL on error.

.. c:function:: stack_free(s)
Free a stack object.

:param s: pointer to stack_t
:type s: :c:type:`stack_t *`

.. c:function:: stack_length(s)
Get stack length.

:param s: pointer to stack_t
:type s: :c:type:`stack_t *`
:returns: stack length or a stack_ret_code if any error happens (stack_t is null).

0 comments on commit ceb5160

Please sign in to comment.