[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