X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-apiset.c;h=c934e8cdabb4519304414171869b01540767fde9;hb=c6380108964e71f533d8c672bb9c217020a95e8d;hp=cf0544600358c6ba66f52326ac33dab4c2a0736c;hpb=af552129e778954878a3a3b4e0138fdb2c1f2602;p=src%2Fapp-framework-binder.git diff --git a/src/afb-apiset.c b/src/afb-apiset.c index cf054460..c934e8cd 100644 --- a/src/afb-apiset.c +++ b/src/afb-apiset.c @@ -31,26 +31,29 @@ #include "afb-xreq.h" #include "jobs.h" -#include - #define INCR 8 /* CAUTION: must be a power of 2 */ /** * Internal description of an api */ -struct api_desc { +struct api_desc +{ + int status; const char *name; /**< name of the api */ struct afb_api api; /**< handler of the api */ }; +/** + * Data structure for apiset + */ struct afb_apiset { - struct afb_apiset *subset; - struct api_desc *apis; - int count; - int timeout; - int refcount; - char name[1]; + struct api_desc *apis; /**< description of apis */ + struct afb_apiset *subset; /**< subset if any */ + int count; /**< count of apis in the set */ + int timeout; /**< the timeout in second for the apiset */ + int refcount; /**< reference count for freeing resources */ + char name[1]; /**< name of the apiset */ }; /** @@ -59,10 +62,10 @@ struct afb_apiset * @param name the api name to search * @return the descriptor if found or NULL otherwise */ -static const struct api_desc *search(struct afb_apiset *set, const char *name) +static struct api_desc *search(struct afb_apiset *set, const char *name) { int i, c, up, lo; - const struct api_desc *a; + struct api_desc *a; /* dichotomic search of the api */ /* initial slice */ @@ -91,6 +94,10 @@ static const struct api_desc *search(struct afb_apiset *set, const char *name) } /** + * Increases the count of references to the apiset and return its address + * @param set the set whose reference count is to be increased + * @return the given apiset + */ struct afb_apiset *afb_apiset_addref(struct afb_apiset *set) { if (set) @@ -98,6 +105,11 @@ struct afb_apiset *afb_apiset_addref(struct afb_apiset *set) return set; } +/** + * Decreases the count of references to the apiset and frees its + * resources when no more references exists. + * @param set the set to unrefrence + */ void afb_apiset_unref(struct afb_apiset *set) { if (set && !__atomic_sub_fetch(&set->refcount, 1, __ATOMIC_RELAXED)) { @@ -109,18 +121,21 @@ void afb_apiset_unref(struct afb_apiset *set) /** * Create an apiset + * @param name the name of the apiset + * @param timeout the default timeout in seconds for the apiset + * @return the created apiset or NULL in case of error */ -struct afb_apiset *afb_apiset_create(const char *name, int timeout, struct afb_apiset *subset) +struct afb_apiset *afb_apiset_create(const char *name, int timeout) { 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; + set->subset = NULL; if (name) strcpy(set->name, name); else @@ -129,13 +144,22 @@ struct afb_apiset *afb_apiset_create(const char *name, int timeout, struct afb_a return set; } +/** + * the name of the apiset + * @param set the api set + * @return the name of the set + */ +const char *afb_apiset_name(struct afb_apiset *set) +{ + return set->name; +} /** * 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) +int afb_apiset_timeout_get(struct afb_apiset *set) { return set->timeout; } @@ -145,7 +169,7 @@ int afb_apiset_get_timeout(struct afb_apiset *set) * @param set the api set * @param to the timeout in seconds */ -void afb_apiset_set_timeout(struct afb_apiset *set, int to) +void afb_apiset_timeout_set(struct afb_apiset *set, int to) { set->timeout = to; } @@ -155,7 +179,7 @@ void afb_apiset_set_timeout(struct afb_apiset *set, int to) * @param set the api set * @return the subset of set */ -struct afb_apiset *afb_apiset_get_subset(struct afb_apiset *set) +struct afb_apiset *afb_apiset_subset_get(struct afb_apiset *set) { return set->subset; } @@ -165,9 +189,14 @@ struct afb_apiset *afb_apiset_get_subset(struct afb_apiset *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) +void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset) { - struct afb_apiset *tmp = set->subset; + struct afb_apiset *tmp; + if (subset == set) { + /* avoid infinite loop */ + subset = NULL; + } + tmp = set->subset; set->subset = afb_apiset_addref(subset); afb_apiset_unref(tmp); } @@ -179,7 +208,6 @@ void afb_apiset_set_subset(struct afb_apiset *set, struct afb_apiset *subset) * @param api the api * @returns 0 in case of success or -1 in case * of error with errno set: - * - EINVAL if name isn't valid * - EEXIST if name already registered * - ENOMEM when out of memory */ @@ -188,13 +216,6 @@ 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_api_is_valid_name(name)) { - ERROR("invalid api name forbidden (name is '%s')", name); - errno = EINVAL; - goto error; - } - /* check previously existing plugin */ for (i = 0 ; i < set->count ; i++) { c = strcasecmp(set->apis[i].name, name); @@ -223,6 +244,7 @@ int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api api) memmove(apis + 1, apis, ((unsigned)(set->count - i)) * sizeof *apis); /* record the plugin */ + apis->status = -1; apis->api = api; apis->name = name; set->count++; @@ -235,6 +257,12 @@ error: return -1; } +/** + * Delete from the 'set' the api of 'name'. + * @param set the set to be changed + * @param name the name of the API to remove + * @return 0 in case of success or -1 in case where the API doesn't exist. + */ int afb_apiset_del(struct afb_apiset *set, const char *name) { int i, c; @@ -257,7 +285,14 @@ int afb_apiset_del(struct afb_apiset *set, const char *name) return -1; } -int afb_apiset_get(struct afb_apiset *set, const char *name, struct afb_api *api) +/** + * Get from the 'set' the API of 'name' in 'api' + * @param set the set of API + * @param name the name of the API to get + * @param api the structure where to store data about the API of name + * @return 0 in case of success or -1 in case of error + */ +int afb_apiset_lookup(struct afb_apiset *set, const char *name, struct afb_api *api) { const struct api_desc *i; @@ -266,13 +301,104 @@ int afb_apiset_get(struct afb_apiset *set, const char *name, struct afb_api *api *api = i->api; return 0; } - if (set->subset) - return afb_apiset_get(set->subset, name, api); errno = ENOENT; return -1; } +/** + * Get from the 'set' the API of 'name' in 'api' with fallback to subset or default api + * @param set the set of API + * @param name the name of the API to get + * @param api the structure where to store data about the API of name + * @return 0 in case of success or -1 in case of error + */ +static struct api_desc *get_api(struct afb_apiset *set, const char *name) +{ + struct api_desc *i = search(set, name); + return i || !set->subset ? i : get_api(set->subset, name); +} + +/** + * Get from the 'set' the API of 'name' in 'api' with fallback to subset or default api + * @param set the set of API + * @param name the name of the API to get + * @param api the structure where to store data about the API of name + * @return 0 in case of success or -1 in case of error + */ +int afb_apiset_get(struct afb_apiset *set, const char *name, struct afb_api *api) +{ + const struct api_desc *i; + + i = get_api(set, name); + if (!i) { + errno = ENOENT; + return -1; + } + *api = i->api; + return 0; +} + +/** + * Starts the service 'api'. + * @param api the api + * @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 + */ +static int start_api(struct afb_apiset *set, struct api_desc *api, int share_session, int onneed) +{ + int rc; + + if (api->status == 0) + return 0; + else if (api->status > 0) { + errno = api->status; + return -1; + } + + NOTICE("API %s starting...", api->name); + if (api->api.itf->service_start) { + api->status = EBUSY; + rc = api->api.itf->service_start(api->api.closure, share_session, onneed, set); + if (rc < 0) { + api->status = errno ?: ECANCELED; + ERROR("The api %s failed to start (%d)", api->name, rc); + return -1; + } + } else if (!onneed) { + /* already started: it is an error */ + ERROR("The api %s is not a startable service", api->name); + api->status = EINVAL; + return -1; + } + NOTICE("API %s started", api->name); + api->status = 0; + return 0; +} + +/** + * Get from the 'set' the API of 'name' in 'api' with fallback to subset or default api + * @param set the set of API + * @param name the name of the API to get + * @param api the structure where to store data about the API of name + * @return 0 in case of success or -1 in case of error + */ +int afb_apiset_get_started(struct afb_apiset *set, const char *name, struct afb_api *api) +{ + struct api_desc *i; + + i = get_api(set, name); + if (!i) { + errno = ENOENT; + return -1; + } + *api = i->api; + return i->status ? start_api(set, i, 1, 1) : 0; +} + /** * Starts a service by its 'api' name. * @param set the api set @@ -285,7 +411,7 @@ int afb_apiset_get(struct afb_apiset *set, const char *name, struct afb_api *api */ int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share_session, int onneed) { - const struct api_desc *a; + struct api_desc *a; a = search(set, name); if (!a) { @@ -294,16 +420,7 @@ int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share return -1; } - if (a->api.itf->service_start) - return a->api.itf->service_start(a->api.closure, share_session, onneed, set); - - if (onneed) - return 0; - - /* already started: it is an error */ - ERROR("The api %s is not a startable service", name); - errno = EINVAL; - return -1; + return start_api(set, a, share_session, onneed); } /** @@ -316,19 +433,18 @@ int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share int afb_apiset_start_all_services(struct afb_apiset *set, int share_session) { int rc; - const struct api_desc *i, *e; + struct api_desc *i, *e; 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; - } + rc = start_api(set, i, share_session, 1); + if (rc < 0) + return rc; i++; } - return 0; + + return set->subset ? afb_apiset_start_all_services(set->subset, share_session) : 0; } /** @@ -392,7 +508,7 @@ int afb_apiset_get_verbosity(struct afb_apiset *set, const char *name) return -1; } if (!i->api.itf->get_verbosity) - return 0; + return verbosity; return i->api.itf->get_verbosity(i->api.closure); } @@ -427,77 +543,17 @@ const char **afb_apiset_get_names(struct afb_apiset *set) 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. + * Enumerate the api names to a callback. * @param set the api set - * @param xreq the request to dispatch + * @param callback the function to call for each name + * @param closure the closure for the callback */ -void afb_apiset_call(struct afb_apiset *set, struct afb_xreq *xreq) +void afb_apiset_enum(struct afb_apiset *set, void (*callback)(struct afb_apiset *set, const char *name, void *closure), void *closure) { - int rc; + int i; - 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); - } + for (i = 0 ; i < set->count ; i++) + callback(set, set->apis[i].name, closure); } -#endif -