Home | History | Annotate | Download | only in src
      1 /*
      2  * module.c, dynamic module interface
      3  *
      4  * Copyright (c) 2009-2010 Wind River Systems, Inc.
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  * http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 
     19 #include <string.h>
     20 #include <stdlib.h>
     21 #include <pthread.h>
     22 
     23 #include <module.h>
     24 
     25 #define LOG_TAG "module"
     26 #include <log.h>
     27 
     28 static struct module *g_module_head;
     29 static char *g_module_err;
     30 
     31 static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
     32 
     33 #define for_each_module(__module, __head)               \
     34     for ((__module) = (__head); (__module) != NULL;     \
     35          (__module) = (__module)->next)
     36 
     37 #define find_last_module(__head)                \
     38     ({                                          \
     39         struct module *m;                       \
     40                                                 \
     41         for_each_module(m, (__head)) {          \
     42             if (!m->next)                       \
     43                 break;                          \
     44         }                                       \
     45         m;                                      \
     46     })
     47 
     48 
     49 static struct module *module_find_with_name(struct module *head,
     50                                             const char *filename)
     51 {
     52     struct module *module;
     53 
     54     for_each_module(module, head) {
     55         if (!strcmp(module->name, filename))
     56             return module;
     57     }
     58 
     59     return NULL;
     60 }
     61 
     62 static struct module *module_find_with_handle(struct module *head,
     63                                               const void *handle)
     64 {
     65     struct module *module;
     66 
     67     for_each_module(module, head) {
     68         if (module->handle == handle)
     69             return module;
     70     }
     71 
     72     return NULL;
     73 }
     74 
     75 static struct module *module_add_list(struct module *head,
     76                                       struct module *add)
     77 {
     78     struct module *last;
     79 
     80     last = find_last_module(head);
     81     if (last)
     82         last->next = add;
     83     else
     84         head = add;
     85 
     86     return head;
     87 }
     88 
     89 static struct module *module_del_list(struct module *head,
     90                                       struct module *del)
     91 {
     92     struct module *prev = NULL;
     93 
     94     for_each_module(prev, head) {
     95         if (prev->next == del)
     96             break;
     97     }
     98 
     99     if (!prev)
    100         head = del->next;
    101     else
    102         prev->next = del->next;
    103 
    104     return head;
    105 }
    106 
    107 static inline void module_set_error(const char *dlerr)
    108 {
    109     if (g_module_err)
    110         free(g_module_err);
    111 
    112     if (dlerr)
    113         g_module_err = strdup(dlerr);
    114     else
    115         g_module_err = NULL;
    116 }
    117 
    118 const char *module_error(void)
    119 {
    120     return g_module_err;
    121 }
    122 
    123 struct module *module_open(const char *file, int flag)
    124 {
    125     struct module *new, *existing;
    126     const char *dlerr;
    127     int init_ret = 0;
    128 
    129     pthread_mutex_lock(&g_lock);
    130 
    131     existing = module_find_with_name(g_module_head, file);
    132     if (existing) {
    133         LOGE("found opened module %s with name\n", existing->name);
    134         existing->ref_count++;
    135         pthread_mutex_unlock(&g_lock);
    136         return existing;
    137     }
    138 
    139     new = malloc(sizeof(*new));
    140     if (!new) {
    141         pthread_mutex_unlock(&g_lock);
    142         return NULL;
    143     }
    144 
    145     new->ref_count = 1;
    146     new->priv = NULL;
    147     new->next = NULL;
    148     new->handle = NULL;
    149 
    150     new->handle = dlopen(file, flag);
    151     if (!(new->handle)) {
    152         LOGE("dlopen failed (%s)\n", file);
    153         dlerr = dlerror();
    154         module_set_error(dlerr);
    155         goto free_new;
    156     }
    157 
    158     existing = module_find_with_handle(g_module_head, new->handle);
    159     if (existing) {
    160         LOGE("found opened module %s with handle\n", existing->name);
    161         existing->ref_count++;
    162 
    163         free(new);
    164         pthread_mutex_unlock(&g_lock);
    165         return existing;
    166     }
    167 
    168     new->name = strdup(file);
    169     if (!new->name) {
    170         goto free_handle;
    171     }
    172 
    173     dlerror();
    174     new->init = dlsym(new->handle, "module_init");
    175     dlerr = dlerror();
    176     if (!dlerr && new->init) {
    177         LOGE("module %s has init(), call the symbol\n", new->name);
    178         init_ret = new->init(new);
    179     }
    180 
    181     if (init_ret) {
    182         LOGE("module %s init() failed (%d)\n", new->name, init_ret);
    183         goto free_handle;
    184     }
    185 
    186     dlerror();
    187     new->exit = dlsym(new->handle, "module_exit");
    188     dlerr = dlerror();
    189     if (dlerr)
    190         new->exit = NULL;
    191 
    192     g_module_head = module_add_list(g_module_head, new);
    193 
    194     pthread_mutex_unlock(&g_lock);
    195     return new;
    196 
    197 free_handle:
    198     dlclose(new->handle);
    199 
    200 free_new:
    201     free(new);
    202 
    203     pthread_mutex_unlock(&g_lock);
    204     return NULL;
    205 }
    206 
    207 int module_close(struct module *module)
    208 {
    209     int ret = 0;
    210 
    211     if (!module || !module->handle)
    212         return 0;
    213 
    214     pthread_mutex_lock(&g_lock);
    215 
    216     module->ref_count--;
    217     ret = module->ref_count;
    218 
    219     LOGV("module %s decrease refcont (%d)\n", module->name, module->ref_count);
    220 
    221     if (!module->ref_count) {
    222         if (module->exit)
    223             module->exit(module);
    224 
    225         if (dlclose(module->handle)) {
    226             LOGE("module %s dlclose failed",module->name);
    227         }
    228 
    229         g_module_head = module_del_list(g_module_head, module);
    230 
    231         LOGV("module %s closed\n", module->name);
    232 
    233         free(module->name);
    234         free(module);
    235     }
    236 
    237     pthread_mutex_unlock(&g_lock);
    238     return ret;
    239 }
    240 
    241 void *module_symbol(struct module *module, const char *string)
    242 {
    243     void *symbol = NULL;
    244     const char *dlerr;
    245 
    246     if (!module || !module->handle || !string)
    247         return NULL;
    248 
    249     pthread_mutex_lock(&g_lock);
    250 
    251     symbol = dlsym(module->handle, string);
    252     if (!symbol) {
    253         dlerr = dlerror();
    254         LOGE("not founded symbol %s in module %s (%s)\n",
    255              string, module->name, dlerr);
    256         module_set_error(dlerr);
    257         symbol = NULL;
    258     }
    259     else
    260         LOGV("found symbol %s in module %s\n", string, module->name);
    261 
    262     pthread_mutex_unlock(&g_lock);
    263     return symbol;
    264 }
    265