X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-apiset.c;fp=src%2Fafb-apis.c;h=d9a4e5e86f47e14c1556539d21d3f671a444000a;hb=a8e971702f23ee67e02b4716ad4159f12cefdca6;hp=6e093550e4113cde18613a80f1f20ff1184c1c38;hpb=9991f9f55b6b77bf89a9e2cec84280d0c9c0b2cd;p=src%2Fapp-framework-binder.git diff --git a/src/afb-apis.c b/src/afb-apiset.c similarity index 53% rename from src/afb-apis.c rename to src/afb-apiset.c index 6e093550..d9a4e5e8 100644 --- a/src/afb-apis.c +++ b/src/afb-apiset.c @@ -25,13 +25,16 @@ #include "afb-session.h" #include "verbose.h" -#include "afb-apis.h" +#include "afb-api.h" +#include "afb-apiset.h" #include "afb-context.h" #include "afb-xreq.h" #include "jobs.h" #include +#define INCR 8 /* CAUTION: must be a power of 2 */ + /** * Internal description of an api */ @@ -40,24 +43,58 @@ struct api_desc { struct afb_api api; /**< handler of the api */ }; -static struct api_desc *apis_array = NULL; -static int apis_count = 0; -static int apis_timeout = 15; +struct afb_apiset +{ + struct afb_apiset *subset; + struct api_desc *apis; + int count; + int timeout; + int refcount; + char name[1]; +}; /** - * Set the API timeout - * @param to the timeout in seconds + * Search the api of 'name'. + * @param set the api set + * @param name the api name to search + * @return the descriptor if found or NULL otherwise */ -void afb_apis_set_timeout(int to) +static const struct api_desc *search(struct afb_apiset *set, const char *name) { - apis_timeout = to; + int i, c, up, lo; + const struct api_desc *a; + + /* dichotomic search of the api */ + /* initial slice */ + lo = 0; + up = set->count; + for (;;) { + /* check remaining slice */ + if (lo >= up) { + /* not found */ + return NULL; + } + /* check the mid of the slice */ + i = (lo + up) >> 1; + a = &set->apis[i]; + c = strcasecmp(a->name, name); + if (c == 0) { + /* found */ + return a; + } + /* update the slice */ + if (c < 0) + lo = i + 1; + else + up = i; + } } /** * Checks wether 'name' is a valid API name. * @return 1 if valid, 0 otherwise */ -int afb_apis_is_valid_api_name(const char *name) +int afb_apiset_valid_name(const char *name) { unsigned char c; @@ -90,8 +127,90 @@ int afb_apis_is_valid_api_name(const char *name) return 1; } +struct afb_apiset *afb_apiset_addref(struct afb_apiset *set) +{ + if (set) + __atomic_add_fetch(&set->refcount, 1, __ATOMIC_RELAXED); + return set; +} + +void afb_apiset_unref(struct afb_apiset *set) +{ + if (set && !__atomic_sub_fetch(&set->refcount, 1, __ATOMIC_RELAXED)) { + afb_apiset_unref(set->subset); + free(set->apis); + free(set); + } +} + +/** + * Create an apiset + */ +struct afb_apiset *afb_apiset_create(const char *name, int timeout, struct afb_apiset *subset) +{ + struct afb_apiset *set; + + set = malloc((name ? strlen(name) : 0) + sizeof *set); + if (set) { + set->subset = afb_apiset_addref(subset); + set->apis = malloc(INCR * sizeof *set->apis); + set->count = 0; + set->timeout = timeout; + set->refcount = 1; + if (name) + strcpy(set->name, name); + else + set->name[0] = 0; + } + return set; +} + + +/** + * Get the API timeout of the set + * @param set the api set + * @return the timeout in seconds + */ +int afb_apiset_get_timeout(struct afb_apiset *set) +{ + return set->timeout; +} + +/** + * Set the API timeout of the set + * @param set the api set + * @param to the timeout in seconds + */ +void afb_apiset_set_timeout(struct afb_apiset *set, int to) +{ + set->timeout = to; +} + +/** + * Get the subset of the set + * @param set the api set + * @return the subset of set + */ +struct afb_apiset *afb_apiset_get_subset(struct afb_apiset *set) +{ + return set->subset; +} + +/** + * Set the subset of the set + * @param set the api set + * @param subset the subset to set + */ +void afb_apiset_set_subset(struct afb_apiset *set, struct afb_apiset *subset) +{ + struct afb_apiset *tmp = set->subset; + set->subset = afb_apiset_addref(subset); + afb_apiset_unref(tmp); +} + /** * Adds the api of 'name' described by 'api'. + * @param set the api set * @param name the name of the api to add (have to survive, not copied!) * @param api the api * @returns 0 in case of success or -1 in case @@ -100,21 +219,21 @@ int afb_apis_is_valid_api_name(const char *name) * - EEXIST if name already registered * - ENOMEM when out of memory */ -int afb_apis_add(const char *name, struct afb_api api) +int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api api) { struct api_desc *apis; int i, c; /* Checks the api name */ - if (!afb_apis_is_valid_api_name(name)) { + if (!afb_apiset_valid_name(name)) { ERROR("invalid api name forbidden (name is '%s')", name); errno = EINVAL; goto error; } /* check previously existing plugin */ - for (i = 0 ; i < apis_count ; i++) { - c = strcasecmp(apis_array[i].name, name); + for (i = 0 ; i < set->count ; i++) { + c = strcasecmp(set->apis[i].name, name); if (c == 0) { ERROR("api of name %s already exists", name); errno = EEXIST; @@ -125,26 +244,24 @@ int afb_apis_add(const char *name, struct afb_api api) } /* allocates enough memory */ - apis = realloc(apis_array, ((unsigned)apis_count + 1) * sizeof * apis); + c = (set->count + INCR) & ~(INCR - 1); + apis = realloc(set->apis, ((unsigned)c) * sizeof * apis); if (apis == NULL) { ERROR("out of memory"); errno = ENOMEM; goto error; } - apis_array = apis; + set->apis = apis; /* copy higher part of the array */ - c = apis_count; - while (c > i) { - apis_array[c] = apis_array[c - 1]; - c--; - } + apis += i; + if (i != set->count) + memmove(apis + 1, apis, ((unsigned)(set->count - i)) * sizeof *apis); /* record the plugin */ - apis = &apis_array[i]; apis->api = api; apis->name = name; - apis_count++; + set->count++; NOTICE("API %s added", name); @@ -154,158 +271,116 @@ error: return -1; } -/** - * Search the 'api'. - * @param api the api of the verb - * @return the descriptor if found or NULL otherwise - */ -static const struct api_desc *search(const char *api) +int afb_apiset_del(struct afb_apiset *set, const char *name) { - int i, c, up, lo; - const struct api_desc *a; + int i, c; - /* dichotomic search of the api */ - /* initial slice */ - lo = 0; - up = apis_count; - for (;;) { - /* check remaining slice */ - if (lo >= up) { - /* not found */ - return NULL; - } - /* check the mid of the slice */ - i = (lo + up) >> 1; - a = &apis_array[i]; - c = strcasecmp(a->name, api); + /* search the api */ + for (i = 0 ; i < set->count ; i++) { + c = strcasecmp(set->apis[i].name, name); if (c == 0) { - /* found */ - return a; + set->count--; + while(i < set->count) { + set->apis[i] = set->apis[i + 1]; + i++; + } + return 0; } - /* update the slice */ - if (c < 0) - lo = i + 1; - else - up = i; + if (c > 0) + break; } + errno = ENOENT; + return -1; } -/** - * Starts a service by its 'api' name. - * @param api name of the service to start - * @param share_session if true start the servic"e in a shared session - * if false start it in its own session - * @param onneed if true start the service if possible, if false the api - * must be a service - * @return a positive number on success - */ -int afb_apis_start_service(const char *api, int share_session, int onneed) +int afb_apiset_get(struct afb_apiset *set, const char *name, struct afb_api *api) { - int i; + const struct api_desc *i; - for (i = 0 ; i < apis_count ; i++) { - if (!strcasecmp(apis_array[i].name, api)) - return apis_array[i].api.itf->service_start(apis_array[i].api.closure, share_session, onneed); + i = search(set, name); + if (i) { + *api = i->api; + return 0; } - ERROR("can't find service %s", api); + if (set->subset) + return afb_apiset_get(set->subset, name, api); + errno = ENOENT; return -1; } /** - * Starts all possible services but stops at first error. + * Starts a service by its 'api' name. + * @param set the api set + * @param name name of the service to start * @param share_session if true start the servic"e in a shared session * if false start it in its own session - * @return 0 on success or a negative number when an error is found - */ -int afb_apis_start_all_services(int share_session) -{ - int i, rc; - - for (i = 0 ; i < apis_count ; i++) { - rc = apis_array[i].api.itf->service_start(apis_array[i].api.closure, share_session, 1); - if (rc < 0) - return rc; - } - return 0; -} - -/** - * Internal direct dispatch of the request 'xreq' - * @param xreq the request to dispatch + * @param onneed if true start the service if possible, if false the api + * must be a service + * @return a positive number on success */ -static void do_call_direct(struct afb_xreq *xreq) +int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share_session, int onneed) { const struct api_desc *a; - /* search the api */ - a = search(xreq->api); - if (!a) - afb_xreq_fail_f(xreq, "unknown-api", "api %s not found", xreq->api); - else { - xreq->context.api_key = a->api.closure; - a->api.itf->call(a->api.closure, xreq); + a = search(set, name); + if (!a) { + ERROR("can't find service %s", name); + errno = ENOENT; + return -1; } -} -/** - * Asynchronous dispatch callback for the request 'xreq' - * @param signum 0 on normal flow or the signal number that interupted the normal flow - */ -static void do_call_async(int signum, void *arg) -{ - struct afb_xreq *xreq = arg; + if (a->api.itf->service_start) + return a->api.itf->service_start(a->api.closure, share_session, onneed, set); - if (signum != 0) - afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum); - else { - do_call_direct(xreq); - } - afb_xreq_unref(xreq); -} + if (onneed) + return 0; -/** - * Dispatch the request 'xreq' synchronously and directly. - * @param xreq the request to dispatch - */ -void afb_apis_call_direct(struct afb_xreq *xreq) -{ - afb_xreq_begin(xreq); - do_call_direct(xreq); + /* already started: it is an error */ + ERROR("The api %s is not a startable service", name); + errno = EINVAL; + return -1; } /** - * Dispatch the request 'xreq' asynchronously. - * @param xreq the request to dispatch + * Starts all possible services but stops at first error. + * @param set the api set + * @param share_session if true start the servic"e in a shared session + * if false start it in its own session + * @return 0 on success or a negative number when an error is found */ -void afb_apis_call(struct afb_xreq *xreq) +int afb_apiset_start_all_services(struct afb_apiset *set, int share_session) { int rc; + const struct api_desc *i, *e; - afb_xreq_begin(xreq); - afb_xreq_addref(xreq); - rc = jobs_queue(NULL, apis_timeout, do_call_async, xreq); - if (rc < 0) { - /* TODO: allows or not to proccess it directly as when no threading? (see above) */ - ERROR("can't process job with threads: %m"); - afb_xreq_fail_f(xreq, "cancelled", "not able to create a job for the task"); - afb_xreq_unref(xreq); + i = set->apis; + e = &set->apis[set->count]; + while (i != e) { + if (i->api.itf->service_start) { + rc = i->api.itf->service_start(i->api.closure, share_session, 1, set); + if (rc < 0) + return rc; + } + i++; } + return 0; } /** * Ask to update the hook flags of the 'api' - * @param api the api to update (NULL updates all) + * @param set the api set + * @param name the api to update (NULL updates all) */ -void afb_apis_update_hooks(const char *api) +void afb_apiset_update_hooks(struct afb_apiset *set, const char *name) { const struct api_desc *i, *e; - if (!api) { - i = apis_array; - e = &apis_array[apis_count]; + if (!name) { + i = set->apis; + e = &set->apis[set->count]; } else { - i = search(api); + i = search(set, name); e = &i[!!i]; } while (i != e) { @@ -317,17 +392,18 @@ void afb_apis_update_hooks(const char *api) /** * Set the verbosity level of the 'api' - * @param api the api to set (NULL set all) + * @param set the api set + * @param name the api to set (NULL set all) */ -void afb_apis_set_verbosity(const char *api, int level) +void afb_apiset_set_verbosity(struct afb_apiset *set, const char *name, int level) { const struct api_desc *i, *e; - if (!api) { - i = apis_array; - e = &apis_array[apis_count]; + if (!name) { + i = set->apis; + e = &set->apis[set->count]; } else { - i = search(api); + i = search(set, name); e = &i[!!i]; } while (i != e) { @@ -339,13 +415,14 @@ void afb_apis_set_verbosity(const char *api, int level) /** * Set the verbosity level of the 'api' - * @param api the api to set (NULL set all) + * @param set the api set + * @param name the api to set (NULL set all) */ -int afb_apis_get_verbosity(const char *api) +int afb_apiset_get_verbosity(struct afb_apiset *set, const char *name) { const struct api_desc *i; - i = api ? search(api) : NULL; + i = name ? search(set, name) : NULL; if (!i) { errno = ENOENT; return -1; @@ -358,30 +435,105 @@ int afb_apis_get_verbosity(const char *api) /** * Get the list of api names + * @param set the api set * @return a NULL terminated array of api names. Must be freed. */ -const char **afb_apis_get_names() +const char **afb_apiset_get_names(struct afb_apiset *set) { size_t size; char *dest; const char **names; int i; - size = apis_count * (1 + sizeof(*names)) + sizeof(*names); - for (i = 0 ; i < apis_count ; i++) - size += strlen(apis_array[i].name); + size = set->count * (1 + sizeof(*names)) + sizeof(*names); + for (i = 0 ; i < set->count ; i++) + size += strlen(set->apis[i].name); names = malloc(size); if (!names) errno = ENOMEM; else { - dest = (void*)&names[apis_count+1]; - for (i = 0 ; i < apis_count ; i++) { + dest = (void*)&names[set->count+1]; + for (i = 0 ; i < set->count ; i++) { names[i] = dest; - dest = stpcpy(dest, apis_array[i].name) + 1; + dest = stpcpy(dest, set->apis[i].name) + 1; } names[i] = NULL; } return names; } + +#if 0 + + + +/** + * Internal direct dispatch of the request 'xreq' + * @param set the api set + * @param xreq the request to dispatch + */ +static void do_call_direct(struct afb_xreq *xreq) +{ + const struct api_desc *a; + + /* search the api */ + a = search(xreq->api); + if (!a) + afb_xreq_fail_f(xreq, "unknown-api", "api %s not found", xreq->api); + else { + xreq->context.api_key = a->api.closure; + a->api.itf->call(a->api.closure, xreq); + } +} + +/** + * Asynchronous dispatch callback for the request 'xreq' + * @param set the api set + * @param signum 0 on normal flow or the signal number that interupted the normal flow + */ +static void do_call_async(int signum, void *arg) +{ + struct afb_xreq *xreq = arg; + + if (signum != 0) + afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum); + else { + do_call_direct(xreq); + } + afb_xreq_unref(xreq); +} + +/** + * Dispatch the request 'xreq' synchronously and directly. + * @param set the api set + * @param xreq the request to dispatch + */ +void afb_apiset_call_direct(struct afb_apiset *set, struct afb_xreq *xreq) +{ + afb_xreq_begin(xreq); + do_call_direct(xreq); +} + +/** + * Dispatch the request 'xreq' asynchronously. + * @param set the api set + * @param xreq the request to dispatch + */ +void afb_apiset_call(struct afb_apiset *set, struct afb_xreq *xreq) +{ + int rc; + + afb_xreq_begin(xreq); + afb_xreq_addref(xreq); + rc = jobs_queue(NULL, apis_timeout, do_call_async, xreq); + if (rc < 0) { + /* TODO: allows or not to proccess it directly as when no threading? (see above) */ + ERROR("can't process job with threads: %m"); + afb_xreq_fail_f(xreq, "cancelled", "not able to create a job for the task"); + afb_xreq_unref(xreq); + } +} + +#endif +