Skip to content

Commit 82525bf

Browse files
committed
Initial work on new documentation.
Return -EPERM when m_map_put()ing to update a value in a map without M_MAP_ALLOW_UPDATE flag.
1 parent bbab4ac commit 82525bf

File tree

13 files changed

+179
-255
lines changed

13 files changed

+179
-255
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,4 @@ docs/_build
6464
.idea/
6565
cmake-build-debug/
6666
cmake-build-release/
67+
venv/

Lib/priv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ typedef struct {
126126
const void *userptr;
127127
} ev_src_t;
128128

129-
/* Struct that holds pubsub messaging, private. It keeps reference count */
129+
/* Struct that holds pubsub messaging, private */
130130
typedef struct {
131131
m_evt_ps_t msg;
132132
m_ps_flags flags;

Lib/public/module/cmn.h.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ typedef enum {
6262
M_SRC_TYPE_PATH, // Path Source
6363
M_SRC_TYPE_PID, // PID Source
6464
M_SRC_TYPE_TASK, // Task source -> M_SRC_ONESHOT flag is forced
65-
M_SRC_TYPE_THRESH, // Threshold source -> M_SRC_ONESHOT flag is forced
65+
M_SRC_TYPE_THRESH,// Threshold source -> M_SRC_ONESHOT flag is forced
6666
M_SRC_TYPE_END // End of supported sources
6767
} m_src_types;
6868

Lib/structs/map.c

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -178,25 +178,23 @@ static int hashmap_put(m_map_t *m, const char *key, void *value) {
178178
}
179179
}
180180

181-
bool insert = false;
182-
if (!entry->key) {
181+
if (entry->key) {
182+
if (m->flags & M_MAP_VAL_ALLOW_UPDATE) {
183+
if (m->dtor && entry->data != value) {
184+
/* Destroy old value if needed */
185+
m->dtor(entry->data);
186+
}
187+
} else {
188+
/* No update allowed */
189+
return -EPERM;
190+
}
191+
} else {
183192
entry->key = key;
184193
m->length++;
185-
insert = true;
186-
}
187-
188-
if (m->flags & M_MAP_VAL_ALLOW_UPDATE) {
189-
if (m->dtor && entry->data != value) {
190-
/* Destroy old value if needed */
191-
m->dtor(entry->data);
192-
}
193-
insert = true;
194-
}
195-
196-
if (insert) {
197-
entry->data = value;
198-
m->last_insert = entry;
199194
}
195+
196+
entry->data = value;
197+
m->last_insert = entry;
200198
return 0;
201199
}
202200

docs/index.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ Welcome to libmodule's documentation!
1111
:caption: Contents:
1212

1313
src/concepts
14-
src/data_structures
1514
src/callbacks
1615
src/lifecycle
17-
src/memory
16+
src/easy
1817
src/pubsub
1918
src/module
2019
src/modules

docs/src/callbacks.rst

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,59 @@
33
<br />
44

55
Callbacks
6-
================
6+
=========
77

8-
Every module needs 5 functions that must be defined by developer. |br|
9-
If using :ref:`module_easy`, they are automatically declared by MODULE macro. |br|
10-
Moreover, a module_pre_start function is declared too, but it is not needed by libmodule interface, ie: it can be left undefined. Your compiler may warn you about that though. |br|
11-
When using :ref:`module_complex` API, libmodule only mandates init() and receive() callbacks. A NULL check() and evaluate() functions mean to avoid checking and evaluating and thus starting module right away.
8+
Every module requires following functions to be defined by developers. |br|
9+
If using :ref:`easy` API, they are automatically declared by M_MOD() macro. |br|
10+
Moreover, a m_mod_pre_start function is declared too, but it is not needed by libmodule interface, ie: it can be left undefined. Your compiler may warn you about that though. |br|
11+
Note that libmodule only mandates m_evt_cb() callback. |br|
12+
Leaving other callbacks as NULL means starting module right away with no further checks. |br|
1213

1314
.. code::
1415
15-
static void module_pre_start(void);
16-
static bool init(void);
17-
static bool check(void);
18-
static bool evaluate(void);
19-
static void receive(const msg_t *const msg, const void *userdata);
20-
static void destroy(void);
16+
void m_mod_pre_start(void);
17+
bool m_start_cb(m_mod_t *mod);
18+
bool m_eval_cb(m_mod_t *mod);
19+
void m_evt_cb(m_mod_t *mod, const m_evt_t *const evt);
20+
void m_stop_cb(m_mod_t *mod);
2121
22-
.. c:function:: module_pre_start(void)
22+
.. c:function:: m_mod_pre_start(void)
2323
2424
This function will be called before any module is registered. |br|
25-
It is the per-module version of :ref:`modules_pre_start <modules_pre_start>` function.
25+
It is the per-module version of :ref:`m_ctx_pre_start <m_ctx_pre_start>` function.
2626

