module.c revision 2f6e87e64736666857c1bbe2cb0692c1f4e56508
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 28static struct module *g_module_head; 29static char *g_module_err; 30 31static 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 49static 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 62static 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 75static 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 89static 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 107static 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 118const char *module_error(void) 119{ 120 return g_module_err; 121} 122 123struct 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\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 150 dlerror(); 151 new->handle = dlopen(file, flag); 152 dlerr = dlerror(); 153 if (dlerr) { 154 LOGE("dlopen failed (%s)\n", dlerr); 155 module_set_error(dlerr); 156 pthread_mutex_unlock(&g_lock); 157 goto free_new; 158 } 159 160 existing = module_find_with_handle(g_module_head, new->handle); 161 if (existing) { 162 LOGE("found opened module %s\n", existing->name); 163 existing->ref_count++; 164 165 free(new); 166 pthread_mutex_unlock(&g_lock); 167 return existing; 168 } 169 170 dlerror(); 171 new->init = dlsym(new->handle, "module_init"); 172 dlerr = dlerror(); 173 if (!dlerr) { 174 LOGE("module %s has init(), call the symbol\n", new->name); 175 init_ret = new->init(new); 176 } 177 178 if (init_ret) { 179 LOGE("module %s init() failed (%d)\n", new->name, init_ret); 180 pthread_mutex_unlock(&g_lock); 181 goto free_handle; 182 } 183 184 dlerror(); 185 new->exit = dlsym(new->handle, "module_exit"); 186 dlerr = dlerror(); 187 if (dlerr) 188 new->exit = NULL; 189 190 new->name = strdup(file); 191 if (!new->name) { 192 if (new->exit) 193 new->exit(new); 194 goto free_handle; 195 } 196 197 g_module_head = module_add_list(g_module_head, new); 198 199 pthread_mutex_unlock(&g_lock); 200 return new; 201 202free_handle: 203 dlclose(new->handle); 204 205free_new: 206 free(new); 207 208 pthread_mutex_unlock(&g_lock); 209 return NULL; 210} 211 212int module_close(struct module *module) 213{ 214 const char *dlerr; 215 int ret = 0; 216 217 if (!module || !module->handle) 218 return 0; 219 220 pthread_mutex_lock(&g_lock); 221 222 module->ref_count--; 223 ret = module->ref_count; 224 225 LOGV("module %s decrease refcont (%d)\n", module->name, module->ref_count); 226 227 if (!module->ref_count) { 228 if (module->exit) 229 module->exit(module); 230 231 dlerror(); 232 dlclose(module->handle); 233 dlerr = dlerror(); 234 if (dlerr) { 235 module_set_error(dlerr); 236 ret = -1; 237 } 238 239 g_module_head = module_del_list(g_module_head, module); 240 241 LOGV("module %s closed\n", module->name); 242 243 free(module->name); 244 free(module); 245 } 246 247 pthread_mutex_unlock(&g_lock); 248 return ret; 249} 250 251void *module_symbol(struct module *module, const char *string) 252{ 253 void *symbol; 254 const char *dlerr; 255 256 if (!module || !module->handle || !string) 257 return NULL; 258 259 pthread_mutex_lock(&g_lock); 260 261 dlerror(); 262 symbol = dlsym(module->handle, string); 263 dlerr = dlerror(); 264 if (dlerr) { 265 LOGE("not founded symbol %s in module %s (%s)\n", 266 string, module->name, dlerr); 267 module_set_error(dlerr); 268 symbol = NULL; 269 } 270 else 271 LOGV("found symbol %s in module %s\n", string, module->name); 272 273 pthread_mutex_unlock(&g_lock); 274 return symbol; 275} 276