1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276 | /** @file svcmgr.c
* @brief Service manager implementation
* @date 27/11/2017
* @author François Cerbelle (Fanfan), francois@cerbelle.net
* @copyright Copyright (c) 2017, François Cerbelle
*
* @todo make threadsafe
* @todo investigate prefix or b+* trees
*
* Implements the services dictionnary in an n-tree structure.
*
* @internal
* Compiler gcc
* Last modified 2024-07-28 19:56
* Organization Cerbelle.net
* Company Home
*
* This source code is released for free distribution under the terms of the
* GNU General Public License as published by the Free Software Foundation.
*/
#include "svcmgr.h"
#include "gettext.h"
#define _(String) gettext (String)
#include <stdarg.h> /* va_list, va_start, va_arg, va_end */
#include <stdint.h>
#include <string.h>
#include <stdlib.h> /* free */
#include <stdio.h> /* printf */
#include "debug/assert.h"
#include "debug/memory.h"
typedef struct service_s {
struct service_s *next;
struct service_s *children;
uint8_t nbArgs;
char *name;
svcfunc_t *function;
} service_t;
/** Services tree root */
static service_t* services=NULL;
/** Find a service in the service list by its name
*
* @param[in] p_list Service list head
* @param[in] p_name Service name to find
* @return A pointer on the service record
*/
static service_t* svcmgr_find(service_t* p_list, const char* p_name)
{
int l_cmp; /*< string comparison */
ASSERT(p_name);
DBG_PRINTF("p_list=%p, p_name=%s",p_list,p_name);
l_cmp=0;
/* Search for the service name in the service list */
while ((p_list!=NULL)&&((l_cmp=strcmp(p_list->name,p_name))<0)) {<--- Assuming that condition '(l_cmp=strcmp(p_list->name,p_name))<0' is not redundant
DBG_PRINTF("p_list=%p, p_list->next=%p",p_list,p_list->next);
DBG_PRINTF("p_list=%p, p_list->name=%s",p_list,p_list->name);
DBG_PRINTF("p_list=%p, l_cmp=%d",p_list,l_cmp);
if (l_cmp!=0)<--- Condition 'l_cmp!=0' is always true
p_list = p_list->next;
}
return (l_cmp==0?p_list:NULL);
}
/** Add a service record to the service list if it does not already
* exists
*
* @param[in,out] p_list Pointer to the head of the list that might
* change if the service is created as the
* first of the list
* @param[in] p_service Service record to insert in the list
* @return Pointer to the created service record or to the already existing
* service record
*/
static service_t* svcmgr_insert(service_t** p_list, service_t* p_service)
{
int l_cmp; /*< string comparison */
ASSERT(p_list);
ASSERT(p_service);
DBG_PRINTF("p_list=%p, p_service=%p",p_list,p_service);
l_cmp=0;
/* Search for the service name in the service list */
while ((*p_list)&&((l_cmp=strcmp((*p_list)->name,p_service->name))<0))
p_list = &(*p_list)->next;
if ((*p_list==NULL)||(l_cmp>0)) {
/** @todo threadsafe critical section */
p_service->next = *p_list;
*p_list = p_service;
/* End of critical section */
}
return *p_list;
}
/** Recursively deletes a service record
*
* @param[in] p_service Pointer on the service to delete
*/
static void svcmgr_rdelete(service_t* p_service)
{
service_t* l_svc;
ASSERT(p_service);
DBG_PRINTF("p_service=%p",p_service);
l_svc = NULL;
/* Delete childrens */
while (p_service->children) {
l_svc = p_service->children;
p_service->children = p_service->next;
svcmgr_rdelete(l_svc);
}
/* Delete name */
free(p_service->name);
/* Delete record */
free(p_service);
}
/** Delete a service record from the service list
*
* @param[in,out] p_list Pointer to the head of the list that might
* change if the service to delete is the first
* of the list
* @param[in] p_name Service name to delete
* @return Pointer on the service after the deleted one (can be NULL
* if the deleted service was the last in the list)
*/
static service_t* svcmgr_delete(service_t** p_list, const char* p_name)
{
int l_cmp; /*< string comparison */
ASSERT(p_list);
ASSERT(p_name);
DBG_PRINTF("p_list=%p, p_name=%s",p_list,p_name);
l_cmp=0;
/* Search for the service name in the service list */
while ((*p_list)&&((l_cmp=strcmp((*p_list)->name,p_name))<0))
p_list = &(*p_list)->next;
if ((*p_list!=NULL)&&(l_cmp==0)) {
service_t* l_svc = *p_list;
*p_list = (*p_list)->next;
svcmgr_rdelete(l_svc);
}
return *p_list;
}
void svcmgr_dump(const char* p_prefix, service_t* p_list)
{
#ifndef NDEBUG
while (p_list) {
printf("%s%s\n",p_prefix, p_list->name);
if (p_list->children) {
char l_fullname[256];
snprintf(l_fullname,255,"%s%s/",p_prefix,p_list->name);
svcmgr_dump(l_fullname,p_list->children);
}
p_list = p_list->next;
}
#else
/* Avoid unused parameters compilation warning for release builds */
((void)p_prefix);
((void)p_list);
#endif
}
void svcmgr_register(const char* p_endpoint, svcfunc_t* p_svcfunc)
{
char* l_token;
char* l_endpoint; /* Get rid of const qualifier */
service_t** l_head;
service_t* l_svc;
service_t* l_retsvc;
ASSERT(p_endpoint);
ASSERT(p_svcfunc);
DBG_PRINTF("p_endpoint=%s, p_svcfunc=%p",p_endpoint,p_svcfunc);
l_endpoint = strdup(p_endpoint);
DBG_PRINTF("l_endpoint=%s",l_endpoint);
l_head=&services;
DBG_PRINTF("l_head=%p, *l_head=%p",l_head,*l_head);
l_svc=NULL;
l_retsvc=NULL;
while ((l_token = strtok_r(l_endpoint,"/",&l_endpoint))) {
DBG_PRINTF("l_token=%s",l_token);
DBG_PRINTF("l_svc=%p",l_svc);
l_svc = (service_t*)malloc(sizeof(service_t));
DBG_PRINTF("l_svc=%p",l_svc);
l_svc->next=NULL;
l_svc->children=NULL;
l_svc->name=strdup(l_token);
if (strlen(l_endpoint)) {
/* Create a intermediate node */
l_svc->nbArgs=0;
l_svc->function=NULL;
} else {
/* Create an endpoint */
l_svc->nbArgs=0;
l_svc->function=p_svcfunc;
}
DBG_MSG("---------");
DBG_PRINTF("l_svc=%p",l_svc);
DBG_PRINTF("l_svc->next=%p",l_svc->next);
DBG_PRINTF("l_svc->children=%p",l_svc->children);
DBG_PRINTF("l_svc->nbArgs=%d",l_svc->nbArgs);
DBG_PRINTF("l_svc->name=%s",l_svc->name);
DBG_PRINTF("l_svc->function=%p",l_svc->function);
DBG_MSG("---------");
if (l_svc!=(l_retsvc=svcmgr_insert(l_head, l_svc)))
free(l_svc);
DBG_PRINTF("l_retsvc=%p",l_retsvc);
l_head=&(l_retsvc->children);
DBG_PRINTF("l_head=%p, *l_head=%p",l_head,*l_head);
};
svcmgr_dump("/",services);
}
uint8_t svcmgr_call(const char* p_endpoint,...)
{
service_t* l_svc;
ASSERT(p_endpoint);
DBG_PRINTF("p_endpoint=%s",p_endpoint);
l_svc=svcmgr_find(services, p_endpoint);
DBG_PRINTF("l_svc=%p",l_svc);
if (l_svc) {
DBG_PRINTF("l_svc->function=%p",l_svc->function);
if (l_svc->function) {
va_list l_ap;
va_start(l_ap, p_endpoint);
l_svc->function(l_ap);
va_end(l_ap);
}
}
DBG_TRACE;
return 0;
}
void svcmgr_unregister(const char* p_endpoint)
{
svcmgr_delete(&services, p_endpoint);
}
/*
sem_init
sem_wait
sem_post
sem_destroy
sem_overview
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
*/
|