27-
.. c:function:: init(void)
27+
.. c:function:: m_start_cb(mod)
2828
29-
Initializes module state; useful to register any fd to be polled or to register any topic. |br|
30-
Note that init() is called each time module is started. |br|
31-
If init callback returns false, module is automatically stopped as its initialization failed.
29+
Initializes module state; useful to register any event source. |br|
30+
It is called whenever module is started. |br|
31+
If m_mod_on_start callback returns false, module is automatically stopped as its initialization failed.
3232

33-
.. c:function:: check(void)
33+
:param: :c:type:`m_mod_t *` mod: pointer to module.
3434

35-
Startup filter to check whether this module should be actually created and managed by libmodule. |br|
36-
37-
:returns: true if the module should be registered, false otherwise.
35+
:returns: true if the module should be started, false otherwise.
3836

39-
.. c:function:: evaluate(void)
37+
.. c:function:: m_eval_cb(mod)
4038
41-
Similar to check() function but at runtime: this function is called for each IDLE module after evey state machine update
42-
and it should check whether a module is now ready to be start (ie: init should be called on this module and its state should be set to RUNNING). |br|
43-
Use this to check intra-modules dependencies or any other env variable.
44-
45-
:returns: true if module is now ready to be started, else false.
46-
47-
.. c:function:: receive(msg, userdata)
39+
This function is called for each IDLE module after evey state machine update, |br|
40+
and it should check whether a module is now ready to be started. |br|
41+
42+
:param: :c:type:`m_mod_t *` mod: pointer to module.
4843

49-
Poll callback, called when any event is ready on module's fd or when a PubSub message is received by a module. |br|
50-
Use msg->is_pubsub to decide which internal message should be read (ie: ps_msg_t or fd_msg_t).
44+
:returns: true if module is now ready to be started, false otherwise.
5145

52-
:param: :c:type:`const msg_t * const` msg: pointer to msg_t struct.
53-
:param: :c:type:`const void *` userdata: pointer to userdata as set by m_set_userdata.
46+
.. c:function:: m_evt_cb(mod, evt)
47+
48+
Poll callback, called when any event is ready to be received by a module. |br|
49+
Use evt->type to establish which event source triggered the event. |br|
50+
Note that evt is memory-ref'd. Thus, if you want to keep a message alive, you need to m_mem_ref() it. |br|
51+
Remember to unref it when done or you will cause a leak. |br|
52+
53+
:param: :c:type:`m_mod_t *` mod: pointer to module.
54+
:param: :c:type:`const m_evt_t * const` evt: pointer to event.
55+
56+
.. c:function:: m_stop_cb(mod)
5457
55-
.. c:function:: destroy(void)
58+
Called whenever module gets stopped, either by deregistration or m_mod_stop(). |br|
59+
Useful to cleanup module state, eg: freeing some data or closing fds registered without M_SRC_FD_AUTOCLOSE flag. |br|
5660

57-
Destroys module, called automatically at module deregistration. Please note that module's fds set as autoclose will be closed.
61+
:param: :c:type:`m_mod_t *` mod: pointer to module.

docs/src/concepts.rst

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,41 +8,28 @@ Concepts
88
Module
99
------
1010

11-
A module is core entity of libmodule: it is a single and indipendent logical unit that reacts to certain events, both pubsub and socket ones. |br|
12-
It can be seen as an Actor with the power of managing socket events. |br|
13-
It offers some callbacks that are used by libmodule to manage its life. |br|
14-
It is initialized through MODULE macro:
15-
16-
.. code::
17-
18-
MODULE("test")
19-
20-
This macro creates a "test" module. |br|
21-
MODULE macro also creates a constructor and destructor that are automatically called by libmodule at start and at end of program. |br|
22-
Finally, this macro declares all of needed callbacks and returns an opaque handler for the module, that will be transparently passed with each call to libmodule API while using :ref:`module_easy`. |br|
11+
A module is core entity of libmodule: it is a single and indipendent logical unit that reacts to events. |br|
12+
It can be seen as an Actor with the ability of managing non-PubSub events. |br|
13+
It requires some callbacks that are used by libmodule to manage its life. |br|
2314

2415
Context
2516
-------
2617

