optional_api: Refactor to use vector's and standard allocators.
authorCorey Farrell <git@cfware.com>
Tue, 26 Dec 2017 01:32:53 +0000 (20:32 -0500)
committerCorey Farrell <git@cfware.com>
Tue, 13 Feb 2018 03:53:35 +0000 (22:53 -0500)
* Replace ad-hoc array management with macro's from vector.h.
* Remove redundent logger messages.
* Use normal Asterisk allocators instead of directly using libc
  allocators.
* Free memory when an API has no implementation or users.

Change-Id: Ic6ecb31798d4a78e7df39ece86a68b60eac05bf5

main/optional_api.c

index 9b9a1a0..d63129c 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "asterisk/optional_api.h"
 #include "asterisk/utils.h"
+#include "asterisk/vector.h"
 
 #if defined(OPTIONAL_API)
 
@@ -56,16 +57,18 @@ struct optional_api_user {
 struct optional_api {
        /*! Pointer to the implementation function; could be null */
        ast_optional_fn impl;
-       /*! Variable length array of users of this API */
-       struct optional_api_user **users;
-       /*! Allocated size of the \a users array */
-       size_t users_maxlen;
-       /*! Number of entries in the \a users array */
-       size_t users_len;
+       /*! Users of the API */
+       AST_VECTOR(, struct optional_api_user *) users;
        /*! Name of the optional API function */
        char symname[];
 };
 
+/*! Vector of \ref optional_api functions */
+AST_VECTOR(, struct optional_api *) apis;
+
+#define USER_OPTIONAL_REF_CMP(ele, value) (ele->optional_ref == value)
+#define OPTIONAL_API_SYMNAME_CMP(ele, value) (!strcmp(ele->symname, value))
+
 /*!
  * \brief Free an \ref optional_api_user.
  *
@@ -74,7 +77,7 @@ struct optional_api {
 static void optional_api_user_destroy(struct optional_api_user *user)
 {
        *user->optional_ref = user->stub;
-       ast_std_free(user);
+       ast_free(user);
 }
 
 /*!
@@ -93,8 +96,10 @@ static struct optional_api_user *optional_api_user_create(
        struct optional_api_user *user;
        size_t size = sizeof(*user) + strlen(module) + 1;
 
-       user = ast_std_calloc(1, size);
+       user = ast_calloc(1, size);
        if (!user) {
+               ast_do_crash();
+
                return NULL;
        }
 
@@ -112,17 +117,15 @@ static struct optional_api_user *optional_api_user_create(
  */
 static void optional_api_destroy(struct optional_api *api)
 {
-       while (api->users_len--) {
-               optional_api_user_destroy(api->users[api->users_len]);
-       }
-       ast_std_free(api->users);
-       api->users = NULL;
-       api->users_maxlen = 0;
-       ast_std_free(api);
+       AST_VECTOR_REMOVE_CMP_UNORDERED(&apis, api,
+               AST_VECTOR_ELEM_DEFAULT_CMP, AST_VECTOR_ELEM_CLEANUP_NOOP);
+       AST_VECTOR_CALLBACK_VOID(&api->users, optional_api_user_destroy);
+       AST_VECTOR_FREE(&api->users);
+       ast_free(api);
 }
 
 /*!
- * \brief Create an \ref optional_api.
+ * \brief Create and link an \ref optional_api.
  *
  * \param symname Name of the optional function.
  * \return New \ref optional_api.
@@ -131,12 +134,12 @@ static void optional_api_destroy(struct optional_api *api)
 static struct optional_api *optional_api_create(const char *symname)
 {
        struct optional_api *api;
-       size_t size;
 
-       size = sizeof(*api) + strlen(symname) + 1;
-       api = ast_std_calloc(1, size);
-       if (!api) {
-               ast_log(LOG_ERROR, "Failed to allocate api\n");
+       api = ast_calloc(1, sizeof(*api) + strlen(symname) + 1);
+       if (!api || AST_VECTOR_APPEND(&apis, api)) {
+               ast_free(api);
+               ast_do_crash();
+
                return NULL;
        }
 
@@ -145,16 +148,6 @@ static struct optional_api *optional_api_create(const char *symname)
        return api;
 }
 
-/*! Array of \ref optional_api functions */
-struct {
-       /*! Variable length array of API's */
-       struct optional_api **list;
-       /*! Allocated size of the \a list array */
-       size_t maxlen;
-       /*! Number of entries in the \a list array */
-       size_t len;
-} apis;
-
 /*!
  * \brief Gets (or creates) the \ref optional_api for the given function.
  *
@@ -164,43 +157,16 @@ struct {
  */
 static struct optional_api *get_api(const char *symname)
 {
-       struct optional_api *api;
-       size_t i;
+       struct optional_api **api;
 
        /* Find one, if we already have it */
-       if (apis.list) {
-               for (i = 0; i < apis.len; ++i) {
-                       if (strcmp(symname, apis.list[i]->symname) == 0) {
-                               return apis.list[i];
-                       }
-               }
+       api = AST_VECTOR_GET_CMP(&apis, symname, OPTIONAL_API_SYMNAME_CMP);
+       if (api) {
+               return *api;
        }
 
        /* API not found. Build one */
-       api = optional_api_create(symname);
-       if (!api) {
-               return NULL;
-       }
-
-       /* 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;
-
-               new_list = ast_std_realloc(apis.list, new_maxlen * sizeof(*new_list));
-               if (!new_list) {
-                       optional_api_destroy(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;
+       return optional_api_create(symname);
 }
 
 /*!
@@ -232,13 +198,14 @@ static void optional_api_user_relink(struct optional_api_user *user,
 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);
+       if (AST_VECTOR_SIZE(&api->users)) {
+               AST_VECTOR_CALLBACK_VOID(&api->users, optional_api_user_relink, api);
+       } else if (!impl) {
+               /* No users or impl means we should delete this api. */
+               optional_api_destroy(api);
        }
 }
 
@@ -247,13 +214,9 @@ void ast_optional_api_provide(const char *symname, ast_optional_fn impl)
        struct optional_api *api;
 
        api = get_api(symname);
-       if (!api) {
-               ast_log(LOG_ERROR, "%s: Allocation failed\n", symname);
-               ast_do_crash();
-               return;
+       if (api) {
+               optional_api_set_impl(api, impl);
        }
-
-       optional_api_set_impl(api, impl);
 }
 
 void ast_optional_api_unprovide(const char *symname, ast_optional_fn impl)
@@ -261,13 +224,9 @@ void ast_optional_api_unprovide(const char *symname, ast_optional_fn impl)
        struct optional_api *api;
 
        api = get_api(symname);
-       if (!api) {
-               ast_log(LOG_ERROR, "%s: Could not find api\n", symname);
-               ast_do_crash();
-               return;
+       if (api) {
+               optional_api_set_impl(api, 0);
        }
-
-       optional_api_set_impl(api, 0);
 }
 
 void ast_optional_api_use(const char *symname, ast_optional_fn *optional_ref,
@@ -276,73 +235,36 @@ void ast_optional_api_use(const char *symname, ast_optional_fn *optional_ref,
        struct optional_api_user *user;
        struct optional_api *api;
 
-
        api = get_api(symname);
        if (!api) {
-               ast_log(LOG_ERROR, "%s: Allocation failed\n", symname);
-               ast_do_crash();
                return;
        }
 
        user = optional_api_user_create(optional_ref, stub, module);
        if (!user) {
-               ast_log(LOG_ERROR, "%s: Allocation failed\n", symname);
-               ast_do_crash();
                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;
-
-               new_list = ast_std_realloc(api->users, new_maxlen * sizeof(*new_list));
-               if (!new_list) {
-                       optional_api_user_destroy(user);
-                       ast_log(LOG_ERROR, "Failed to allocate api list\n");
-                       ast_do_crash();
-                       return;
-               }
-
-               api->users_maxlen = new_maxlen;
-               api->users = new_list;
+       if (!AST_VECTOR_APPEND(&api->users, user)) {
+               optional_api_user_relink(user, api);
+       } else {
+               optional_api_user_destroy(user);
+               ast_do_crash();
        }
-
-       api->users[api->users_len++] = user;
-
-       optional_api_user_relink(user, api);
 }
 
 void ast_optional_api_unuse(const char *symname, ast_optional_fn *optional_ref,
        const char *module)
 {
        struct optional_api *api;
-       size_t i;
 
        api = get_api(symname);
-       if (!api) {
-               ast_log(LOG_ERROR, "%s: Could not find api\n", symname);
-               ast_do_crash();
-               return;
-       }
-
-       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) {
-                               *user->optional_ref = user->stub;
-                       }
-
-                       /* Remove from the list */
-                       api->users[i] = api->users[--api->users_len];
-
-                       optional_api_user_destroy(user);
-                       return;
+       if (api) {
+               AST_VECTOR_REMOVE_CMP_UNORDERED(&api->users, optional_ref, USER_OPTIONAL_REF_CMP, optional_api_user_destroy);
+               if (!api->impl && !AST_VECTOR_SIZE(&api->users)) {
+                       optional_api_destroy(api);
                }
        }
-
-       ast_log(LOG_ERROR, "%s: Could not find user %s\n", symname, module);
 }
-
 #endif /* defined(OPTIONAL_API) */