• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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