27-
A context is a way to create subnets of modules. You can loop on events from each context, and each context behaves independently from others. |br|
18+
A context can be seen as a collector for modules. You can loop on events from each context, and each context behaves independently from others. |br|
2819
This can be particularly useful when dealing with 2+ threads; ideally, each thread has its own module's context and thus its own events to be polled. |br|
29-
A context is automatically created for you first time a module that binds on that context is registered; so, multi-context API is very similar to single context one. |br|
30-
To initialize a module binding it to its context, use MODULE_CTX macro:
31-
32-
.. code::
33-
34-
MODULE_CTX("test", "myCtx")
35-
36-
This macro firstly creates a "myCtx" context, then a "test" module using same MODULE macro as before. |br|
37-
Indeed, MODULE macro is only a particular case of MODULE_CTX macro, where myCtx is automatically setted to "default". |br|
38-
This makes sense, as you can expect: single context API is a multi context API with only 1 context. |br|
3920
Modules can only see and reach (through PubSub messaging) other modules from same context. |br|
4021

4122
Loop
4223
----
4324

44-
Libmodule offers an internal loop, started with modules_ctx_loop(); note that each context has its own loop. |br|
45-
Moreover, you can even easily integrate it into your own loop: modules_ctx_get_fd() will retrieve a pollable fd and POLLIN events will be raised whenever a new message is available. |br|
46-
Remember that before starting your loop, modules_ctx_dispatch() should be called, to dispatch initial "LoopStarted" messages to each module. |br|
47-
Then, whenever POLLIN data is available on libmodule's fd, you only need to call modules_ctx_dispatch() again. |br|
48-
Finally, remember to close() libmodule's fd retrieved through modules_ctx_get_fd(). |br|
25+
Libmodule offers an internal loop, started with m_ctx_loop(); note that each context has its own loop. |br|
26+
Moreover, you can even easily integrate it into your own loop: m_ctx_get_fd() will retrieve a pollable fd and POLLIN events will be raised whenever a new message is available. |br|
27+
Remember that before starting your loop, m_ctx_dispatch() should be called, to dispatch initial "LoopStarted" messages to each module. |br|
28+
Then, whenever POLLIN data is available on libmodule's fd, you only need to call m_ctx_dispatch() again. |br|
29+
Finally, remember to close() libmodule's fd retrieved through m_ctx_get_fd(). |br|
30+
31+
Source
32+
------
33+
34+
Each module's listens to events by registering sources. |br|
35+
A source can be a timer, a topic (for PubSub communications between modules), a signal, a socket, etc etc. |br|

docs/src/data_structures.rst

Lines changed: 0 additions & 103 deletions
This file was deleted.

docs/src/easy.rst

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
.. |br| raw:: html
2+
3+
<br />
4+
5+
Easy API
6+
========
7+
8+
MOD macro
9+
=========
10+
11+
Libmodule easy API allows simple single-context applications developing. |br|
12+
It offers a
13+
14+
.. code::
15+
16+
M_MOD(name)
17+
18+
macro that automatically manages a module's lifecycle for you. |br|
19+
Moreover, it declares all needed callbacks as seen in :ref:`callbacks`. |br|
20+
Finally, a m_mod_pre_start function is declared too, but it is not needed by libmodule interface, ie: it can be left undefined. Your compiler may warn you about that though. |br|
21+
22+
.. code::
23+
24+
static void m_mod_pre_start(void);
25+
static bool m_mod_on_start(m_mod_t *mod);
26+
static bool m_mod_on_eval(m_mod_t *mod);
27+
static void m_mod_on_evt(m_mod_t *mod, const m_evt_t *const msg);
28+
static void m_mod_on_stop(m_mod_t *mod);
29+
30+
.. c:function:: m_mod_pre_start(void)
31+
32+
This function will be called before any module is registered. |br|
33+
It is the per-module version of :ref:`m_ctx_pre_start <m_ctx_pre_start>` function.
34+
35+
Provided Main
36+
=============
37+
38+
Libmodule offers a weak, thus overridable, default main symbol that just loops on default ctx. |br|
39+
To further customize it, a weak m_ctx_pre_loop() function is also available, called by default main. |br|
40+
You can use this function to eg: parse argv parameters or read some config values. |br|
41+
42+
.. c:function:: m_ctx_pre_loop(c, argc, argv)
43+
44+
Called by default main. |br|
45+
Useful to initialize your program before libmodule starts looping on default context. |br|
46+
47+
:param: :c:type:`m_ctx_t *` c: pointer to context.
48+
:param: :c:type:`int` argc: number of commandline arguments.
49+
:param: :c:type:`char *[]` argv: array of commandline arguments strings.
50+

0 commit comments

Comments
 (0)