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