bind lasy
[lttv.git] / ltt / branches / poly / lttv / module.c
1
2 /* module.c : Implementation of the module loading/unloading mechanism.
3 *
4 */
5
6 #include <lttv/module.h>
7
8
9 struct _LttvModule
10 {
11 GModule *module;
12 guint ref_count;
13 guint load_count;
14 GPtrArray *dependents;
15 };
16
17
18 /* Table of loaded modules and paths where to search for modules */
19
20 static GHashTable *modules = NULL;
21
22 static GPtrArray *modulesPaths = NULL;
23
24 static void lttv_module_unload_all();
25
26
27 void lttv_module_init(int argc, char **argv)
28 {
29 modules = g_hash_table_new(g_str_hash, g_str_equal);
30 modulesPaths = g_ptr_array_new();
31 }
32
33
34 void lttv_module_destroy()
35 {
36 int i;
37
38 /* Unload all modules */
39 lttv_module_unload_all();
40
41 /* Free the modules paths pointer array as well as the elements */
42 for(i = 0; i < modulesPaths->len ; i++) {
43 g_free(modulesPaths->pdata[i]);
44 }
45 g_ptr_array_free(modulesPaths,TRUE) ;
46 modulesPaths = NULL;
47
48 /* destroy the hash table */
49 g_hash_table_destroy(modules) ;
50 modules = NULL;
51 }
52
53
54 /* Add a new pathname to the modules loading search path */
55
56 void lttv_module_path_add(const char *name)
57 {
58 g_ptr_array_add(modulesPaths,(char*)g_strdup(name));
59 }
60
61
62 static LttvModule *
63 module_load(const char *name, int argc, char **argv)
64 {
65 GModule *gm;
66
67 LttvModule *m;
68
69 int i;
70
71 char *pathname;
72
73 const char *module_name;
74
75 LttvModuleInit init_function;
76
77 /* Try to find the module along all the user specified paths */
78
79 for(i = 0 ; i < modulesPaths->len ; i++) {
80 pathname = g_module_build_path(modulesPaths->pdata[i],name);
81 gm = g_module_open(pathname,G_MODULE_BIND_LAZY);
82 g_critical("module : %s", pathname);
83 g_critical("erreur : %s", g_module_error());
84 g_free(pathname);
85
86 if(gm != NULL) break;
87 }
88
89 /* Try the default system path */
90
91 if(gm == NULL) {
92 pathname = g_module_build_path(NULL,name);
93 gm = g_module_open(pathname,G_MODULE_BIND_LAZY);
94 g_critical("module : %s", pathname);
95 g_free(pathname);
96 }
97
98 /* Module cannot be found */
99 if(gm==NULL)
100 g_critical("module est null");
101 if(gm == NULL) return NULL;
102
103 /* Check if the module was already opened using the hopefully canonical name
104 returned by g_module_name. */
105
106 module_name = g_module_name(gm);
107
108 m = g_hash_table_lookup(modules, module_name);
109
110 if(m == NULL) {
111
112 /* Module loaded for the first time. Insert it in the table and call the
113 init function if any. */
114
115 m = g_new(LttvModule, 1);
116 m->module = gm;
117 m->ref_count = 0;
118 m->load_count = 0;
119 m->dependents = g_ptr_array_new();
120 g_hash_table_insert(modules, (gpointer)module_name, m);
121
122 if(!g_module_symbol(gm, "init", (gpointer)&init_function)) {
123 g_warning("module %s (%s) has no init function", name, pathname);
124 }
125 else init_function(m, argc, argv);
126 }
127 else {
128
129 /* Module was already opened, check that it really is the same and
130 undo the extra g_module_open */
131
132 if(m->module != gm) g_error("Two gmodules with the same pathname");
133 g_module_close(gm);
134 }
135
136 m->ref_count++;
137 return m;
138 }
139
140
141 LttvModule *
142 lttv_module_load(const char *name, int argc, char **argv)
143 {
144 LttvModule *m = module_load(name, argc, argv);
145 if(m != NULL) m->load_count++;
146 return m;
147 }
148
149
150 LttvModule *
151 lttv_module_require(LttvModule *m, const char *name, int argc, char **argv)
152 {
153 LttvModule *module;
154
155 module = module_load(name, argc, argv);
156 if(module != NULL) g_ptr_array_add(m->dependents, module);
157 return module;
158 }
159
160
161 static void module_unload(LttvModule *m)
162 {
163 LttvModuleDestroy destroy_function;
164
165 char *pathname;
166
167 guint i, len;
168
169 /* Decrement the reference count */
170
171 m->ref_count--;
172 if(m->ref_count > 0) return;
173
174 /* We really have to unload the module, first unload its dependents */
175
176 len = m->dependents->len;
177
178 for(i = 0 ; i < len ; i++) {
179 module_unload(m->dependents->pdata[i]);
180 }
181
182 if(len != m->dependents->len) g_error("dependents list modified");
183
184 /* Unload the module itself */
185
186 if(!g_module_symbol(m->module, "destroy", (gpointer)&destroy_function)) {
187 g_warning("module (%s) has no destroy function", pathname);
188 }
189 else destroy_function();
190
191 g_hash_table_remove(modules, g_module_name(m->module));
192 g_ptr_array_free(m->dependents, TRUE);
193 g_module_close(m->module);
194 g_free(m);
195 }
196
197
198 void lttv_module_unload(LttvModule *m)
199 {
200 if(m->load_count <= 0) {
201 g_error("more unload than load (%s)", g_module_name(m->module));
202 return;
203 }
204 m->load_count--;
205 module_unload(m);
206 }
207
208
209 static void
210 list_modules(gpointer key, gpointer value, gpointer user_data)
211 {
212 g_ptr_array_add((GPtrArray *)user_data, value);
213 }
214
215
216 LttvModule **
217 lttv_module_list(guint *nb)
218 {
219 GPtrArray *list = g_ptr_array_new();
220
221 LttvModule **array;
222
223 g_hash_table_foreach(modules, list_modules, list);
224 *nb = list->len;
225 array = (LttvModule **)list->pdata;
226 g_ptr_array_free(list, FALSE);
227 return array;
228 }
229
230
231 LttvModule **
232 lttv_module_info(LttvModule *m, const char **name,
233 guint *ref_count, guint *load_count, guint *nb_dependents)
234 {
235 guint i, len = m->dependents->len;
236
237 LttvModule **array = g_new(LttvModule *, len);
238
239 *name = g_module_name(m->module);
240 *ref_count = m->ref_count;
241 *load_count = m->load_count;
242 *nb_dependents = len;
243 for(i = 0 ; i < len ; i++) array[i] = m->dependents->pdata[i];
244 return array;
245 }
246
247
248 static void
249 list_independent(gpointer key, gpointer value, gpointer user_data)
250 {
251 LttvModule *m = (LttvModule *)value;
252
253 if(m->load_count > 0) g_ptr_array_add((GPtrArray *)user_data, m);
254 }
255
256
257 void
258 lttv_module_unload_all()
259 {
260 guint i;
261
262 LttvModule *m;
263
264 GPtrArray *independent_modules = g_ptr_array_new();
265
266 g_hash_table_foreach(modules, list_independent, independent_modules);
267
268 for(i = 0 ; i < independent_modules->len ; i++) {
269 m = (LttvModule *)independent_modules->pdata[i];
270 while(m->load_count > 0) lttv_module_unload(m);
271 }
272
273 g_ptr_array_free(independent_modules, TRUE);
274 if(g_hash_table_size(modules) != 0) g_warning("cannot unload all modules");
275 }
This page took 0.056351 seconds and 4 git commands to generate.