Skip to content

Commit

Permalink
Self_t is now an incomplete structure declaration in module.h. This w…
Browse files Browse the repository at this point in the history
…ay we can properly have type checking and avoid using void pointers everywhere (too dangerous). It saves lots of cast too (thus leading to better performace).

Added a MODULE_PRE_START macro that defines a function per-module that will be called before initing any module.
Renamed back get_fd to init.
Now users can implement non-pollable modules, ie modules that are not bound to any fd/incoming events but only act as actor.
  • Loading branch information
FedeDP committed Mar 18, 2018
1 parent 1e471b6 commit 1a53f36
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 73 deletions.
61 changes: 33 additions & 28 deletions Lib/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,12 @@

#define GET_MOD(self) \
MOD_ASSERT(self, "NULL self handler.", MOD_NO_SELF); \
self_t *s = (self_t *)self; \
GET_CTX(s->ctx) \
CTX_GET_MOD(s->name, c)
GET_CTX(self->ctx) \
CTX_GET_MOD(self->name, c)

#define GET_MOD_IN_STATE(self, state) \
GET_MOD(self); \
if (!module_is(s, state)) { return MOD_WRONG_STATE; }
if (!module_is(self, state)) { return MOD_WRONG_STATE; }

#define CHILDREN_LOOP(f) \
child_t *tmp = m->children; \
Expand All @@ -44,10 +43,10 @@
}

/* Struct that holds self module informations, static to each module */
typedef struct {
struct _self {
const char *name; // module's name
const char *ctx; // module's ctx
} self_t;
};

