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