Skip to content

Commit 4e7dcb2

Browse files
committed
* Dropped _GNU_SOURCE define.
* Added a map_has_key function. * Avoid changing needs_free value in hashmap_rehash function * Added support for libkqueue on non linux systems: this way library should be buildable in windows and solaris too.
1 parent 1961330 commit 4e7dcb2

File tree

14 files changed

+127
-95
lines changed

14 files changed

+127
-95
lines changed

CMakeLists.txt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,22 @@ if(BUILD_TESTS)
1515
if (CMOCKA_FOUND)
1616
enable_testing()
1717
add_subdirectory(tests)
18-
message(STATUS "Building tests.")
18+
message(STATUS "Tests building enabled.")
1919
else()
2020
message(WARNING "Missing cmocka.")
2121
endif()
2222
endif()
2323

2424
if(BUILD_SAMPLES)
2525
add_subdirectory(Samples)
26-
message(STATUS "Building examples.")
26+
message(STATUS "Examples building enabled.")
2727
endif()
2828

2929
if(BUILD_DOCS)
3030
find_package(Sphinx)
3131
if(SPHINX_FOUND)
3232
add_subdirectory(docs)
33-
message(STATUS "Building docs.")
33+
message(STATUS "Docs building enabled.")
3434
else()
3535
message(WARNING "Missing sphinx.")
3636
endif()
@@ -44,6 +44,7 @@ file(GLOB SOURCES Lib/*.c)
4444
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
4545
set(SOURCES ${SOURCES} Lib/poll_plugins/epoll_priv.c)
4646
else()
47+
find_package(Kqueue REQUIRED)
4748
set(SOURCES ${SOURCES} Lib/poll_plugins/kqueue_priv.c)
4849
endif()
4950

@@ -65,9 +66,13 @@ set_target_properties(
6566
)
6667

6768
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wtype-limits -Wstrict-overflow -fno-strict-aliasing -Wformat -Wformat-security")
68-
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -D_GNU_SOURCE -fvisibility=hidden")
69+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -fvisibility=hidden")
6970

70-
target_include_directories(${PROJECT_NAME} PRIVATE Lib/ Lib/public/module/)
71+
# KQUEUE_INCLUDE_DIRS will be empty where native epoll/kqueue are supported
72+
target_include_directories(${PROJECT_NAME} PRIVATE Lib/ Lib/public/module/ ${KQUEUE_INCLUDE_DIRS})
73+
74+
# KQUEUE_LIBRARIES will be empty where native epoll/kqueue are supported
75+
target_link_libraries(${PROJECT_NAME} ${KQUEUE_LIBRARIES})
7176

7277
install(TARGETS ${PROJECT_NAME}
7378
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}

Lib/map.c

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
typedef struct _hashmap_element {
1010
const char *key;
1111
bool in_use;
12-
bool need_free;
12+
bool needs_free;
1313
void *data;
1414
} map_elem;
1515

@@ -27,6 +27,7 @@ static unsigned long crc32(const unsigned char *s, unsigned int len);
2727
static unsigned int hashmap_hash_int(const map_t *m, const char *keystring);
2828
static int hashmap_hash(map_t *m, const char* key);
2929
static map_ret_code hashmap_rehash(map_t *m);
30+
static map_ret_code hashmap_put(map_t *m, const char *key, void *value, const bool needs_free);
3031

3132
static unsigned long crc32_tab[] = {
3233
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
@@ -177,11 +178,10 @@ static map_ret_code hashmap_rehash(map_t *m) {
177178
m->size = 0;
178179

179180
/* Rehash the elements */
180-
int status = MAP_OK;
181+
map_ret_code status = MAP_OK;
181182
for (int i = 0; i < old_size && status == MAP_OK; i++) {
182183
if (curr[i].in_use) {
183-
/* Internal hashmap_put to avoid re-mallocing already malloc'd keys */
184-
status = map_put(m, curr[i].key, curr[i].data, false);
184+
status = hashmap_put(m, curr[i].key, curr[i].data, curr[i].needs_free);
185185
}
186186
}
187187
memhook._free(curr);
@@ -196,6 +196,11 @@ map_ret_code map_put(map_t *m, const char *key, void *value, const bool dupkey)
196196
MOD_ASSERT(key, "NULL key.", MAP_ERR);
197197
MOD_ASSERT(value, "NULL value.", MAP_ERR);
198198

199+
/* Find a place to put our value */
200+
return hashmap_put(m, dupkey ? mem_strdup(key) : key, value, dupkey);
201+
}
202+
203+
static map_ret_code hashmap_put(map_t *m, const char *key, void *value, const bool needs_free) {
199204
/* Find a place to put our value */
200205
int index = hashmap_hash(m, key);
201206
while (index == MAP_FULL) {
@@ -207,34 +212,41 @@ map_ret_code map_put(map_t *m, const char *key, void *value, const bool dupkey)
207212

208213
/* Set the data */
209214
m->data[index].data = value;
210-
m->data[index].key = dupkey ? mem_strdup(key) : key;
215+
m->data[index].key = key;
211216
m->data[index].in_use = true;
212-
m->data[index].need_free = dupkey;
217+
m->data[index].needs_free = needs_free;
213218
m->size++;
214219
return MAP_OK;
215220
}
216221

217222
/*
218223
* Get your pointer out of the hashmap with a key
219224
*/
220-
map_ret_code map_get(const map_t *m, const char *key, void **arg) {
221-
MOD_ASSERT(m, "NULL map.", MAP_ERR);
222-
MOD_ASSERT(key, "NULL key.", MAP_ERR);
225+
void *map_get(const map_t *m, const char *key) {
226+
if (!m) {
227+
fprintf(stderr, "NULL map.\n");
228+
return NULL;
229+
}
230+
if (!key) {
231+
fprintf(stderr, "NULL key.\n");
232+
return NULL;
233+
}
223234

224235
/* Find data location */
225236
int curr = hashmap_hash_int(m, key);
226237

227238
/* Linear probing, if necessary */
228239
for (int i = 0; i< MAX_CHAIN_LENGTH; i++) {
229240
if (m->data[curr].in_use && !strcmp(m->data[curr].key, key)) {
230-
*arg = (m->data[curr].data);
231-
return MAP_OK;
241+
return m->data[curr].data;
232242
}
233243
curr = (curr + 1) % m->table_size;
234244
}
235-
236-
*arg = NULL;
237-
return MAP_MISSING;
245+
return NULL;
246+
}
247+
248+
bool map_has_key(const map_t *m, const char *key) {
249+
return map_get(m, key) != NULL;
238250
}
239251

240252
/*
@@ -278,11 +290,11 @@ map_ret_code map_remove(map_t *m, const char *key) {
278290
/* Blank out the fields */
279291
m->data[curr].in_use = false;
280292
m->data[curr].data = NULL;
281-
if (m->data[curr].need_free) {
293+
if (m->data[curr].needs_free) {
282294
memhook._free((void *)m->data[curr].key);
283295
}
284296
m->data[curr].key = NULL;
285-
m->data[curr].need_free = false;
297+
m->data[curr].needs_free = false;
286298

287299
/* Reduce the size */
288300
m->size--;
@@ -300,7 +312,7 @@ map_ret_code map_free(map_t *m) {
300312
MOD_ASSERT(m, "NULL map.", MAP_ERR);
301313

302314
for (int i = 0; i < m->table_size; i++) {
303-
if (m->data[i].need_free) {
315+
if (m->data[i].needs_free) {
304316
memhook._free((void *)m->data[i].key);
305317
}
306318
}

Lib/module.c

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
#include "module.h"
22
#include "poll_priv.h"
3-
#include <string.h>
4-
#include <stdarg.h>
53

64
static module_ret_code init_ctx(const char *ctx_name, m_context **context);
75
static void destroy_ctx(const char *ctx_name, m_context *context);
86
static m_context *check_ctx(const char *ctx_name);
7+
static int _pipe(module *mod);
98
static module_ret_code init_pubsub_fd(module *mod);
109
static void default_logger(const self_t *self, const char *fmt, va_list args, const void *userdata);
1110
static int tell_if(void *data, void *m);
@@ -51,16 +50,30 @@ static void destroy_ctx(const char *ctx_name, m_context *context) {
5150
}
5251

5352
static m_context *check_ctx(const char *ctx_name) {
54-
m_context *context = NULL;
55-
map_get(ctx, ctx_name, (void **)&context); \
53+
m_context *context = map_get(ctx, ctx_name);
5654
if (!context) {
5755
init_ctx(ctx_name, &context);
5856
}
5957
return context;
6058
}
6159

60+
static int _pipe(module *mod) {
61+
int ret = pipe(mod->pubsub_fd);
62+
if (ret == 0) {
63+
for (int i = 0; i < 2; i++) {
64+
int flags = fcntl(mod->pubsub_fd[i], F_GETFL, 0);
65+
if (flags == -1) {
66+
flags = 0;
67+
}
68+
fcntl(mod->pubsub_fd[i], F_SETFL, flags | O_NONBLOCK);
69+
fcntl(mod->pubsub_fd[i], F_SETFD, FD_CLOEXEC);
70+
}
71+
}
72+
return ret;
73+
}
74+
6275
static module_ret_code init_pubsub_fd(module *mod) {
63-
if (_pipe(mod->pubsub_fd) == 0) {
76+
if (_pipe(mod) == 0) {
6477
if (module_register_fd(&mod->self, mod->pubsub_fd[0], true, NULL) == MOD_OK) {
6578
return MOD_OK;
6679
}
@@ -82,8 +95,7 @@ module_ret_code module_register(const char *name, const char *ctx_name, const se
8295
m_context *context = check_ctx(ctx_name);
8396
MOD_ASSERT(context, "Failed to create context.", MOD_ERR);
8497

85-
module *mod = NULL;
86-
map_get(context->modules, name, (void **)&mod);
98+
module *mod = map_get(context->modules, name);
8799
MOD_ASSERT(!mod, "Module with same name already registered in context.", MOD_ERR);
88100

89101
MODULE_DEBUG("Registering module '%s'.\n", name);
@@ -277,9 +289,8 @@ char *mem_strdup(const char *s) {
277289
module_ret_code module_register_topic(const self_t *self, const char *topic) {
278290
MOD_ASSERT(topic, "NULL topic.", MOD_ERR);
279291
GET_MOD(self);
280-
void *tmp = NULL;
281292

282-
if (map_get(c->topics, topic, (void **)&tmp) == MAP_MISSING) {
293+
if (!map_has_key(c->topics, topic)) {
283294
if (map_put(c->topics, topic, mod, true) == MAP_OK) {
284295
tell_system_pubsub_msg(c, TOPIC_REGISTERED, topic);
285296
return MOD_OK;
@@ -291,10 +302,10 @@ module_ret_code module_register_topic(const self_t *self, const char *topic) {
291302
module_ret_code module_deregister_topic(const self_t *self, const char *topic) {
292303
MOD_ASSERT(topic, "NULL topic.", MOD_ERR);
293304
GET_MOD(self);
294-
void *tmp = NULL;
305+
void *tmp = map_get(c->topics, topic); // NULL if key is not present
295306

296307
/* Only same mod which registered topic can deregister it */
297-
if (map_get(c->topics, topic, (void **)&tmp) == MAP_OK && tmp == mod) {
308+
if (tmp == mod) {
298309
if (map_remove(c->topics, topic) == MAP_OK) {
299310
tell_system_pubsub_msg(c, TOPIC_DEREGISTERED, topic);
300311
return MOD_OK;
@@ -306,11 +317,9 @@ module_ret_code module_deregister_topic(const self_t *self, const char *topic) {
306317
module_ret_code module_subscribe(const self_t *self, const char *topic) {
307318
MOD_ASSERT(topic, "NULL topic.", MOD_ERR);
308319
GET_MOD(self);
309-
void *tmp = NULL;
310320

311321
/* If topic exists and we are not already subscribed */
312-
if (map_get(c->topics, topic, (void **)&tmp) == MAP_OK &&
313-
map_get(mod->subscriptions, topic, (void **)&tmp) == MAP_MISSING) {
322+
if (map_has_key(c->topics, topic) && !map_has_key(mod->subscriptions, topic)) {
314323
/* Store pointer to mod as value, even if it will be unused; this should be a hashset */
315324
if (map_put(mod->subscriptions, topic, mod, true) == MAP_OK) {
316325
return MOD_OK;
@@ -322,10 +331,8 @@ module_ret_code module_subscribe(const self_t *self, const char *topic) {
322331
module_ret_code module_unsubscribe(const self_t *self, const char *topic) {
323332
MOD_ASSERT(topic, "NULL topic.", MOD_ERR);
324333
GET_MOD(self);
325-
void *tmp = NULL;
326334

327-
if (map_get(c->topics, topic, (void **)&tmp) == MAP_OK &&
328-
map_remove(mod->subscriptions, topic) == MAP_OK) {
335+
if (map_remove(mod->subscriptions, topic) == MAP_OK) {
329336
return MOD_OK;
330337
}
331338
return MOD_ERR;
@@ -358,15 +365,14 @@ int flush_pubsub_msg(void *data, void *m) {
358365
static int tell_if(void *data, void *m) {
359366
module *mod = (module *)m;
360367
const pubsub_msg_t *msg = (pubsub_msg_t *)data;
361-
void *tmp = NULL;
362368

363369
/*
364370
* Only if mod is actually running or paused and
365371
* it is a SYSTEM message or
366372
* topic is null or this module is subscribed to topic
367373
*/
368374
if (module_is(&mod->self, RUNNING | PAUSED) && (msg->type != USER || !msg->topic ||
369-
map_get(mod->subscriptions, msg->topic, (void **)&tmp) == MAP_OK)) {
375+
map_has_key(mod->subscriptions, msg->topic))) {
370376

371377
MODULE_DEBUG("Telling a message to %s.\n", mod->self.name);
372378

@@ -433,7 +439,7 @@ static module_ret_code publish_msg(const self_t *self, const char *topic,
433439
* Only module that registered a topic can publish on the topic.
434440
* Moreover, a publish can only be made on existent topic.
435441
*/
436-
if (!topic || (map_get(c->topics, topic, (void **)&tmp) == MAP_OK && tmp == mod)) {
442+
if (!topic || ((tmp = map_get(c->topics, topic)) && tmp == mod)) {
437443
pubsub_msg_t m = { .topic = topic, .message = message, .sender = self, .type = USER, .size = size };
438444
return tell_pubsub_msg(&m, NULL, c);
439445
}

Lib/module_priv.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
#include <assert.h>
21
#include <stdlib.h>
3-
#include <unistd.h>
42
#include "map.h"
53

64
#define MOD_ASSERT(cond, msg, ret) if(!cond) { fprintf(stderr, "%s\n", msg); return ret; }
@@ -13,13 +11,11 @@
1311

1412
#define GET_CTX(name) \
1513
MOD_ASSERT(name, "NULL ctx.", MOD_ERR); \
16-
m_context *c = NULL; \
17-
map_get(ctx, (char *)name, (void **)&c); \
14+
m_context *c = map_get(ctx, (char *)name); \
1815
MOD_ASSERT(c, "Context not found.", MOD_NO_CTX);
1916

2017
#define CTX_GET_MOD(name, ctx) \
21-
module *mod = NULL; \
22-
map_get(ctx->modules, (char *)name, (void **)&mod); \
18+
module *mod = map_get(ctx->modules, (char *)name); \
2319
MOD_ASSERT(mod, "Module not found.", MOD_NO_MOD);
2420

2521
#define GET_MOD(self) \

Lib/modules.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "modules.h"
22
#include "poll_priv.h"
3-
#include <string.h>
43

54
static _ctor1_ void modules_init(void);
65
static _dtor0_ void modules_destroy(void);

Lib/poll_plugins/epoll_priv.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,3 @@ int poll_close(int fd, void **pevents, int *max_events) {
5050
poll_destroy_pevents(pevents, max_events);
5151
return close(fd);
5252
}
53-
54-
int _pipe(int fd[2]) {
55-
return pipe2(fd, O_NONBLOCK | O_CLOEXEC);
56-
}

Lib/poll_plugins/kqueue_priv.c

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,8 @@
44
#include <sys/time.h>
55

66
int poll_create(void) {
7-
int fd;
8-
#ifdef __APPLE__
9-
fd = kqueue();
7+
int fd = kqueue();
108
fcntl(fd, F_SETFD, FD_CLOEXEC);
11-
#else
12-
fd = kqueue1(O_CLOEXEC);
13-
#endif
149
return fd;
1510
}
1611

@@ -25,11 +20,9 @@ int poll_set_new_evt(module_poll_t *tmp, m_context *c, enum op_type flag) {
2520
struct kevent *_ev = (struct kevent *)tmp->ev;
2621
EV_SET(_ev, tmp->fd, EVFILT_READ, f, 0, 0, (void *)tmp);
2722
int ret = kevent(c->fd, _ev, 1, NULL, 0, NULL);
28-
/* Workaround for STDIN_FILENO: it returns EINVAL on add, and ENOENT on remove but it is actually pollable */
29-
if (ret == -1 && tmp->fd == STDIN_FILENO) {
30-
if ((f == EV_ADD && errno == EINVAL) || (f == EV_DELETE && errno == ENOENT)) {
31-
ret = 0;
32-
}
23+
/* Workaround for STDIN_FILENO: it is actually pollable */
24+
if (tmp->fd == STDIN_FILENO) {
25+
ret = 0;
3326
}
3427
return ret;
3528
}
@@ -63,18 +56,3 @@ int poll_close(int fd, void **pevents, int *max_events) {
6356
poll_destroy_pevents(pevents, max_events);
6457
return close(fd);
6558
}
66-
67-
int _pipe(int fd[2]) {
68-
int ret = pipe(fd);
69-
if (ret == 0) {
70-
for (int i = 0; i < 2; i++) {
71-
int flags = fcntl(fd[i], F_GETFL, 0);
72-
if (flags == -1) {
73-
flags = 0;
74-
}
75-
fcntl(fd[i], F_SETFL, flags | O_NONBLOCK);
76-
fcntl(fd[i], F_SETFD, FD_CLOEXEC);
77-
}
78-
}
79-
return ret;
80-
}

0 commit comments

Comments
 (0)