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