On 23 February 2017 at 04:57, Bill Fischofer <bill.fischo...@linaro.org> wrote:
> > > On Wed, Feb 22, 2017 at 6:55 AM, Christophe Milard < > christophe.mil...@linaro.org> wrote: > >> The functions to register and probe enumerator classes are added. >> >> Signed-off-by: Christophe Milard <christophe.mil...@linaro.org> >> --- >> platform/linux-generic/Makefile.am | 1 + >> platform/linux-generic/_modules.c | 4 + >> platform/linux-generic/drv_driver.c | 212 >> ++++++++++++++++++++- >> .../linux-generic/include/drv_driver_internal.h | 22 +++ >> platform/linux-generic/include/odp_internal.h | 5 + >> platform/linux-generic/odp_init.c | 21 +- >> 6 files changed, 260 insertions(+), 5 deletions(-) >> create mode 100644 platform/linux-generic/include/drv_driver_internal.h >> >> diff --git a/platform/linux-generic/Makefile.am >> b/platform/linux-generic/Makefile.am >> index 66ff53d..b7d1b1a 100644 >> --- a/platform/linux-generic/Makefile.am >> +++ b/platform/linux-generic/Makefile.am >> @@ -133,6 +133,7 @@ noinst_HEADERS = \ >> ${srcdir}/include/_ishm_internal.h \ >> ${srcdir}/include/_ishmphy_internal.h \ >> ${srcdir}/include/_ishmpool_internal.h \ >> + ${srcdir}/include/drv_driver_internal.h\ >> ${srcdir}/include/odp_align_internal.h \ >> ${srcdir}/include/odp_atomic_internal.h \ >> ${srcdir}/include/odp_buffer_inlines.h \ >> diff --git a/platform/linux-generic/_modules.c >> b/platform/linux-generic/_modules.c >> index 6bb854e..b23c81f 100644 >> --- a/platform/linux-generic/_modules.c >> +++ b/platform/linux-generic/_modules.c >> @@ -9,6 +9,7 @@ >> #include <odp/api/std_types.h> >> #include <odp/api/debug.h> >> #include <odp_debug_internal.h> >> +#include <drv_driver_internal.h> >> #include <libconfig.h> >> #include <dlfcn.h> >> >> @@ -40,6 +41,9 @@ static int load_modules(void) >> ODP_DBG("module %s loaded.\n", module_name); >> } >> >> + /* give a chance top the driver interface to probe for new >> things: */ >> > > Garbled phrasing. I assume the intent here was "Give the top driver > interface a chance to probe for new things" ? > > >> + _odpdrv_driver_probe_drv_items(); >> + >> return 0; >> } >> >> diff --git a/platform/linux-generic/drv_driver.c >> b/platform/linux-generic/drv_driver.c >> index 529da48..50956a7 100644 >> --- a/platform/linux-generic/drv_driver.c >> +++ b/platform/linux-generic/drv_driver.c >> @@ -4,20 +4,131 @@ >> * SPDX-License-Identifier: BSD-3-Clause >> */ >> >> +#include <string.h> >> + >> #include <odp_config_internal.h> >> +#include <_ishmpool_internal.h> >> >> #include <odp/api/std_types.h> >> #include <odp/api/debug.h> >> +#include <odp/api/rwlock_recursive.h> >> #include <odp/drv/driver.h> >> +#include <odp/drv/spec/driver.h> >> #include <odp_debug_internal.h> >> +#include <drv_driver_internal.h> >> + >> +static enum {UNDONE, IN_PROGRESS, DONE} init_global_status; >> + >> +/* pool from which different list elements are alocated: */ >> +#define ELT_POOL_SIZE (1 << 20) /* 1Mb */ >> +static _odp_ishm_pool_t *list_elt_pool; >> + >> +typedef struct _odpdrv_enumr_class_s _odpdrv_enumr_class_t; >> + >> +/* an enumerator class (list element) */ >> +struct _odpdrv_enumr_class_s { >> + odpdrv_enumr_class_param_t param; >> + int probed; >> + _odp_ishm_pool_t *pool; >> + struct _odpdrv_enumr_class_s *next; >> +}; >> + >> +/* the enumerator class list: */ >> +typedef struct _odpdrv_enumr_class_lst_t { >> + odp_rwlock_recursive_t lock; >> + _odpdrv_enumr_class_t *head; >> +} _odpdrv_enumr_class_lst_t; >> +static struct _odpdrv_enumr_class_lst_t enumr_class_lst; >> + >> +/* some driver elements (such as enumeraor classes, drivers, devio) may >> + * register before init_global and init_local complete. Mutex will fail >> + * in this cases but should be used later on. >> + * These functions disable the usage of Mutex while it is global init >> i.e. >> + * while single threaded*/ >> > > I don't understand why these tests are needed. You've put the driver init > stuff at the end of odp_init_global() so all the other machinery is > available to you at this point. So these guards seem unnecessary. > Is this flag solving problem described as "driver probe time...", which to cover both statically and dynamically linked modules' situation? at the very beginning: statically linked plugin modules __constructor__ (register) ... odp_init_global(): _odpdrv_driver_init_global(): _odp_modules_init_global(): dynamically linked plugin modules __constructor__ (register), and kick the probing ... One possible alternative may be creating two lists: registered_list: ring-buffer based, no system intialization required, all plugin modules register by only adding themselves into this list but no further operations. (malloc, shm, etc). probed_list: lock protected, probing will actually walk through registered_list and do initialization like shm allocate and then move them into probed list. In this way: eliminate this flag and also the probed flag in structure? > > >> +static void enumr_class_list_read_lock(void) >> +{ >> + if (init_global_status == DONE) >> + odp_rwlock_recursive_read_lock(&enumr_class_lst.lock); >> +} >> + >> +static void enumr_class_list_read_unlock(void) >> +{ >> + if (init_global_status == DONE) >> + odp_rwlock_recursive_read_unlock(&enumr_class_lst.lock); >> +} >> + >> +static void enumr_class_list_write_lock(void) >> +{ >> + if (init_global_status == DONE) >> + odp_rwlock_recursive_write_lock(&enumr_class_lst.lock); >> +} >> + >> +static void enumr_class_list_write_unlock(void) >> +{ >> + if (init_global_status == DONE) >> + odp_rwlock_recursive_write_unlock(&enumr_class_lst.lock); >> +} >> + >> >> odpdrv_enumr_class_t odpdrv_enumr_class_register(od >> pdrv_enumr_class_param_t >> *param) >> { >> - ODP_ERR("NOT Supported yet! Enumerator Class %s Registration!\n.", >> - param->name); >> + _odpdrv_enumr_class_t *enumr_c; >> >> - return ODPDRV_ENUMR_CLASS_INVALID; >> + /* parse the list of already registered enumerator class to make >> + * sure no enumerator with identical name already exists: >> + */ >> + enumr_class_list_read_lock(); >> + enumr_c = enumr_class_lst.head; >> + while (enumr_c) { >> + if (strncmp(param->name, enumr_c->param.name, >> + ODPDRV_NAME_SIZE) == 0) { >> + ODP_ERR("enumerator class %s already exists!\n", >> + param->name); >> + enumr_class_list_read_unlock(); >> + return ODPDRV_ENUMR_CLASS_INVALID; >> + } >> + enumr_c = enumr_c->next; >> + } >> + enumr_class_list_read_unlock(); >> + >> + /* allocate memory for the new enumerator class: >> + * If init_global has not been done yet, then, we cannot allocate >> + * from any _ishm pool (ishm has not even been initialised at this >> + * stage...this happens when statically linked enumerator classes >> + * register: their __constructor__ function is run before main() >> + * is called). But any malloc performed here(before init_global) >> + * will be inherited by any odpthreads (process or pthreads) as we >> + * are still running in the ODP instantiation processes and all >> + * other processes are guaranteed to be descendent of this one... >> + * If init_global has been done, then we allocate from the _ishm >> pool >> + * to guarantee visibility from any ODP thread. >> + */ >> + >> + if (init_global_status == UNDONE) { >> + enumr_c = malloc(sizeof(_odpdrv_enumr_class_t)); >> + if (!enumr_c) >> + return ODPDRV_ENUMR_CLASS_INVALID; >> + enumr_c->pool = NULL; >> + } else { >> + enumr_c = _odp_ishm_pool_alloc(list_elt_pool, >> + >> sizeof(_odpdrv_enumr_class_t)); >> + if (!enumr_c) { >> + ODP_ERR("_odp_ishm_pool_alloc failed!\n"); >> + return ODPDRV_ENUMR_CLASS_INVALID; >> + } >> + enumr_c->pool = list_elt_pool; >> + } >> + >> + /* save init parameters and insert enumerator class in list */ >> + enumr_c->param = *param; >> + enumr_c->probed = 0; >> + enumr_class_list_write_lock(); >> + enumr_c->next = enumr_class_lst.head; >> + enumr_class_lst.head = enumr_c; >> + enumr_class_list_write_unlock(); >> + >> + return (odpdrv_enumr_class_t)enumr_c; >> } >> >> odpdrv_enumr_t odpdrv_enumr_register(odpdrv_enumr_param_t *param) >> @@ -57,8 +168,101 @@ odpdrv_driver_t >> odpdrv_driver_register(odpdrv_driver_param_t >> *param) >> return ODPDRV_DRIVER_INVALID; >> } >> >> +/* the following function is called each time probing is needed, i.e. >> + * at init or after loading a new module as a module can be anything, >> + * including enumerators or drivers */ >> +void _odpdrv_driver_probe_drv_items(void) >> +{ >> + _odpdrv_enumr_class_t *enumr_c; >> + >> + /* probe unprobed enumerators: */ >> + enumr_class_list_read_lock(); >> + enumr_c = enumr_class_lst.head; >> > > Where is enumr_class_lst.head initialized? You've initialized the lock > part of this struct in _odpdrv_init_global() but not the head. So this may > contain uninitialized / stale values from a previous ODP instance. > > >> + while (enumr_c) { >> + if (!enumr_c->probed) { >> + enumr_c->param.probe(); >> + enumr_c->probed = 1; >> + } >> + enumr_c = enumr_c->next; >> + } >> + enumr_class_list_read_unlock(); >> +} >> + >> int odpdrv_print_all(void) >> { >> - ODP_ERR("odpdrv_print_all not Supported yet!\n."); >> + _odpdrv_enumr_class_t *enumr_c; >> + >> + /* we cannot use ODP_DBG before ODP init... */ >> + if (init_global_status == UNDONE) >> + return 0; >> + >> + ODP_DBG("ODP Driver status:\n"); >> + >> + /* print the list of registered enumerator classes: */ >> + enumr_class_list_read_lock(); >> + enumr_c = enumr_class_lst.head; >> + ODP_DBG("The following enumerator classes have been >> registered:\n"); >> + while (enumr_c) { >> + ODP_DBG(" class: %s\n", enumr_c->param.name); >> + enumr_c = enumr_c->next; >> + } >> + enumr_class_list_read_unlock(); >> + return 0; >> +} >> + >> +int _odpdrv_driver_init_global(void) >> +{ >> + /* create a memory pool to for list elements: */ >> + list_elt_pool = _odp_ishm_pool_create(NULL, ELT_POOL_SIZE, >> + 0, ELT_POOL_SIZE, 0); >> + >> + /* remember that init global is being done so the further list >> allocs >> + * are made from the list_elt_pool: */ >> + init_global_status = IN_PROGRESS; >> + >> + /* from now, we want to ensure mutex on the list: init lock: */ >> + odp_rwlock_recursive_init(&enumr_class_lst.lock); >> + >> + /* probe things... */ >> + _odpdrv_driver_probe_drv_items(); >> + >> + return 0; >> +} >> + >> +int _odpdrv_driver_init_local(void) >> +{ >> + /* remember that init global is done, so list mutexes are used >> from >> + * now */ >> + init_global_status = DONE; >> > > Not clear what this does. Also, having the init() function manipulate a > global variable is not good form. The idea behind the init_local() calls is > that these routines do thread-local initialization. Remember this routine > may be called in parallel from multiple threads if the app is launching > threads since each of them is going to be calling odp_init_local(). > > >> + return 0; >> +} >> + >> +int _odpdrv_driver_term_global(void) >> +{ >> + _odpdrv_enumr_class_t *enumr_c; >> + >> + if (init_global_status == UNDONE) >> + return 0; >> > > I'm not sure what this guard is protecting against. If an app calls > odp_term_global() before it calls odp_init_global() that is an application > programming error and we need not worry about such things. > > >> + >> + /* remove all enumerator classes which are registered: */ >> + enumr_class_list_write_lock(); >> + while (enumr_class_lst.head) { >> + enumr_c = enumr_class_lst.head; >> + if (enumr_c->param.remove) { /* run remove callback, if >> any */ >> + if (enumr_c->param.remove()) >> + ODP_ERR("Enumerator class %s removal >> failed.\n", >> + enumr_c->param.name); >> + } >> + enumr_class_lst.head = enumr_c->next; >> + if (enumr_c->pool) >> + _odp_ishm_pool_free(list_elt_pool, enumr_c); >> + else >> + free(enumr_c); >> + } >> + enumr_class_list_write_unlock(); >> + >> + /* destroy the list element pool: */ >> + _odp_ishm_pool_destroy(list_elt_pool); >> + >> return 0; >> } >> diff --git a/platform/linux-generic/include/drv_driver_internal.h >> b/platform/linux-generic/include/drv_driver_internal.h >> new file mode 100644 >> index 0000000..eb06c1b >> --- /dev/null >> +++ b/platform/linux-generic/include/drv_driver_internal.h >> @@ -0,0 +1,22 @@ >> +/* Copyright (c) 2017, Linaro Limited >> + * All rights reserved. >> + * >> + * SPDX-License-Identifier: BSD-3-Clause >> + */ >> + >> +#ifndef DRV_DRIVER_INTERNAL_H_ >> +#define DRV_DRIVER_INTERNAL_H_ >> + >> +#ifdef __cplusplus >> +extern "C" { >> +#endif >> + >> +#include <sys/types.h> >> + >> +void _odpdrv_driver_probe_drv_items(void); >> + >> +#ifdef __cplusplus >> +} >> +#endif >> + >> +#endif >> diff --git a/platform/linux-generic/include/odp_internal.h >> b/platform/linux-generic/include/odp_internal.h >> index 05c8a42..1760b56 100644 >> --- a/platform/linux-generic/include/odp_internal.h >> +++ b/platform/linux-generic/include/odp_internal.h >> @@ -71,6 +71,7 @@ enum init_stage { >> CLASSIFICATION_INIT, >> TRAFFIC_MNGR_INIT, >> NAME_TABLE_INIT, >> + DRIVER_INIT, >> MODULES_INIT, >> ALL_INIT /* All init stages completed */ >> }; >> @@ -130,6 +131,10 @@ int _odp_ishm_init_local(void); >> int _odp_ishm_term_global(void); >> int _odp_ishm_term_local(void); >> >> +int _odpdrv_driver_init_global(void); >> +int _odpdrv_driver_init_local(void); >> +int _odpdrv_driver_term_global(void); >> + >> int _odp_modules_init_global(void); >> >> int cpuinfo_parser(FILE *file, system_info_t *sysinfo); >> diff --git a/platform/linux-generic/odp_init.c >> b/platform/linux-generic/odp_init.c >> index 685e02f..c59cc28 100644 >> --- a/platform/linux-generic/odp_init.c >> +++ b/platform/linux-generic/odp_init.c >> @@ -266,6 +266,12 @@ int odp_init_global(odp_instance_t *instance, >> } >> stage = NAME_TABLE_INIT; >> >> + if (_odpdrv_driver_init_global()) { >> + ODP_ERR("ODP drivers init failed\n"); >> + goto init_failed; >> + } >> + stage = DRIVER_INIT; >> + >> if (_odp_modules_init_global()) { >> ODP_ERR("ODP modules init failed\n"); >> goto init_failed; >> @@ -296,6 +302,13 @@ int _odp_term_global(enum init_stage stage) >> switch (stage) { >> case ALL_INIT: >> case MODULES_INIT: >> + case DRIVER_INIT: >> + if (_odpdrv_driver_term_global()) { >> + ODP_ERR("driver term failed.\n"); >> + rc = -1; >> + } >> + /* Fall through */ >> + >> case NAME_TABLE_INIT: >> if (_odp_int_name_tbl_term_global()) { >> ODP_ERR("Name table term failed.\n"); >> @@ -445,7 +458,13 @@ int odp_init_local(odp_instance_t instance, >> odp_thread_type_t thr_type) >> ODP_ERR("ODP schedule local init failed.\n"); >> goto init_fail; >> } >> - /* stage = SCHED_INIT; */ >> + stage = SCHED_INIT; >> + >> + if (_odpdrv_driver_init_local()) { >> + ODP_ERR("ODP driver local init failed.\n"); >> + goto init_fail; >> + } >> + /* stage = DRIVER_INIT; */ >> >> return 0; >> >> -- >> 2.7.4 >> >> >