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