[asterisk-commits] dlee: branch dlee/ASTERISK-22296 r397658 - in /team/dlee/ASTERISK-22296: incl...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Aug 26 12:37:50 CDT 2013
Author: dlee
Date: Mon Aug 26 12:37:48 2013
New Revision: 397658
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=397658
Log:
Even less magic
Modified:
team/dlee/ASTERISK-22296/include/asterisk/optional_api.h
team/dlee/ASTERISK-22296/main/asterisk.c
team/dlee/ASTERISK-22296/main/loader.c
team/dlee/ASTERISK-22296/main/optional_api.c
Modified: team/dlee/ASTERISK-22296/include/asterisk/optional_api.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/include/asterisk/optional_api.h?view=diff&rev=397658&r1=397657&r2=397658
==============================================================================
--- team/dlee/ASTERISK-22296/include/asterisk/optional_api.h (original)
+++ team/dlee/ASTERISK-22296/include/asterisk/optional_api.h Mon Aug 26 12:37:48 2013
@@ -116,8 +116,7 @@
void ast_optional_api_unuse(const char *symname, ast_optional_fn *function,
const char *module);
-void optional_api_onload(void);
-void optional_api_onunload(void);
+void optional_api_cleanup(void);
#define AST_OPTIONAL_API_NAME(name) __##name
Modified: team/dlee/ASTERISK-22296/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/main/asterisk.c?view=diff&rev=397658&r1=397657&r2=397658
==============================================================================
--- team/dlee/ASTERISK-22296/main/asterisk.c (original)
+++ team/dlee/ASTERISK-22296/main/asterisk.c Mon Aug 26 12:37:48 2013
@@ -246,6 +246,7 @@
#include "asterisk/stasis_endpoints.h"
#include "asterisk/stasis_system.h"
#include "asterisk/security_events.h"
+#include "asterisk/optional_api.h"
#include "../defaults.h"
@@ -4133,6 +4134,8 @@
ast_el_read_history(filename);
}
+ ast_register_cleanup(optional_api_cleanup);
+
ast_json_init();
ast_ulaw_init();
ast_alaw_init();
Modified: team/dlee/ASTERISK-22296/main/loader.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/main/loader.c?view=diff&rev=397658&r1=397657&r2=397658
==============================================================================
--- team/dlee/ASTERISK-22296/main/loader.c (original)
+++ team/dlee/ASTERISK-22296/main/loader.c Mon Aug 26 12:37:48 2013
@@ -57,7 +57,6 @@
#include "asterisk/app.h"
#include "asterisk/test.h"
#include "asterisk/sounds_index.h"
-#include "asterisk/optional_api.h"
#include <dlfcn.h>
@@ -413,11 +412,7 @@
dereference it */
if (lib)
- while (!dlclose(lib));
-
- /* If mod offered an optional API, it's not there any more!
- * Scan optional_api users for potential unloads. */
- optional_api_onunload();
+ dlclose(lib);
}
static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap, int required);
@@ -466,7 +461,7 @@
if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
/* no, it did not, so close it and return */
- while (!dlclose(lib));
+ dlclose(lib);
/* note that the module's destructor will call ast_module_unregister(),
which will free the structure we allocated in resource_being_loaded */
return NULL;
@@ -477,32 +472,11 @@
/* if we are being asked only to load modules that provide global symbols,
and this one does not, then close it and return */
if (global_symbols_only && !wants_global) {
- while (!dlclose(lib));
+ dlclose(lib);
return NULL;
}
- /* This section is a workaround for a gcc 4.1 bug that has already been
- * fixed in later versions. Unfortunately, some distributions, such as
- * RHEL/CentOS 5, distribute gcc 4.1, so we're stuck with having to deal
- * with this issue. This basically ensures that optional_api modules are
- * loaded before any module which requires their functionality. */
-#if !defined(HAVE_ATTRIBUTE_weak_import) && !defined(HAVE_ATTRIBUTE_weakref)
- if (!ast_strlen_zero(mod->info->nonoptreq)) {
- /* Force any required dependencies to load */
- char *each, *required_resource = ast_strdupa(mod->info->nonoptreq);
- while ((each = strsep(&required_resource, ","))) {
- struct ast_module *dependency;
- each = ast_strip(each);
- dependency = find_resource(each, 0);
- /* Is it already loaded? */
- if (!dependency) {
- load_resource(each, global_symbols_only, resource_heap, 1);
- }
- }
- }
-#endif
-
- while (!dlclose(lib));
+ dlclose(lib);
resource_being_loaded = NULL;
/* start the load process again */
@@ -525,9 +499,6 @@
AST_LIST_LAST(&module_list)->lib = lib;
resource_being_loaded = NULL;
-
- /* The module may offer up an optional API another module wants. */
- optional_api_onload();
return AST_LIST_LAST(&module_list);
}
Modified: team/dlee/ASTERISK-22296/main/optional_api.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/main/optional_api.c?view=diff&rev=397658&r1=397657&r2=397658
==============================================================================
--- team/dlee/ASTERISK-22296/main/optional_api.c (original)
+++ team/dlee/ASTERISK-22296/main/optional_api.c Mon Aug 26 12:37:48 2013
@@ -20,10 +20,17 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-#include "asterisk/astobj2.h"
-#include "asterisk/lock.h"
#include "asterisk/optional_api.h"
#include "asterisk/utils.h"
+
+/*
+ * \file Optional API innards.
+ *
+ * The calls to ast_optional_api_*() happen implicitly from \c __constructor__
+ * calls which are defined in header files. This means that some number of them
+ * happen before main() is called. This makes calling into any other Asterisk
+ * API a dangerous thing, because we don't know if they've been initialized yet.
+ */
struct optional_api_user {
ast_optional_fn *optional_ref;
@@ -33,56 +40,32 @@
struct optional_api {
ast_optional_fn impl;
- struct ao2_container *users;
+ struct optional_api_user **users;
+ size_t users_maxlen;
+ size_t users_len;
char symname[];
};
-static void optional_api_dtor(void *obj)
-{
- struct optional_api *api = obj;
-
- ao2_cleanup(api->users);
+static void optional_api_free(struct optional_api *api)
+{
+ free(api->users);
api->users = NULL;
-}
-
-static struct optional_api *optional_api_create(const char *symname)
-{
- RAII_VAR(struct optional_api *, api, NULL, ao2_cleanup);
- size_t size;
-
- if (!symname) {
- return NULL;
- }
- size = sizeof(*api) + strlen(symname) + 1;
-
- api = ao2_alloc_options(size, optional_api_dtor, OBJ_NOLOCK);
- if (!api) {
- return NULL;
- }
-
- api->users = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
- NULL, NULL);
- if (!api->users) {
- return NULL;
- }
-
- return ao2_bump(api);
-}
-
-static void optional_api_user_dtor(void *obj) {
- struct optional_api_user *user = obj;
-
+ free(api);
+}
+
+static void optional_api_user_free(struct optional_api_user *user)
+{
ast_assert(*user->optional_ref == user->stub);
+ free(user);
}
static struct optional_api_user *optional_api_user_create(
ast_optional_fn *optional_ref, ast_optional_fn stub, const char *module)
{
- RAII_VAR(struct optional_api_user *, user, NULL, ao2_cleanup);
+ struct optional_api_user *user;
size_t size = sizeof(*user) + strlen(module) + 1;
- user = ao2_alloc_options(size, optional_api_user_dtor,
- AO2_ALLOC_OPT_LOCK_NOLOCK);
+ user = calloc(1, size);
if (!user) {
return NULL;
}
@@ -92,151 +75,146 @@
/* safe strcpy */
strcpy(user->module, module);
- return ao2_bump(user);
-
-}
-
-static struct ao2_container *_apis;
-
-static int optional_api_sort(const void *obj_left, const void *obj_right,
- int flags)
-{
- const struct optional_api *object_left = obj_left;
- const struct optional_api *object_right = obj_right;
- const char *right_key = obj_right;
- int cmp;
-
- switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
- case OBJ_POINTER:
- right_key = object_right->symname;
- /* Fall through */
- case OBJ_KEY:
- cmp = strcmp(object_left->symname, right_key);
- break;
- case OBJ_PARTIAL_KEY:
- /*
- * We could also use a partial key struct containing a length
- * so strlen() does not get called for every comparison instead.
- */
- cmp = strncmp(object_left->symname, right_key, strlen(right_key));
- break;
- default:
- /* Sort can only work on something with a full or partial key. */
- ast_assert(0);
- cmp = 0;
- break;
- }
- return cmp;
-}
-
-static void optional_api_cleanup(void)
-{
- ao2_cleanup(_apis);
- _apis = NULL;
-}
-
-static struct ao2_container *get_apis(void)
-{
- /* optional_api calls can happen before main() starts, or during
- * dlopen() as modules are loaded. These are (or at least should be)
- * synchronized, so no lock is needed here.
- *
- * Which is good, because there's no consistent way to build a global
- * mutex that we know will be initialized before get_apis() is first
- * called.
- */
- if (_apis) {
- return _apis;
- }
-
- ast_register_cleanup(optional_api_cleanup);
-
- _apis = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX,
- AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, optional_api_sort,
- NULL);
- if (!_apis) {
- ast_log(LOG_ERROR, "Failed to allocate apis\n");
- ast_assert(0);
+ return user;
+}
+
+struct {
+ struct optional_api **list;
+ size_t maxlen;
+ size_t len;
+} apis;
+
+/* optional_api may run before main(), so it can't register its own cleanup.
+ * This gets registered in main().
+ */
+void optional_api_cleanup(void)
+{
+ size_t i;
+
+ for (i = 0; i < apis.len; ++i) {
+ optional_api_free(apis.list[i]);
+ }
+ apis.len = 0;
+ free(apis.list);
+ apis.list = NULL;
+ apis.maxlen = 0;
+}
+
+static struct optional_api *get_api(const char *symname)
+{
+ struct optional_api *api;
+ size_t size;
+ size_t i;
+
+ /* Find one, if we already have it */
+ for (i = 0; i < apis.len; ++i) {
+ if (strcmp(symname, apis.list[i]->symname) == 0) {
+ return apis.list[i];
+ }
+ }
+
+ /* API not found. Build one */
+ ast_verb(6, "%s: building api object\n", symname);
+ size = sizeof(*api) + strlen(symname) + 1;
+ api = calloc(1, size);
+ if (!api) {
+ ast_log(LOG_ERROR, "Failed to allocate api\n");
return NULL;
}
- return 0;
+ /* safe strcpy */
+ strcpy(api->symname, symname);
+
+ /* Grow the list, if needed */
+ if (apis.len + 1 > apis.maxlen) {
+ size_t new_maxlen = apis.maxlen ? 2 * apis.maxlen : 1;
+ struct optional_api **new_list =
+ realloc(apis.list, new_maxlen * sizeof(*new_list));
+
+ if (!new_list) {
+ ast_free(api);
+ ast_log(LOG_ERROR, "Failed to allocate api list\n");
+ return NULL;
+ }
+
+ apis.maxlen = new_maxlen;
+ apis.list = new_list;
+ }
+
+ apis.list[apis.len++] = api;
+
+ return api;
}
static void optional_api_user_relink(struct optional_api_user *user,
struct optional_api *api)
{
- if (api->impl) {
- ast_verb(4, "%s: linking %s\n", api->symname, user->module);
+ if (api->impl && *user->optional_ref != api->impl) {
+ ast_verb(4, "%s: linking for %s\n", api->symname, user->module);
*user->optional_ref = api->impl;
- } else {
- ast_verb(4, "%s: stubbing %s\n", api->symname, user->module);
+ } else if (!api->impl && *user->optional_ref != user->stub) {
+ ast_verb(4, "%s: stubbing for %s\n", api->symname,
+ user->module);
*user->optional_ref = user->stub;
}
}
-static int optional_api_user_relink_cb(void *obj, void *arg, int flags)
-{
- struct optional_api_user *user = obj;
- struct optional_api *api = arg;
-
- optional_api_user_relink(user, api);
- return 0;
+static void optional_api_set_impl(struct optional_api *api,
+ ast_optional_fn impl)
+{
+ size_t i;
+
+ api->impl = impl;
+
+ /* re-link all users */
+ for (i = 0; i < api->users_len; ++i) {
+ optional_api_user_relink(api->users[i], api);
+ }
}
void ast_optional_api_provide(const char *symname, ast_optional_fn impl)
{
- RAII_VAR(struct optional_api *, api, NULL, ao2_cleanup);
- SCOPED_AO2LOCK(lock, get_apis());
+ struct optional_api *api;
ast_verb(4, "%s: providing\n", symname);
- api = ao2_find(get_apis(), symname, OBJ_NOLOCK);
- if (!api) {
- api = optional_api_create(symname);
- if (!api) {
- ast_log(LOG_ERROR, "%s: Allocation failed\n", symname);
- return;
- }
- }
-
- api->impl = impl;
- ao2_callback(api->users, OBJ_NODATA, optional_api_user_relink_cb, impl);
+ api = get_api(symname);
+ if (!api) {
+ ast_log(LOG_ERROR, "%s: Allocation failed\n", symname);
+ return;
+ }
+
+ optional_api_set_impl(api, impl);
}
void ast_optional_api_unprovide(const char *symname, ast_optional_fn impl)
{
- RAII_VAR(struct optional_api *, api, NULL, ao2_cleanup);
- SCOPED_AO2LOCK(lock, get_apis());
+ struct optional_api *api;
ast_verb(4, "%s: un-providing\n", symname);
- api = ao2_find(get_apis(), symname, OBJ_NOLOCK);
+ api = get_api(symname);
if (!api) {
ast_log(LOG_ERROR, "%s: Could not find api\n", symname);
return;
}
- api->impl = 0;
- ao2_callback(api->users, OBJ_NODATA, optional_api_user_relink_cb, impl);
+ optional_api_set_impl(api, 0);
}
void ast_optional_api_use(const char *symname, ast_optional_fn *optional_ref,
ast_optional_fn stub, const char *module)
{
- RAII_VAR(struct optional_api_user *, user, NULL, ao2_cleanup);
- RAII_VAR(struct optional_api *, api, NULL, ao2_cleanup);
- SCOPED_AO2LOCK(lock, get_apis());
+ struct optional_api_user *user;
+ struct optional_api *api;
+
ast_verb(4, "%s: use by %s\n", symname, module);
- api = ao2_find(get_apis(), symname, OBJ_NOLOCK);
- if (!api) {
- api = optional_api_create(symname);
- if (!api) {
- ast_log(LOG_ERROR, "%s: Allocation failed\n", symname);
- return;
- }
+ api = get_api(symname);
+ if (!api) {
+ ast_log(LOG_ERROR, "%s: Allocation failed\n", symname);
+ return;
}
user = optional_api_user_create(optional_ref, stub, module);
@@ -245,37 +223,59 @@
return;
}
+ /* Add user to the API */
+ if (api->users_len + 1 > api->users_maxlen) {
+ size_t new_maxlen = api->users_maxlen ?
+ 2 * api->users_maxlen : 1;
+ struct optional_api_user **new_list =
+ realloc(api->users, new_maxlen * sizeof(*new_list));
+
+ if (!new_list) {
+ ast_free(user);
+ ast_log(LOG_ERROR, "Failed to allocate api list\n");
+ /* Called during module load; no way to return failure.
+ * assert false and hope for the best */
+ ast_assert(0);
+ return;
+ }
+
+ api->users_maxlen = new_maxlen;
+ api->users = new_list;
+ }
+
+ api->users[api->users_len++] = user;
+
optional_api_user_relink(user, api);
-}
-
-static int optional_api_user_find_and_unuse(void *obj, void *arg, int flags)
-{
- struct optional_api_user *user = obj;
- ast_optional_fn *optional_ref = arg;
-
- if (user->optional_ref != optional_ref) {
- return 0;
- }
-
- ast_verb(4, " Stubbing %s\n", user->module);
- *user->optional_ref = user->stub;
- return CMP_MATCH | CMP_STOP;
}
void ast_optional_api_unuse(const char *symname, ast_optional_fn *optional_ref,
const char *module)
{
- RAII_VAR(struct optional_api *, api, NULL, ao2_cleanup);
- SCOPED_AO2LOCK(lock, get_apis());
+ struct optional_api *api;
+ size_t i;
ast_verb(4, "%s: un-use by %s\n", symname, module);
- api = ao2_find(get_apis(), symname, OBJ_NOLOCK);
+ api = get_api(symname);
if (!api) {
ast_log(LOG_ERROR, "%s: Could not find api\n", symname);
return;
}
- ao2_callback(api->users, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA,
- optional_api_user_find_and_unuse, optional_ref);
-}
+ for (i = 0; i < api->users_len; ++i) {
+ struct optional_api_user *user = api->users[i];
+ if (user->optional_ref == optional_ref) {
+ if (*user->optional_ref != user->stub) {
+ ast_verb(4, "%s: Stubbing %s\n", symname,
+ user->module);
+ *user->optional_ref = user->stub;
+ }
+
+ /* Remove from the list */
+ api->users[i] = api->users[--api->users_len];
+
+ optional_api_user_free(user);
+ break;
+ }
+ }
+}
More information about the asterisk-commits
mailing list