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
module_find_with_name(struct module * head,const char * filename)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
module_find_with_handle(struct module * head,const void * handle)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
module_add_list(struct module * head,struct module * add)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
module_del_list(struct module * head,struct module * del)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
module_set_error(const char * dlerr)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
module_error(void)118 const char *module_error(void)
119 {
120 return g_module_err;
121 }
122
module_open(const char * file,int flag)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
module_close(struct module * module)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
module_symbol(struct module * module,const char * string)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