LCOV - code coverage report
Current view: top level - src - svcmgr.c (source / functions) Hit Total Coverage
Test: mkernel.info Lines: 103 107 96.3 %
Date: 2024-07-29 14:14:23 Functions: 8 8 100.0 %

          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             : */

Generated by: LCOV version 1.16