UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
module.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2013-2024 CESNET
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#include <assert.h>
39#include <stdlib.h>
40#include <string.h>
41
42#include "debug.h"
43#include "module.h"
44#include "utils/list.h"
45
46#define MOD_NAME "[module] "
47
48void module_init_default(struct module *module_data)
49{
50 int ret = 0;
51 memset(module_data, 0, sizeof(struct module));
52
53 pthread_mutexattr_t attr;
54 ret |= pthread_mutexattr_init(&attr);
55 ret |= pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
56 ret |= pthread_mutex_init(&module_data->lock, &attr);
57 ret |= pthread_mutex_init(&module_data->msg_queue_lock, &attr);
58 ret |= pthread_mutexattr_destroy(&attr);
59 assert(ret == 0 && "Unable to create mutex or set attributes");
60
61 module_data->children = simple_linked_list_init();
62 module_data->msg_queue = simple_linked_list_init();
64
65 module_data->magic = MODULE_MAGIC;
66}
67
68static void
69module_mutex_lock(pthread_mutex_t *lock)
70{
71 MSG(DEBUG, "Locking lock %p\n", lock);
72 pthread_mutex_lock(lock);
73}
74
75static void
76module_mutex_unlock(pthread_mutex_t *lock)
77{
78 MSG(DEBUG, "Unlocking lock %p\n", lock);
79 pthread_mutex_unlock(lock);
80}
81
82void module_register(struct module *module_data, struct module *parent)
83{
84 if(parent) {
85 module_data->parent = parent;
86 module_mutex_lock(&module_data->parent->lock);
87 simple_linked_list_append(module_data->parent->children, module_data);
89 module_mutex_unlock(&module_data->parent->lock);
90 }
91}
92
93void module_done(struct module *module_data)
94{
95 if(!module_data)
96 return;
97
98 if (module_data->cls == MODULE_CLASS_NONE)
99 return;
100
101 assert(module_data->magic == MODULE_MAGIC);
102
103 if(module_data->parent) {
104 module_mutex_lock(&module_data->parent->lock);
105 bool found = simple_linked_list_remove(
106 module_data->parent->children, module_data);
107 assert(found);
108 module_mutex_unlock(&module_data->parent->lock);
109 }
110
111 // we assume that deleter may dealloc space where are structure stored
112 module_mutex_lock(&module_data->lock);
113 struct module tmp;
114 memcpy(&tmp, module_data, sizeof(struct module));
115 module_mutex_unlock(&module_data->lock);
116
117 module_data->cls = MODULE_CLASS_NONE;
118
119 if(module_data->deleter)
120 module_data->deleter(module_data);
121
122 if(simple_linked_list_size(tmp.children) > 0) {
123 log_msg(LOG_LEVEL_WARNING, "Warning: Child database not empty! Remaining:\n");
124 dump_tree(&tmp, 0);
126 for(void *it = simple_linked_list_it_init(module_data->children); it != NULL; ) {
127 struct module *child = simple_linked_list_it_next(&it);
128 module_mutex_lock(&child->lock);
129 child->parent = NULL;
130 module_mutex_unlock(&child->lock);
131 }
133 }
135
137 fprintf(stderr, "Warning: Message queue not empty!\n");
139 printf("Path: ");
140 dump_parents(&tmp);
141 }
142 struct message *m;
143 while ((m = check_message(&tmp))) {
144 free_message(m, NULL);
145 }
146 }
148
151 free_message_for_child(m, NULL);
152 }
154
155 pthread_mutex_destroy(&tmp.lock);
156
157 free(tmp.name);
158}
159
160static const char *module_class_name_pairs[] = {
161 [MODULE_CLASS_ROOT] = "root",
162 [MODULE_CLASS_PORT] = "port",
163 [MODULE_CLASS_COMPRESS] = "compress",
164 [MODULE_CLASS_DATA] = "data",
165 [MODULE_CLASS_SENDER] = "sender",
166 [MODULE_CLASS_RECEIVER] = "receiver",
167 [MODULE_CLASS_TX] = "transmit",
168 [MODULE_CLASS_AUDIO] = "audio",
169 [MODULE_CLASS_CONTROL] = "control",
170 [MODULE_CLASS_CAPTURE] = "capture",
171 [MODULE_CLASS_FILTER] = "filter",
172 [MODULE_CLASS_DISPLAY] = "display",
173 [MODULE_CLASS_DECODER] = "decoder",
174 [MODULE_CLASS_EXPORTER] = "exporter",
175 [MODULE_CLASS_KEYCONTROL] = "keycontrol",
176};
177
179{
180 if((unsigned int) cls < sizeof(module_class_name_pairs)/sizeof(const char *))
182 else
183 return NULL;
184}
185
186void
187append_message_path(char *buf, int buflen, const enum module_class *modules)
188{
189 const enum module_class *mod = modules;
190
191 while(*mod != MODULE_CLASS_NONE) {
192 if(strlen(buf) > 0) {
193 strncat(buf, ".", buflen - strlen(buf) - 1);
194 }
195 const char *node_name = module_class_name(*mod);
196 assert(node_name != NULL);
197
198 strncat(buf, node_name, buflen - strlen(buf) - 1);
199 mod += 1;
200 }
201}
202
203struct module *get_root_module(struct module *node)
204{
205 assert(node);
206 while(node->parent) {
207 node = node->parent;
208 }
209 assert(node->cls == MODULE_CLASS_ROOT);
210
211 return node;
212}
213
214struct module *get_parent_module(struct module *node)
215{
216 return node->parent;
217}
218
223static struct module *find_child(struct module *node, const char *node_name, int id_num,
224 const char *id_name)
225{
226 for(void *it = simple_linked_list_it_init(node->children); it != NULL; ) {
227 struct module *child = (struct module *) simple_linked_list_it_next(&it);
228 const char *child_name = module_class_name(child->cls);
229 assert(child_name != NULL);
230 if(strcasecmp(child_name, node_name) == 0) {
231 if (id_name != NULL) {
232 if (child->name && strcmp(child->name, id_name) == 0) {
234 return child;
235 }
236 } else if (id_num-- == 0) {
238 return child;
239 }
240 }
241 }
242 return NULL;
243}
244
251static void get_receiver_index(char *node_str, int *index, char **name) {
252 if (strchr(node_str, '[') && (strchr(node_str, ']') > strchr(node_str, '['))) {
253 char *item = strchr(node_str, '[') + 1;
254 *strchr(node_str, '[') = '\0';
255 *strchr(item, ']') = '\0';
256 if (isdigit(item[0])) {
257 *index = atoi(item);
258 } else {
259 *name = item;
260 }
261 }
262}
263
264struct module *get_module(struct module *root, const char *const_path)
265{
266 assert(root != NULL);
267 assert(const_path != NULL);
268
269 struct module *receiver = root;
270 char *path, *tmp;
271 char *item, *save_ptr;
272
273 module_mutex_lock(&root->lock);
274
275 tmp = path = strdup(const_path);
276 assert(path != NULL);
277 while ((item = strtok_r(path, ".", &save_ptr))) {
278 struct module *old_receiver = receiver;
279
280 receiver = get_matching_child(receiver, item);
281
282 if (!receiver) {
283 module_mutex_unlock(&old_receiver->lock);
284 free(tmp);
285 return NULL;
286 }
287 module_mutex_lock(&receiver->lock);
288 module_mutex_unlock(&old_receiver->lock);
289
290 path = NULL;
291
292 }
293 free(tmp);
294
295 module_mutex_unlock(&receiver->lock);
296
297 return receiver;
298}
299
300struct module *get_matching_child(struct module *node, const char *const_path)
301{
302 struct module *receiver = node;
303 char *path, *tmp;
304 char *item, *save_ptr = NULL;
305
306 assert(node != NULL);
307
308 tmp = path = strdup(const_path);
309 assert(path != NULL);
310 if ((item = strtok_r(path, ".", &save_ptr))) {
311 int id_num = 0;
312 char *id_name = NULL;
313 get_receiver_index(item, &id_num, &id_name);
314 receiver = find_child(receiver, item, id_num, id_name);
315 if (!receiver) {
316 free(tmp);
317 return NULL;
318 }
319 free(tmp);
320 return receiver;
321 }
322
323 free(tmp);
324
325 return NULL;
326}
327
333void dump_tree(struct module *root_node, int indent) {
334 for(int i = 0; i < indent; ++i)
335 putchar(' ');
336
337 printf("%s\n", module_class_name(root_node->cls));
338
339 module_mutex_lock(&root_node->lock);
340 for(void *it = simple_linked_list_it_init(root_node->children); it != NULL; ) {
341 struct module *child = simple_linked_list_it_next(&it);
342 dump_tree(child, indent + 2);
343 }
344 module_mutex_unlock(&root_node->lock);
345}
346
347void
348dump_parents(struct module *node)
349{
350 bool first = true;
351 while (node != NULL) {
352 if (!first) {
353 printf("<-");
354 }
355 printf("%s", module_class_name(node->cls));
356 first = false;
357 node = get_parent_module(node);
358 }
359 printf("\n");
360}
361
366static const char *get_module_identifier(struct module *mod)
367{
368 const char *cls_name = module_class_name(mod->cls);
369 struct module *parent = get_parent_module(mod);
370 if (parent == NULL) {
371 return cls_name;
372 }
373
375
376 int our_index = 0;
377 for (void *it = simple_linked_list_it_init(parent->children);
378 it != NULL;) {
379 struct module *child = simple_linked_list_it_next(&it);
380 if (child->cls != mod->cls) {
381 continue;
382 }
383 if (child == mod) { // found our node
384 break;
385 }
386 our_index += 1;
387 }
388 if (our_index == 0) {
390 return cls_name;
391 }
392 // append our index if >0
393 _Thread_local static char name[128];
394 name[sizeof name - 1] = '\0';
395 int ret = snprintf(name, sizeof name, "%s[%d]", cls_name, our_index);
396 assert((unsigned)ret < sizeof name);
397
399
400 return name;
401}
402
408bool module_get_path_str(struct module *mod, char *buf, size_t buflen) {
409 assert(buflen > 0);
410 buf[0] = '\0';
411
412 while (mod) {
413 const char *cur_name = get_module_identifier(mod);
414 if (sizeof(buf) + 1 + sizeof(cur_name) >= buflen) {
415 return false;
416 }
417 // move content of buf strlen(cur_name) right
418 if (strlen(buf) > 0) {
419 memmove(buf + strlen(cur_name) + 1, buf, strlen(buf) + 1);
420 buf[strlen(cur_name)] = '.'; // and separate with '.'
421 } else { // rightmost (first written) element
422 buf[strlen(cur_name)] = '\0';
423 }
424 memcpy(buf, cur_name, strlen(cur_name));
425 mod = mod->parent;
426 }
427
428 return true;
429}
430
431/* vim: set expandtab sw=8: */
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define MSG(l, fmt,...)
Definition debug.h:96
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
void module_init_default(struct module *module_data)
Definition module.c:48
void module_register(struct module *module_data, struct module *parent)
Definition module.c:82
void dump_tree(struct module *root_node, int indent)
Definition module.c:333
bool module_get_path_str(struct module *mod, char *buf, size_t buflen)
Definition module.c:408
#define MODULE_MAGIC
Definition module.h:79
struct module * get_module(struct module *root, const char *const_path)
Definition module.c:264
void dump_parents(struct module *node)
Definition module.c:348
void module_done(struct module *module_data)
Definition module.c:93
module_class
Definition module.h:81
const char * module_class_name(enum module_class cls)
Definition module.c:178
struct module * get_matching_child(struct module *node, const char *const_path)
Definition module.c:300
struct module * get_root_module(struct module *node)
Definition module.c:203
void append_message_path(char *buf, int buflen, const enum module_class *modules)
Definition module.c:187
struct module * get_parent_module(struct module *node)
Definition module.c:214
@ MODULE_CLASS_CONTROL
Definition module.h:91
@ MODULE_CLASS_NONE
Definition module.h:82
@ MODULE_CLASS_DATA
Definition module.h:86
@ MODULE_CLASS_ROOT
Definition module.h:83
@ MODULE_CLASS_DISPLAY
Definition module.h:94
@ MODULE_CLASS_FILTER
Definition module.h:93
@ MODULE_CLASS_EXPORTER
Definition module.h:96
@ MODULE_CLASS_COMPRESS
Definition module.h:85
@ MODULE_CLASS_KEYCONTROL
Definition module.h:97
@ MODULE_CLASS_RECEIVER
Definition module.h:88
@ MODULE_CLASS_AUDIO
Definition module.h:90
@ MODULE_CLASS_CAPTURE
Definition module.h:92
@ MODULE_CLASS_DECODER
Definition module.h:95
@ MODULE_CLASS_TX
Definition module.h:89
@ MODULE_CLASS_SENDER
Definition module.h:87
@ MODULE_CLASS_PORT
Definition module.h:84
enum library_class cls
Definition host.cpp:749
volatile int log_level
Definition debug.cpp:65
void simple_linked_list_append(struct simple_linked_list *l, void *data)
Definition list.cpp:68
void * simple_linked_list_it_next(void **i)
Definition list.cpp:119
bool simple_linked_list_remove(struct simple_linked_list *l, void *item)
Definition list.cpp:144
int simple_linked_list_size(struct simple_linked_list *l)
Definition list.cpp:93
struct simple_linked_list * simple_linked_list_init(void)
Definition list.cpp:53
void simple_linked_list_destroy(struct simple_linked_list *l)
Definition list.cpp:58
void simple_linked_list_it_destroy(void *i)
Should be used when it != NULL, eg. when leaving the loop before the end.
Definition list.cpp:139
void * simple_linked_list_pop(struct simple_linked_list *l)
Definition list.cpp:82
void * simple_linked_list_it_init(struct simple_linked_list *l)
Definition list.cpp:108
#define DEBUG
Definition main.c:27
void free_message(struct message *msg, struct response *r)
void free_message_for_child(void *m, struct response *r)
Definition messaging.cpp:99
struct message * check_message(struct module *mod)
void module_check_undelivered_messages(struct module *node)
Sends message with waiting for response.
static void get_receiver_index(char *node_str, int *index, char **name)
Definition module.c:251
static const char * module_class_name_pairs[]
Definition module.c:160
static void module_mutex_lock(pthread_mutex_t *lock)
Definition module.c:69
static const char * get_module_identifier(struct module *mod)
Definition module.c:366
static struct module * find_child(struct module *node, const char *node_name, int id_num, const char *id_name)
Definition module.c:223
static void module_mutex_unlock(pthread_mutex_t *lock)
Definition module.c:76
codec_t first
Definition sdl2.c:423
const char * parent
Definition settings.cpp:198
const char * name
Definition settings.cpp:193
Definition hd-rum.c:27
char * name
Definition module.h:129
enum module_class cls
Definition module.h:115
struct simple_linked_list * msg_queue
Definition module.h:122
pthread_mutex_t msg_queue_lock
Definition module.h:121
pthread_mutex_t lock
Definition module.h:114
uint32_t magic
Definition module.h:112
struct simple_linked_list * children
Definition module.h:117
struct simple_linked_list * msg_queue_children
messages for childern that were not delivered
Definition module.h:124
module_deleter_t deleter
Definition module.h:118
struct module * parent
Definition module.h:116