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