Skip to content

Commit

Permalink
Merge pull request #2 from FedeDP/kqueue_support
Browse files Browse the repository at this point in the history
Kqueue support
  • Loading branch information
FedeDP committed Apr 3, 2018
2 parents 74254b2 + 042686f commit 61963d9
Show file tree
Hide file tree
Showing 18 changed files with 240 additions and 120 deletions.
9 changes: 6 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
dist: trusty
sudo: false

notifications:
email:
recipients: nierro92@gmail.com
Expand All @@ -9,6 +6,12 @@ notifications:

language: c

os:
- linux
- osx

sudo: false

compiler:
- gcc
- clang
Expand Down
19 changes: 14 additions & 5 deletions 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 1.0.0 DESCRIPTION "Easily create modular C programs")
project(module VERSION 1.0.0 LANGUAGES C DESCRIPTION "Easily create modular C programs")

set(CMAKE_BUILD_TYPE Debug)
# set(CMAKE_BUILD_TYPE Release)
Expand All @@ -9,27 +9,36 @@ include(GNUInstallDirs)

# Find source files
file(GLOB SOURCES Lib/*.c)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(SOURCES ${SOURCES} Lib/poll_plugins/epoll_priv.c)
else()
set(SOURCES ${SOURCES} Lib/poll_plugins/kqueue_priv.c)
endif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")

message(STATUS "Building Libmodule ${PROJECT_VERSION} for ${CMAKE_SYSTEM_NAME}")

set(PUBLIC_H Lib/module.h Lib/modules.h)

# Include header files
include_directories(Lib)

add_library(${PROJECT_NAME} SHARED ${SOURCES})

set_target_properties(${PROJECT_NAME} PROPERTIES
set_target_properties(
${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION 1
PUBLIC_HEADER "${PUBLIC_H}"
)
)

# build with -DMAX_EVENTS=X to overwrite the default value of 512
# MAX_EVENTS are max number of fds for each context.
if (NOT MAX_EVENTS)
set(MAX_EVENTS 512)
endif (NOT MAX_EVENTS)
message(STATUS "MAX_EVENTS=${MAX_EVENTS}")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wl,--no-undefined -Wshadow -Wtype-limits -Wstrict-overflow -fno-strict-aliasing -Wformat -Wformat-security")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -D_GNU_SOURCE -fvisibility=hidden -DMAX_EVENTS=${MAX_EVENTS}")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wtype-limits -Wstrict-overflow -fno-strict-aliasing -Wformat -Wformat-security")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -D_GNU_SOURCE -fvisibility=hidden -DMAX_EVENTS=${MAX_EVENTS} -DMODULE_VERSION_MAJ=${PROJECT_VERSION_MAJOR} -DMODULE_VERSION_MIN=${PROJECT_VERSION_MINOR} -DMODULE_VERSION_PAT=${PROJECT_VERSION_PATCH}")

configure_file(Extra/libmodule.pc.in libmodule.pc @ONLY)

Expand Down
78 changes: 37 additions & 41 deletions Lib/module.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include <module.h>
#include <module_priv.h>
#include <module.h>
#include <poll_priv.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>

static module_ret_code init_ctx(const char *ctx_name, m_context **context);
Expand All @@ -14,7 +13,6 @@ static module_ret_code add_subscription(module *mod, const char *topic);
static int tell_if(void *data, void *m);
static pubsub_msg_t *create_pubsub_msg(const char *message, const char *sender, const char *topic);
static module_ret_code tell_pubsub_msg(pubsub_msg_t *m, module *mod, m_context *c);
static int manage_fds(module *mod, m_context *c, int type, int stop);
static module_ret_code start_children(module *m);
static module_ret_code stop_children(module *m);

Expand All @@ -25,9 +23,9 @@ static module_ret_code init_ctx(const char *ctx_name, m_context **context) {
MOD_ASSERT(*context, "Failed to malloc.", MOD_ERR);

**context = (m_context) {0};
(*context)->epollfd = epoll_create1(EPOLL_CLOEXEC);
MOD_ASSERT(((*context)->epollfd >= 0), "Failed to create epollfd.", MOD_ERR);

(*context)->fd = poll_create();
MOD_ASSERT(((*context)->fd >= 0), "Failed to create context fd.", MOD_ERR);

(*context)->logger = default_logger;

Expand All @@ -44,7 +42,7 @@ static module_ret_code init_ctx(const char *ctx_name, m_context **context) {
static void destroy_ctx(const char *ctx_name, m_context *context) {
MODULE_DEBUG("Destroying context '%s'.\n", ctx_name);
hashmap_free(context->modules);
close(context->epollfd);
poll_close(context->fd);
free(context);
hashmap_remove(ctx, (char *)ctx_name);
}
Expand Down Expand Up @@ -75,7 +73,7 @@ module_ret_code module_register(const char *name, const char *ctx_name, const se
MOD_ASSERT(mod, "Failed to malloc.", MOD_ERR);

*mod = (module) {0};
if (hashmap_put(context->modules, (char *)name, mod) == MAP_OK) {
if (hashmap_put(context->modules, (char *)name, mod) == MAP_OK) {
mod->hook = hook;
mod->state = IDLE;
mod->self.name = strdup(name);
Expand Down Expand Up @@ -121,12 +119,11 @@ static module_ret_code add_children(module *mod, const self_t *self) {
tmp = &(*tmp)->next;
}
*tmp = malloc(sizeof(child_t));
if (*tmp) {
(*tmp)->self = self;
(*tmp)->next = NULL;
return MOD_OK;
}
return MOD_ERR;
MOD_ASSERT(*tmp, "Failed to malloc.", MOD_ERR);

(*tmp)->self = self;
(*tmp)->next = NULL;
return MOD_OK;
}

module_ret_code module_binds_to(const self_t *self, const char *parent) {
Expand Down Expand Up @@ -192,19 +189,16 @@ module_ret_code module_add_fd(const self_t *self, int fd) {
MOD_ASSERT(tmp, "Failed to malloc.", MOD_ERR);

tmp->fd = fd;
tmp->ev.data.ptr = (void *)tmp;
tmp->ev.events = EPOLLIN;
poll_set_data(&tmp->ev, (void *)tmp);
tmp->prev = mod->fds;
tmp->self = (void *)self;
mod->fds = tmp;
c->num_fds++;

/* If a fd is added at runtime, start polling on it */
if (module_is(self, RUNNING)) {
if (!epoll_ctl(c->epollfd, EPOLL_CTL_ADD, tmp->fd, &tmp->ev)) {
return MOD_OK;
}
return MOD_ERR;
int ret = poll_set_new_evt(tmp, c, ADD);
return !ret ? MOD_OK : MOD_ERR;
}
return MOD_OK;
}
Expand All @@ -223,6 +217,7 @@ module_ret_code module_rm_fd(const self_t *self, int fd, int close_fd) {
if (close_fd) {
close(t->fd);
}
free(t->ev);
free(t);
c->num_fds--;
return MOD_OK;
Expand Down Expand Up @@ -332,16 +327,16 @@ int module_is(const self_t *self, const enum module_states st) {

/** Module state setters **/

static int manage_fds(module *mod, m_context *c, int type, int stop) {
static int manage_fds(module *mod, m_context *c, int flag, int stop) {
module_poll_t *tmp = mod->fds, *t = NULL;
int ret = 0;

while (tmp && !ret) {
if (stop) {
ret = close(tmp->fd);
ret = poll_set_new_evt(tmp, c, flag);
if (flag == RM && stop) {
ret += close(tmp->fd);
free(tmp->ev);
t = tmp;
} else {
ret = epoll_ctl(c->epollfd, type, tmp->fd, &tmp->ev);
}
tmp = tmp->prev;
free(t); // only used when called with stop: properly free module_poll_t
Expand All @@ -359,32 +354,33 @@ module_ret_code module_start(const self_t *self) {
module_ret_code module_pause(const self_t *self) {
GET_MOD_IN_STATE(self, RUNNING);

if (!manage_fds(mod, c, EPOLL_CTL_DEL, 0)) {
mod->state = PAUSED;
return MOD_OK;
}
return MOD_ERR;
int ret = manage_fds(mod, c, RM, 0);
MOD_ASSERT(!ret, "Failed to pause module.", MOD_ERR);

mod->state = PAUSED;
return MOD_OK;
}

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

if (!manage_fds(mod, c, EPOLL_CTL_ADD, 0)) {
mod->state = RUNNING;
return MOD_OK;
}
return MOD_ERR;
int ret = manage_fds(mod, c, ADD, 0);
MOD_ASSERT(!ret, "Failed to resume module.", MOD_ERR);

mod->state = RUNNING;
return MOD_OK;
}

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

MODULE_DEBUG("Stopping module %s.\n", self->name);
if (!manage_fds(mod, c, -1, 1)) { // implicitly calls EPOLL_CTL_DEL
mod->state = STOPPED;
return MOD_OK;
}
return MOD_ERR;

int ret = manage_fds(mod, c, RM, 1);
MOD_ASSERT(!ret, "Failed to stop module.", MOD_ERR);

mod->state = STOPPED;
return MOD_OK;
}

static module_ret_code start_children(module *m) {
Expand Down
8 changes: 8 additions & 0 deletions Lib/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@

/* Module interface functions */

#ifdef __cplusplus
extern "C"{
#endif

/* Module registration */
_public_ module_ret_code module_register(const char *name, const char *ctx_name, const self_t **self, userhook *hook);
_public_ module_ret_code module_deregister(const self_t **self);
Expand Down Expand Up @@ -68,3 +72,7 @@ _public_ module_ret_code module_update_fd(const self_t *self, int old_fd, int ne
_public_ module_ret_code module_subscribe(const self_t *self, const char *topic);
_public_ module_ret_code module_tell(const self_t *self, const char *recipient, const char *message);
_public_ module_ret_code module_publish(const self_t *self, const char *topic, const char *message);

#ifdef __cplusplus
}
#endif
49 changes: 24 additions & 25 deletions Lib/module_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,43 @@

#include <assert.h>
#include <hashmap.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <unistd.h>

#ifndef NDEBUG
#define MODULE_DEBUG printf("Libmodule: "); printf
#define MOD_ASSERT(cond, msg, ret) assert(cond)
#define MODULE_DEBUG printf("Libmodule: "); printf
#define MOD_ASSERT(cond, msg, ret) assert(cond)
#else
#define MODULE_DEBUG (void)
#define MOD_ASSERT(cond, msg, ret) if(!cond) { fprintf(stderr, "%s\n", msg); return ret; }
#define MODULE_DEBUG (void)
#define MOD_ASSERT(cond, msg, ret) if(!cond) { fprintf(stderr, "%s\n", msg); return ret; }
#endif


#define GET_CTX(name) \
m_context *c = NULL; \
hashmap_get(ctx, (char *)name, (void **)&c); \
MOD_ASSERT(c, "Context not found.", MOD_NO_CTX);
m_context *c = NULL; \
hashmap_get(ctx, (char *)name, (void **)&c); \
MOD_ASSERT(c, "Context not found.", MOD_NO_CTX);

#define CTX_GET_MOD(name, ctx) \
module *mod = NULL; \
hashmap_get(ctx->modules, (char *)name, (void **)&mod); \
MOD_ASSERT(mod, "Module not found.", MOD_NO_MOD);
module *mod = NULL; \
hashmap_get(ctx->modules, (char *)name, (void **)&mod); \
MOD_ASSERT(mod, "Module not found.", MOD_NO_MOD);

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

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

#define CHILDREN_LOOP(f) \
child_t *tmp = m->children; \
while (tmp) { \
GET_MOD(tmp->self); \
f; \
tmp = tmp->next; \
}
child_t *tmp = m->children; \
while (tmp) { \
GET_MOD(tmp->self); \
f; \
tmp = tmp->next; \
}

/* Struct that holds self module informations, static to each module */
struct _self {
Expand All @@ -49,7 +48,7 @@ struct _self {

typedef struct _poll_t {
int fd;
struct epoll_event ev; // fd's epoll event struct
void *ev;
self_t *self; // ptr needed to map a fd to a self_t in epoll
struct _poll_t *prev;
} module_poll_t;
Expand All @@ -72,7 +71,7 @@ typedef struct {

typedef struct {
int quit;
int epollfd;
int fd;
int num_fds; // number of fds in this context
log_cb logger;
map_t modules;
Expand Down
24 changes: 11 additions & 13 deletions Lib/modules.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#include <modules.h>
#include <module_priv.h>
#include <poll_priv.h>

static _ctor1_ void modules_init(void);
static _dtor0_ void modules_destroy(void);
static void evaluate_new_state(m_context *context);

static void modules_init(void) {
MODULE_DEBUG("Initializing library.\n");
MODULE_DEBUG("Initializing libmodule %d.%d.%d.\n", MODULE_VERSION_MAJ, MODULE_VERSION_MIN, MODULE_VERSION_PAT);
ctx = hashmap_new();
}

static void modules_destroy(void) {
MODULE_DEBUG("Destroying library.\n");
MODULE_DEBUG("Destroying libmodule.\n");
hashmap_free(ctx);
}

Expand All @@ -26,19 +26,17 @@ module_ret_code modules_ctx_set_logger(const char *ctx_name, log_cb logger) {
module_ret_code modules_ctx_loop(const char *ctx_name) {
GET_CTX(ctx_name);

struct epoll_event pevents[MAX_EVENTS] = {{ 0 }};
while (!c->quit) {
int nfds = epoll_wait(c->epollfd, pevents, c->num_fds, -1);
MOD_ASSERT(nfds > 0, "Epoll_wait error.", MOD_ERR);
int nfds = poll_wait(c->fd, c->num_fds);

MOD_ASSERT(nfds > 0, "Context loop error.", MOD_ERR);
for (int i = 0; i < nfds; i++) {
if (pevents[i].events & EPOLLIN) {
module_poll_t *p = (module_poll_t *)pevents[i].data.ptr;
module_poll_t *p = poll_recv(i);
MOD_ASSERT(p, "Context loop error.", MOD_ERR);
CTX_GET_MOD(p->self->name, c);

CTX_GET_MOD(p->self->name, c);

const msg_t msg = { p->fd, NULL };
mod->hook->recv(&msg, mod->userdata);
}
const msg_t msg = { p->fd, NULL };
mod->hook->recv(&msg, mod->userdata);
}
evaluate_new_state(c);
}
Expand Down

0 comments on commit 61963d9

Please sign in to comment.