uninitialized variables checked, plus O2 optimisations checked : strict aliasing...
[lttv.git] / ltt / branches / poly / lttv / lttv / module.c
1
2 /* This file is part of the Linux Trace Toolkit viewer
3 * Copyright (C) 2003-2004 Michel Dagenais
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License Version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
17 * MA 02111-1307, USA.
18 */
19
20
21 /* module.c : Implementation of the module loading/unloading mechanism. */
22
23 #include <lttv/module.h>
24 #include <gmodule.h>
25
26
27 struct _LttvLibrary
28 {
29 LttvLibraryInfo info;
30 GPtrArray *modules;
31 GModule *gm;
32 guint locked_loaded;
33 };
34
35
36 struct _LttvModule
37 {
38 LttvModuleInfo info;
39 char **prerequisites_names;
40 GPtrArray *prerequisites;
41 };
42
43
44 /* Modules are searched by name. However, a library may be loaded which
45 provides a module with the same name as an existing one. A stack of
46 modules is thus maintained for each name.
47
48 Libraries correspond to glib modules. The g_module function is
49 responsible for loading each library only once. */
50
51 static GHashTable *modules_by_name = NULL;
52
53 static GPtrArray *libraries = NULL;
54
55 static GHashTable *libraries_by_g_module = NULL;
56
57 static GPtrArray *library_paths = NULL;
58
59 static gboolean initialized = FALSE;
60
61 static gboolean destroyed = TRUE;
62
63 static struct _LttvModuleDescription *builtin_chain = NULL;
64
65 static struct _LttvModuleDescription *module_chain = NULL;
66
67 static struct _LttvModuleDescription **module_next = &module_chain;
68
69 static GQuark lttv_module_error;
70
71 static void init();
72
73 static void finish_destroy();
74
75 static void module_release(LttvModule *m);
76
77
78 static LttvLibrary *library_add(char *name, char *path, GModule *gm)
79 {
80 LttvLibrary *l;
81
82 LttvModule *m;
83
84 struct _LttvModuleDescription *link;
85
86 GPtrArray *modules;
87
88 l = g_new(LttvLibrary, 1);
89 l->modules = g_ptr_array_new();
90 l->gm = gm;
91 l->locked_loaded = 0;
92 l->info.name = g_strdup(name);
93 l->info.path = g_strdup(path);
94 l->info.load_count = 0;
95
96 g_ptr_array_add(libraries, l);
97 g_hash_table_insert(libraries_by_g_module, gm, l);
98
99 *module_next = NULL;
100 for(link = module_chain; link != NULL; link = link->next) {
101 m = g_new(LttvModule, 1);
102 g_ptr_array_add(l->modules, m);
103
104 modules = g_hash_table_lookup(modules_by_name, link->name);
105 if(modules == NULL) {
106 modules = g_ptr_array_new();
107 g_hash_table_insert(modules_by_name, g_strdup(link->name), modules);
108 }
109 g_ptr_array_add(modules, m);
110
111 m->prerequisites_names = link->prerequisites;
112 m->prerequisites = g_ptr_array_new();
113 m->info.name = link->name;
114 m->info.short_description = link->short_description;
115 m->info.description = link->description;
116 m->info.init = link->init;
117 m->info.destroy = link->destroy;
118 m->info.library = l;
119 m->info.require_count = 0;
120 m->info.use_count = 0;
121 m->info.prerequisites_number = link->prerequisites_number;
122 }
123 return l;
124 }
125
126
127 static void library_remove(LttvLibrary *l)
128 {
129 LttvModule *m;
130
131 GPtrArray *modules;
132 GPtrArray **modules_ptr = &modules; /* for strict aliasing */
133 guint i;
134
135 char *key;
136 char **key_ptr = &key; /* for strict aliasing */
137
138 for(i = 0 ; i < l->modules->len ; i++) {
139 m = (LttvModule *)(l->modules->pdata[i]);
140
141 g_hash_table_lookup_extended(modules_by_name, m->info.name,
142 (gpointer *)key_ptr, (gpointer *)modules_ptr);
143 g_assert(modules != NULL);
144 g_ptr_array_remove(modules, m);
145 if(modules->len == 0) {
146 g_hash_table_remove(modules_by_name, m->info.name);
147 g_ptr_array_free(modules, TRUE);
148 g_free(key);
149 }
150
151 g_ptr_array_free(m->prerequisites, TRUE);
152 g_free(m);
153 }
154
155 g_ptr_array_remove(libraries, l);
156 g_hash_table_remove(libraries_by_g_module, l->gm);
157 g_ptr_array_free(l->modules, TRUE);
158 g_free(l->info.name);
159 g_free(l->info.path);
160 g_free(l);
161 }
162
163
164 static LttvLibrary *library_load(char *name, GError **error)
165 {
166 GModule *gm = NULL;
167
168 int i, nb;
169
170 /* path is always initialized, checked */
171 char *path = NULL, *pathname;
172
173 LttvLibrary *l;
174
175 GString *messages = g_string_new("");
176
177 /* insure that module.c is initialized */
178
179 init();
180
181 /* Try to find the library along all the user specified paths */
182
183 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Load library %s", name);
184 nb = lttv_library_path_number();
185 for(i = 0 ; i <= nb ; i++) {
186 if(i < nb) path = lttv_library_path_get(i);
187 else path = NULL;
188
189 pathname = g_module_build_path(path ,name);
190 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Try path %s", pathname);
191 module_chain = NULL;
192 module_next = &module_chain;
193 gm = g_module_open(pathname,0);
194 g_free(pathname);
195
196 if(gm != NULL) break;
197
198 g_string_append(messages, g_module_error());
199 g_string_append(messages, "\n");
200 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_INFO,"Trial failed, %s", g_module_error());
201 }
202
203 /* Module cannot be found */
204
205 if(gm == NULL) {
206 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Failed to load %s", name);
207 g_set_error(error, lttv_module_error, LTTV_MODULE_NOT_FOUND,
208 "Cannot load library %s: %s", name, messages->str);
209 g_string_free(messages, TRUE);
210 return NULL;
211 }
212 g_string_free(messages, TRUE);
213
214 /* Check if the library was already loaded */
215
216 l = g_hash_table_lookup(libraries_by_g_module, gm);
217
218 /* This library was not already loaded */
219
220 if(l == NULL) {
221 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Library %s (%s) loaded", name,
222 g_module_name(gm));
223 l = library_add(name, path, gm);
224 }
225 return l;
226 }
227
228
229 LttvLibrary *lttv_library_load(char *name, GError **error)
230 {
231 LttvLibrary *l = library_load(name, error);
232 if(l != NULL) l->info.load_count++;
233 return l;
234 }
235
236
237 static void library_unload(LttvLibrary *l)
238 {
239 guint i;
240
241 GModule *gm;
242
243 LttvModule *m;
244
245 if(l->locked_loaded > 0) {
246 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Unload library %s: locked loaded",
247 l->info.name);
248 return;
249 }
250
251 if(l->info.load_count > 0) {
252 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Unload library %s: load count %d",
253 l->info.name, l->info.load_count);
254 return;
255 }
256
257 /* Check if all its modules have been released */
258
259 for(i = 0 ; i < l->modules->len ; i++) {
260 m = (LttvModule *)(l->modules->pdata[i]);
261 if(m->info.use_count > 0) {
262 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO,"Unload library %s: module %s used",
263 l->info.name, m->info.name);
264 return;
265 }
266 }
267
268 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Unload library %s: close the GModule",
269 l->info.name);
270 gm = l->gm;
271 library_remove(l);
272 if(gm != NULL) g_module_close(gm);
273
274 /* insure that module.c will be finalized */
275
276 finish_destroy();
277 }
278
279
280 void lttv_library_unload(LttvLibrary *l)
281 {
282 /* In the case where we wait for a module to release, the load count is 0
283 * and should not be decremented. */
284 if(l->info.load_count != 0) l->info.load_count--;
285 library_unload(l);
286 }
287
288
289 static void library_lock_loaded(LttvLibrary *l)
290 {
291 l->locked_loaded++;
292 }
293
294
295 static void library_unlock_loaded(LttvLibrary *l)
296 {
297 l->locked_loaded--;
298 library_unload(l);
299 }
300
301
302 static LttvModule *module_require(char *name, GError **error)
303 {
304 GError *tmp_error = NULL;
305
306 guint i, j;
307
308 LttvModule *m, *required;
309
310 LttvLibrary *l = NULL;
311
312 GPtrArray *modules;
313
314 /* Insure that module.c is initialized */
315
316 init();
317
318 /* Check if the module is already loaded */
319
320 modules = g_hash_table_lookup(modules_by_name, name);
321
322 /* Try to load a library having the module name */
323
324 if(modules == NULL) {
325 l = library_load(name, error);
326 if(l == NULL) return NULL;
327 else library_lock_loaded(l);
328
329 /* A library was found, does it contain the named module */
330
331 modules = g_hash_table_lookup(modules_by_name, name);
332 if(modules == NULL) {
333 g_set_error(error, lttv_module_error, LTTV_MODULE_NOT_FOUND,
334 "Module %s not found in library %s", name, l->info.name);
335 library_unlock_loaded(l);
336 return NULL;
337 }
338 }
339 m = (LttvModule *)(modules->pdata[modules->len - 1]);
340
341 /* We have the module */
342
343 m->info.use_count++;
344
345 /* First use of the module. Initialize after getting the prerequisites */
346
347 if(m->info.use_count == 1) {
348 for(i = 0 ; i < m->info.prerequisites_number ; i++) {
349 required = module_require(m->prerequisites_names[i], &tmp_error);
350
351 /* A prerequisite could not be found, undo everything and fail */
352
353 if(required == NULL) {
354 for(j = 0 ; j < m->prerequisites->len ; j++) {
355 module_release((LttvModule *)(m->prerequisites->pdata[j]));
356 }
357 g_ptr_array_set_size(m->prerequisites, 0);
358 if(l != NULL) library_unlock_loaded(l);
359 g_set_error(error, lttv_module_error, LTTV_MODULE_NOT_FOUND,
360 "Cannot find prerequisite for module %s: %s", name,
361 tmp_error->message);
362 g_clear_error(&tmp_error);
363 return NULL;
364 }
365 g_ptr_array_add(m->prerequisites, required);
366 }
367 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Module %s: init()", m->info.name);
368 m->info.init();
369 }
370
371 /* Decrement the load count of the library. It will not really be
372 unloaded since it contains a currently used module. */
373
374 if(l != NULL) library_unlock_loaded(l);
375
376 return(m);
377 }
378
379
380 /* The require_count for a module is the number of explicit calls to
381 lttv_module_require, while the use_count also counts the number of times
382 a module is needed as a prerequisite. */
383
384 LttvModule *lttv_module_require(char *name, GError **error)
385 {
386 LttvModule *m = module_require(name, error);
387 if(m != NULL) m->info.require_count++;
388 return(m);
389 }
390
391
392 static void module_release(LttvModule *m)
393 {
394 guint i;
395
396 library_lock_loaded(m->info.library);
397
398 m->info.use_count--;
399 if(m->info.use_count == 0) {
400 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Module %s: destroy()",m->info.name);
401 m->info.destroy();
402 for(i = 0 ; i < m->prerequisites->len ; i++) {
403 module_release((LttvModule *)(m->prerequisites->pdata[i]));
404 }
405 g_ptr_array_set_size(m->prerequisites, 0);
406 }
407 library_unlock_loaded(m->info.library);
408 }
409
410
411 void lttv_module_release(LttvModule *m)
412 {
413 m->info.require_count--;
414 module_release(m);
415 }
416
417
418 void lttv_module_info(LttvModule *m, LttvModuleInfo *info)
419 {
420 *info = m->info;
421 }
422
423
424 unsigned lttv_module_prerequisite_number(LttvModule *m)
425 {
426 return m->prerequisites->len;
427 }
428
429
430 LttvModule *lttv_module_prerequisite_get(LttvModule *m, unsigned i)
431 {
432 return (LttvModule *)(m->prerequisites->pdata[i]);
433 }
434
435
436 void lttv_library_info(LttvLibrary *l, LttvLibraryInfo *info)
437 {
438 *info = l->info;
439 }
440
441
442 unsigned lttv_library_module_number(LttvLibrary *l)
443 {
444 return l->modules->len;
445 }
446
447
448 LttvModule *lttv_library_module_get(LttvLibrary *l, unsigned i)
449 {
450 return (LttvModule *)(l->modules->pdata[i]);
451 }
452
453
454 unsigned lttv_library_number()
455 {
456 return libraries->len;
457 }
458
459
460 LttvLibrary *lttv_library_get(unsigned i)
461 {
462 return (LttvLibrary *)(libraries->pdata[i]);
463 }
464
465
466 void lttv_library_path_add(const char *name)
467 {
468 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Add library path %s", name);
469 g_ptr_array_add(library_paths,(char*)g_strdup(name));
470 }
471
472
473 void lttv_library_path_remove(const char *name)
474 {
475 guint i;
476
477 for(i = 0 ; i < library_paths->len ; i++) {
478 if(g_str_equal(name, library_paths->pdata[i])) {
479 g_free(library_paths->pdata[i]);
480 g_ptr_array_remove_index(library_paths,i);
481 return;
482 }
483 }
484 }
485
486
487 unsigned lttv_library_path_number()
488 {
489 return library_paths->len;
490 }
491
492
493 char *lttv_library_path_get(unsigned i)
494 {
495 return (char *)(library_paths->pdata[library_paths->len - i - 1]);
496 }
497
498
499 void lttv_module_register(struct _LttvModuleDescription *d)
500 {
501 *module_next = d;
502 module_next = &(d->next);
503 }
504
505
506 static void init()
507 {
508 if(initialized) return;
509 g_assert(destroyed);
510
511 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Init module.c");
512
513 initialized = TRUE;
514 destroyed = FALSE;
515 lttv_module_error = g_quark_from_string("LTTV_MODULE_ERROR");
516 modules_by_name = g_hash_table_new(g_str_hash, g_str_equal);
517 libraries = g_ptr_array_new();
518 libraries_by_g_module = g_hash_table_new(g_direct_hash, g_direct_equal);
519 library_paths = g_ptr_array_new();
520
521 if(builtin_chain == NULL) builtin_chain = module_chain;
522 module_chain = builtin_chain;
523 library_add("builtin", NULL, NULL);
524 }
525
526
527 static void finish_destroy()
528 {
529 guint i;
530
531 if(initialized) return;
532 g_assert(!destroyed);
533
534 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Finish destroy module.c");
535 g_hash_table_destroy(modules_by_name);
536 g_ptr_array_free(libraries, TRUE);
537 g_hash_table_destroy(libraries_by_g_module);
538 for(i = 0 ; i < library_paths->len ; i++) {
539 g_free(library_paths->pdata[i]);
540 }
541 g_ptr_array_free(library_paths, TRUE);
542 destroyed = TRUE;
543 }
544
545
546 static void destroy()
547 {
548 guint i, j, nb;
549
550 LttvLibrary *l, **locked_libraries;
551
552 LttvModule *m;
553
554 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Destroy module.c");
555
556 /* Unload all libraries */
557
558 nb = libraries->len;
559 locked_libraries = g_new(LttvLibrary *, nb);
560
561 for(i = 0 ; i < nb ; i++) {
562 l = (LttvLibrary *)(libraries->pdata[i]);
563 locked_libraries[i] = l;
564 library_lock_loaded(l);
565 for(j = 0 ; j < l->modules->len ; j++) {
566 m = (LttvModule *)(l->modules->pdata[j]);
567 while(m->info.require_count > 0) lttv_module_release(m);
568 }
569 while(l->info.load_count > 0) lttv_library_unload(l);
570 }
571
572 for(i = 0 ; i < nb ; i++) {
573 l = locked_libraries[i];
574 library_unlock_loaded(l);
575 }
576 g_free(locked_libraries);
577
578 /* The library containing module.c may be locked by our caller */
579
580 g_assert(libraries->len <= 1);
581
582 initialized = FALSE;
583 }
584
585 LTTV_MODULE("module", "Modules in libraries", \
586 "Load libraries, list, require and initialize contained modules", \
587 init, destroy)
588
This page took 0.041491 seconds and 4 git commands to generate.