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     void *handle;
    127     const char *dlerr;
    128     int init_ret = 0;
    129 
    130     pthread_mutex_lock(&g_lock);
    131 
    132     existing = module_find_with_name(g_module_head, file);
    133     if (existing) {
    134         LOGE("found opened module %s with name\n", existing->name);
    135         existing->ref_count++;
    136         pthread_mutex_unlock(&g_lock);
    137         return existing;
    138     }
    139 
    140     new = malloc(sizeof(*new));
    141     if (!new) {
    142         pthread_mutex_unlock(&g_lock);
    143         return NULL;
    144     }
    145 
    146     new->ref_count = 1;
    147     new->priv = NULL;
    148     new->next = NULL;
    149     new->handle = NULL;
    150 
    151     new->handle = dlopen(file, flag);
    152     if (!(new->handle)) {
    153         LOGE("dlopen failed (%s)\n", file);
    154         dlerr = dlerror();
    155         module_set_error(dlerr);
    156         goto free_new;
    157     }
    158 
    159     existing = module_find_with_handle(g_module_head, new->handle);
    160     if (existing) {
    161         LOGE("found opened module %s with handle\n", existing->name);
    162         existing->ref_count++;
    163 
    164         free(new);
    165         pthread_mutex_unlock(&g_lock);
    166         return existing;
    167     }
    168 
    169     new->name = strdup(file);
    170     if (!new->name) {
    171         goto free_handle;
    172     }
    173 
    174     dlerror();
    175     new->init = dlsym(new->handle, "module_init");
    176     dlerr = dlerror();
    177     if (!dlerr && new->init) {
    178         LOGE("module %s has init(), call the symbol\n", new->name);
    179         init_ret = new->init(new);
    180     }
    181 
    182     if (init_ret) {
    183         LOGE("module %s init() failed (%d)\n", new->name, init_ret);
    184         goto free_handle;
    185     }
    186 
    187     dlerror();
    188     new->exit = dlsym(new->handle, "module_exit");
    189     dlerr = dlerror();
    190     if (dlerr)
    191         new->exit = NULL;
    192 
    193     g_module_head = module_add_list(g_module_head, new);
    194 
    195     pthread_mutex_unlock(&g_lock);
    196     return new;
    197 
    198 free_handle:
    199     dlclose(new->handle);
    200 
    201 free_new:
    202     free(new);
    203 
    204     pthread_mutex_unlock(&g_lock);
    205     return NULL;
    206 }
    207 
    208 int module_close(struct module *module)
    209 {
    210     const char *dlerr;
    211     int ret = 0;
    212 
    213     if (!module || !module->handle)
    214         return 0;
    215 
    216     pthread_mutex_lock(&g_lock);
    217 
    218     module->ref_count--;
    219     ret = module->ref_count;
    220 
    221     LOGV("module %s decrease refcont (%d)\n", module->name, module->ref_count);
    222 
    223     if (!module->ref_count) {
    224         if (module->exit)
    225             module->exit(module);
    226 
    227         if (dlclose(module->handle)) {
    228             LOGE("module %s dlclose failed",module->name);
    229         }
    230 
    231         g_module_head = module_del_list(g_module_head, module);
    232 
    233         LOGV("module %s closed\n", module->name);
    234 
    235         free(module->name);
    236         free(module);
    237     }
    238 
    239     pthread_mutex_unlock(&g_lock);
    240     return ret;
    241 }
    242 
    243 void *module_symbol(struct module *module, const char *string)
    244 {
    245     void *symbol = NULL;
    246     const char *dlerr;
    247 
    248     if (!module || !module->handle || !string)
    249         return NULL;
    250 
    251     pthread_mutex_lock(&g_lock);
    252 
    253     symbol = dlsym(module->handle, string);
    254     if (!symbol) {
    255         dlerr = dlerror();
    256         LOGE("not founded symbol %s in module %s (%s)\n",
    257              string, module->name, dlerr);
    258         module_set_error(dlerr);
    259         symbol = NULL;
    260     }
    261     else
    262         LOGV("found symbol %s in module %s\n", string, module->name);
    263 
    264     pthread_mutex_unlock(&g_lock);
    265     return symbol;
    266 }
    267