typedef struct child {
const self_t *self; // module's name
Expand Down Expand Up @@ -135,7 +134,7 @@ static m_context *check_ctx(const char *ctx_name) {
return context;
}

int module_register(const char *name, const char *ctx_name, const void **self, userhook *hook) {
int module_register(const char *name, const char *ctx_name, const self_t **self, userhook *hook) {
MOD_ASSERT(name, "NULL module name.", MOD_ERR);
MOD_ASSERT(ctx_name, "NULL context name.", MOD_ERR);

Expand Down Expand Up @@ -170,7 +169,7 @@ int module_register(const char *name, const char *ctx_name, const void **self, u
return MOD_ERR;
}

int module_deregister(const void **self) {
int module_deregister(const self_t **self) {
self_t *tmp = (self_t *) *self;

GET_MOD(tmp);
Expand Down Expand Up @@ -209,7 +208,7 @@ static int add_children(module *mod, const void *self) {
return MOD_ERR;
}

int module_binds_to(const void *self, const char *parent) {
int module_binds_to(const self_t *self, const char *parent) {
self_t *tmp = (self_t *) self;
GET_CTX(tmp->ctx);

Expand Down Expand Up @@ -267,20 +266,20 @@ static int evaluate_module(void *data, void *m) {
if (module_is(&mod->self, IDLE)
&& mod->hook->evaluate()) {

int fd = mod->hook->get_fd();
int fd = mod->hook->init();
module_start(&mod->self, fd);
}
return MAP_OK;
}

int module_become(const void *self, recv_cb new_recv) {
int module_become(const self_t *self, recv_cb new_recv) {
GET_MOD_IN_STATE(self, RUNNING);

mod->hook->recv = new_recv;
return MOD_OK;
}

int module_log(const void *self, const char *fmt, ...) {
int module_log(const self_t *self, const char *fmt, ...) {
MOD_ASSERT(self, "Module not found.", MOD_NO_MOD);

va_list args;
Expand All @@ -291,14 +290,14 @@ int module_log(const void *self, const char *fmt, ...) {
return MOD_OK;
}

int module_set_userdata(const void *self, const void *userdata) {
int module_set_userdata(const self_t *self, const void *userdata) {
GET_MOD(self);

mod->userdata = userdata;
return MOD_OK;
}

int module_update_fd(const void *self, int new_fd, int close_old) {
int module_update_fd(const self_t *self, int new_fd, int close_old) {
GET_MOD_IN_STATE(self, RUNNING);

/* De-register this fd from epoll */
Expand Down Expand Up @@ -331,7 +330,7 @@ static int add_subscription(module *mod, const char *topic) {
return MOD_ERR;
}

int module_subscribe(const void *self, const char *topic) {
int module_subscribe(const self_t *self, const char *topic) {
GET_MOD(self);

return add_subscription(mod, topic);
Expand All @@ -355,7 +354,7 @@ static int tell_if(void *data, void *m) {
return MAP_OK;
}

int module_tell(const void *self, const char *message, const char *recipient) {
int module_tell(const self_t *self, const char *message, const char *recipient) {
self_t *s = (self_t *)self;
GET_CTX(s->ctx);
CTX_GET_MOD(recipient, c);
Expand All @@ -374,7 +373,7 @@ int module_tell(const void *self, const char *message, const char *recipient) {
return MOD_OK;
}

int module_publish(const void *self, const char *topic, const char *message) {
int module_publish(const self_t *self, const char *topic, const char *message) {
self_t *s = (self_t *)self;
GET_CTX(s->ctx);

Expand All @@ -393,60 +392,66 @@ int module_publish(const void *self, const char *topic, const char *message) {

/** Module state getter **/

int module_is(const void *self, const enum module_states st) {
int module_is(const self_t *self, const enum module_states st) {
GET_MOD(self);

return mod->state & st;
}

/** Module state setters **/

int module_start(const void *self, int fd) {
int module_start(const self_t *self, int fd) {
GET_MOD_IN_STATE(self, IDLE);

mod->fd = fd;
MODULE_DEBUG("Starting module %s.\n", ((self_t *)self)->name);
return module_resume(self);
}

int module_pause(const void *self) {
int module_pause(const self_t *self) {
GET_MOD_IN_STATE(self, RUNNING);

int ret = epoll_ctl(c->epollfd, EPOLL_CTL_DEL, mod->fd, NULL);
int ret = 0;
if (mod->fd != MODULE_DONT_POLL) {
epoll_ctl(c->epollfd, EPOLL_CTL_DEL, mod->fd, NULL);
}
if (!ret) {
mod->state = PAUSED;
return MOD_OK;
}
return MOD_ERR;
}

int module_resume(const void *self) {
int module_resume(const self_t *self) {
GET_MOD_IN_STATE(self, IDLE | PAUSED);

mod->ev.data.ptr = (void *)self;
mod->ev.events = EPOLLIN;
int ret = epoll_ctl(c->epollfd, EPOLL_CTL_ADD, mod->fd, &mod->ev);
int ret = 0;
if (mod->fd != MODULE_DONT_POLL) {
mod->ev.data.ptr = (void *)self;
mod->ev.events = EPOLLIN;
ret = epoll_ctl(c->epollfd, EPOLL_CTL_ADD, mod->fd, &mod->ev);
}
if (!ret) {
mod->state = RUNNING;
return MOD_OK;
}
return MOD_ERR;
}

int module_stop(const void *self) {
int module_stop(const self_t *self) {
GET_MOD_IN_STATE(self, RUNNING);

MODULE_DEBUG("Stopping module %s.\n", ((self_t *)self)->name);
mod->state = STOPPED;
if (close(mod->fd) == 0) { // implicitly calls EPOLL_CTL_DEL
if (mod->fd == MODULE_DONT_POLL || close(mod->fd) == 0) { // implicitly calls EPOLL_CTL_DEL
return MOD_OK;
}
return MOD_ERR;
}

static int start_children(module *m) {
CHILDREN_LOOP({
int fd = mod->hook->get_fd();
int fd = mod->hook->init();
module_start(&mod->self, fd);
});
return MOD_OK;
Expand Down
72 changes: 41 additions & 31 deletions Lib/module.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
#pragma once

#include <stdio.h>
#include <limits.h>

/* Convenience macros */

#define MOD_OK 0
#define MOD_ERR -1
#define MOD_NO_SELF -2
#define MOD_NO_MOD -3
#define MOD_NO_CTX -4
#define MOD_NO_PARENT -5
#define MOD_WRONG_STATE -6
#define MODULE_DONT_POLL INT_MIN

#define _public_ __attribute__ ((visibility("default")))

/*
* ctors order:
* 1) modules_pre_start() + modules_init();
Expand All @@ -31,22 +27,23 @@

/* Interface Macros */
#define MODULE_CTX(name, ctx) \
static int get_fd(void); \
static int init(void); \
static int check(void); \
static int evaluate(void); \
static void recv(msg_t *msg, const void *userdata); \
static void destroy(void); \
static const void *self = NULL; \
void _weak_ _ctor1_ ctx##_##name_pre_start(void); \
static void _ctor2_ init(void) { \
static const self_t *self = NULL; \
static void _ctor2_ constructor(void) { \
if (check()) { \
static userhook hook = { get_fd, evaluate, recv, destroy }; \
static userhook hook = { init, evaluate, recv, destroy }; \
module_register(name, ctx, &self, &hook); \
} \
} \
static void _dtor1_ deinit(void) { module_deregister(&self); }
static void _dtor1_ destructor(void) { module_deregister(&self); }

#define MODULE(name) MODULE_CTX(name, DEFAULT_CTX)

#define MODULE_PRE_START() static void _ctor1_ module_pre_start(void)

/* Defines for easy API (with no need bothering with both self and ctx) */
#define m_is(x) module_is(self, x)
Expand All @@ -69,8 +66,21 @@

/** Structs types **/

/* Incomplete structure declaration to self handler */
typedef struct _self self_t;

/* Modules states */
enum module_states { IDLE = 1, RUNNING = 2, PAUSED = 4, STOPPED = 8 };
enum module_states { IDLE = 0x1, RUNNING = 0x2, PAUSED = 0x4, STOPPED = 0x8 };

enum module_return_codes {
MOD_WRONG_STATE = -6,
MOD_NO_PARENT,
MOD_NO_CTX,
MOD_NO_MOD,
MOD_NO_SELF,
MOD_ERR,
MOD_OK
};

typedef struct {
const char *topic;
Expand All @@ -84,36 +94,36 @@ typedef struct {
} msg_t;

/* Callbacks typedefs */
typedef int(*get_fd_cb)(void);
typedef int(*init_cb)(void);
typedef int(*evaluate_cb)(void);
typedef void(*recv_cb)(msg_t *msg, const void *userdata);
typedef void(*destroy_cb)(void);

/* Struct that holds user defined callbacks */
typedef struct {
get_fd_cb get_fd; // module's get_fd function (should return a FD)
init_cb init; // module's init function (should return a FD)
evaluate_cb evaluate; // module's state changed function
recv_cb recv; // module's recv function
destroy_cb destroy; // module's destroy function
} userhook;

/* Module interface functions */
_public_ int module_register(const char *name, const char *ctx_name, const void **self, userhook *hook);
_public_ int module_deregister(const void **self);
_public_ int module_register(const char *name, const char *ctx_name, const self_t **self, userhook *hook);
_public_ int module_deregister(const self_t **self);
/* FIXME: do not export this for now as its support is not complete */
int module_binds_to(const void *self, const char *parent);
_public_ int module_is(const void *self, const enum module_states st);
_public_ int module_start(const void *self, int fd);
_public_ int module_pause(const void *self);
_public_ int module_resume(const void *self);
_public_ int module_stop(const void *self);
_public_ int module_become(const void *self, recv_cb new_recv);
_public_ int module_log(const void *self, const char *fmt, ...);
_public_ int module_set_userdata(const void *self, const void *userdata);
_public_ int module_update_fd(const void *self, int new_fd, int close_old);
_public_ int module_subscribe(const void *self, const char *topic);
_public_ int module_tell(const void *self, const char *message, const char *recipient);
_public_ int module_publish(const void *self, const char *topic, const char *message);
int module_binds_to(const self_t *self, const char *parent);
_public_ int module_is(const self_t *self, const enum module_states st);
_public_ int module_start(const self_t *self, int fd);
_public_ int module_pause(const self_t *self);
_public_ int module_resume(const self_t *self);
_public_ int module_stop(const self_t *self);
_public_ int module_become(const self_t *self, recv_cb new_recv);
_public_ int module_log(const self_t *self, const char *fmt, ...);
_public_ int module_set_userdata(const self_t *self, const void *userdata);
_public_ int module_update_fd(const self_t *self, int new_fd, int close_old);
_public_ int module_subscribe(const self_t *self, const char *topic);
_public_ int module_tell(const self_t *self, const char *message, const char *recipient);
_public_ int module_publish(const self_t *self, const char *topic, const char *message);

/* Modules interface functions */
_public_ void _ctor0_ _weak_ modules_pre_start(void);
Expand Down
15 changes: 14 additions & 1 deletion Samples/Easy/a.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@ MODULE("A");

static void recv_ready(msg_t *msg, const void *userdata);

/*
* This macro will create a function that is automatically
* called before registering the module. Use this to set some
* global state needed eg: in check() function
*/
MODULE_PRE_START() {
printf("A: Not yet inited!\n");
}

/*
* Initializes this module's state;
* returns a valid fd to be polled.
*/
static int get_fd(void) {
static int init(void) {
int fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK);

struct itimerspec timerValue = {{0}};
Expand Down Expand Up @@ -73,6 +82,10 @@ static void recv(msg_t *msg, const void *userdata) {
if (counter % 3 == 0) {
m_become(ready);
m_set_userdata(&counter);
/*
* Publish a message on "test" topic to let
* other module know we're changing state.
*/
m_publish("test", "changing recv");
}
}
Expand Down
12 changes: 11 additions & 1 deletion Samples/Easy/b.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@
*/
MODULE("B");

/*
* This macro will create a function that is automatically
* called before registering the module. Use this to set some
* global state needed eg: in check() function
*/
MODULE_PRE_START() {
printf("B: Not yet inited!\n");
}

/*
* Initializes this module's state;
* returns a valid fd to be polled.
*/
static int get_fd(void) {
static int init(void) {
/* This module is subscribed to "test" topic */
m_subscribe("test");

Expand Down Expand Up @@ -74,6 +83,7 @@ static void recv(msg_t *msg, const void *userdata) {
modules_quit();
} else {
m_log("Received message '%s' from %s on topic '%s'.\n", msg->message->message, msg->message->sender, msg->message->topic);
/* Answer back to sender with a message */
m_tell("Nice!", msg->message->sender);
}
}

0 comments on commit 1a53f36

Please sign in to comment.