2 /* This file is part of the Linux Trace Toolkit viewer
3 * Copyright (C) 2003-2004 Michel Dagenais
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;
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.
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,
21 /* module.c : Implementation of the module loading/unloading mechanism. */
27 #include <lttv/module.h>
43 char **prerequisites_names
;
44 GPtrArray
*prerequisites
;
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.
52 Libraries correspond to glib modules. The g_module function is
53 responsible for loading each library only once. */
55 static GHashTable
*modules_by_name
= NULL
;
57 static GPtrArray
*libraries
= NULL
;
59 static GHashTable
*libraries_by_g_module
= NULL
;
61 static GPtrArray
*library_paths
= NULL
;
63 static gboolean initialized
= FALSE
;
65 static gboolean destroyed
= TRUE
;
67 static struct _LttvModuleDescription
*builtin_chain
= NULL
;
69 static struct _LttvModuleDescription
*module_chain
= NULL
;
71 static struct _LttvModuleDescription
**module_next
= &module_chain
;
73 static GQuark lttv_module_error
;
77 static void finish_destroy();
79 static void module_release(LttvModule
*m
);
82 static LttvLibrary
*library_add(char *name
, char *path
, GModule
*gm
)
88 struct _LttvModuleDescription
*link
;
92 l
= g_new(LttvLibrary
, 1);
93 l
->modules
= g_ptr_array_new();
96 l
->info
.name
= g_strdup(name
);
97 l
->info
.path
= g_strdup(path
);
98 l
->info
.load_count
= 0;
100 g_ptr_array_add(libraries
, l
);
101 g_hash_table_insert(libraries_by_g_module
, gm
, l
);
104 for(link
= module_chain
; link
!= NULL
; link
= link
->next
) {
105 m
= g_new(LttvModule
, 1);
106 g_ptr_array_add(l
->modules
, m
);
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
);
113 g_ptr_array_add(modules
, m
);
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
;
123 m
->info
.require_count
= 0;
124 m
->info
.use_count
= 0;
125 m
->info
.prerequisites_number
= link
->prerequisites_number
;
131 static void library_remove(LttvLibrary
*l
)
136 GPtrArray
**modules_ptr
= &modules
; /* for strict aliasing */
140 char **key_ptr
= &key
; /* for strict aliasing */
142 for(i
= 0 ; i
< l
->modules
->len
; i
++) {
143 m
= (LttvModule
*)(l
->modules
->pdata
[i
]);
145 g_hash_table_lookup_extended(modules_by_name
, m
->info
.name
,
146 (gpointer
*)key_ptr
, (gpointer
*)modules_ptr
);
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
);
155 g_ptr_array_free(m
->prerequisites
, TRUE
);
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
);
168 static LttvLibrary
*library_load(char *name
, GError
**error
)
174 /* path is always initialized, checked */
175 char *path
= NULL
, *pathname
;
179 GString
*messages
= g_string_new("");
181 /* insure that module.c is initialized */
185 /* Try to find the library along all the user specified paths */
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
);
193 pathname
= g_module_build_path(path
,name
);
194 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Try path %s", pathname
);
196 module_next
= &module_chain
;
197 gm
= g_module_open(pathname
,0);
200 if(gm
!= NULL
) break;
202 g_string_append(messages
, g_module_error());
203 g_string_append(messages
, "\n");
204 g_log(G_LOG_DOMAIN
,G_LOG_LEVEL_INFO
,"Trial failed, %s", g_module_error());
207 /* Module cannot be found */
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
);
216 g_string_free(messages
, TRUE
);
218 /* Check if the library was already loaded */
220 l
= g_hash_table_lookup(libraries_by_g_module
, gm
);
222 /* This library was not already loaded */
225 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Library %s (%s) loaded", name
,
227 l
= library_add(name
, path
, gm
);
233 LttvLibrary
*lttv_library_load(char *name
, GError
**error
)
235 LttvLibrary
*l
= library_load(name
, error
);
236 if(l
!= NULL
) l
->info
.load_count
++;
240 /* Returns < 0 if still in use, 0 if freed */
241 static gint
library_unload(LttvLibrary
*l
)
249 if(l
->locked_loaded
> 0) {
250 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Unload library %s: locked loaded",
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
;
261 /* Check if all its modules have been released */
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
);
272 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Unload library %s: close the GModule",
276 if(gm
!= NULL
) g_module_close(gm
);
278 /* insure that module.c will be finalized */
285 gint
lttv_library_unload(LttvLibrary
*l
)
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
;
299 static void library_lock_loaded(LttvLibrary
*l
)
305 static gint
library_unlock_loaded(LttvLibrary
*l
)
308 return library_unload(l
);
312 static LttvModule
*module_require(char *name
, GError
**error
)
314 GError
*tmp_error
= NULL
;
318 LttvModule
*m
, *required
;
320 LttvLibrary
*l
= NULL
;
324 /* Insure that module.c is initialized */
328 /* Check if the module is already loaded */
330 modules
= g_hash_table_lookup(modules_by_name
, name
);
332 /* Try to load a library having the module name */
334 if(modules
== NULL
) {
335 l
= library_load(name
, error
);
336 if(l
== NULL
) return NULL
;
337 else library_lock_loaded(l
);
339 /* A library was found, does it contain the named module */
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
);
349 m
= (LttvModule
*)(modules
->pdata
[modules
->len
- 1]);
351 /* We have the module */
355 /* First use of the module. Initialize after getting the prerequisites */
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
);
361 /* A prerequisite could not be found, undo everything and fail */
363 if(required
== NULL
) {
364 for(j
= 0 ; j
< m
->prerequisites
->len
; j
++) {
365 module_release((LttvModule
*)(m
->prerequisites
->pdata
[j
]));
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
,
372 g_clear_error(&tmp_error
);
375 g_ptr_array_add(m
->prerequisites
, required
);
377 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Module %s: init()", m
->info
.name
);
381 /* Decrement the load count of the library. It will not really be
382 unloaded since it contains a currently used module. */
384 if(l
!= NULL
) library_unlock_loaded(l
);
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. */
394 LttvModule
*lttv_module_require(char *name
, GError
**error
)
396 LttvModule
*m
= module_require(name
, error
);
397 if(m
!= NULL
) m
->info
.require_count
++;
402 static void module_release(LttvModule
*m
)
406 library_lock_loaded(m
->info
.library
);
409 if(m
->info
.use_count
== 0) {
410 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Module %s: destroy()",m
->info
.name
);
412 for(i
= 0 ; i
< m
->prerequisites
->len
; i
++) {
413 module_release((LttvModule
*)(m
->prerequisites
->pdata
[i
]));
415 g_ptr_array_set_size(m
->prerequisites
, 0);
417 library_unlock_loaded(m
->info
.library
);
421 void lttv_module_release(LttvModule
*m
)
423 m
->info
.require_count
--;
428 void lttv_module_info(LttvModule
*m
, LttvModuleInfo
*info
)
434 unsigned lttv_module_prerequisite_number(LttvModule
*m
)
436 return m
->prerequisites
->len
;
440 LttvModule
*lttv_module_prerequisite_get(LttvModule
*m
, unsigned i
)
442 return (LttvModule
*)(m
->prerequisites
->pdata
[i
]);
446 void lttv_library_info(LttvLibrary
*l
, LttvLibraryInfo
*info
)
452 unsigned lttv_library_module_number(LttvLibrary
*l
)
454 return l
->modules
->len
;
458 LttvModule
*lttv_library_module_get(LttvLibrary
*l
, unsigned i
)
460 return (LttvModule
*)(l
->modules
->pdata
[i
]);
464 unsigned lttv_library_number()
466 return libraries
->len
;
470 LttvLibrary
*lttv_library_get(unsigned i
)
472 return (LttvLibrary
*)(libraries
->pdata
[i
]);
476 void lttv_library_path_add(const char *name
)
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
));
483 void lttv_library_path_remove(const char *name
)
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
);
497 unsigned lttv_library_path_number()
499 return library_paths
->len
;
503 char *lttv_library_path_get(unsigned i
)
505 return (char *)(library_paths
->pdata
[library_paths
->len
- i
- 1]);
509 void lttv_module_register(struct _LttvModuleDescription
*d
)
512 module_next
= &(d
->next
);
518 if(initialized
) return;
521 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Init module.c");
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();
531 if(builtin_chain
== NULL
) builtin_chain
= module_chain
;
532 module_chain
= builtin_chain
;
533 library_add("builtin", NULL
, NULL
);
537 static void finish_destroy()
541 if(initialized
) return;
542 g_assert(!destroyed
);
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
]);
551 g_ptr_array_free(library_paths
, TRUE
);
556 static void destroy()
560 LttvLibrary
*l
, **locked_libraries
;
564 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Destroy module.c");
566 /* Unload all libraries */
569 locked_libraries
= g_new(LttvLibrary
*, nb
);
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
);
580 if(library_unlock_loaded(l
) > 0)
581 while(lttv_library_unload(l
) > 0);
583 /* If the number of librairies loaded have changed, restart from the
585 if(nb
!= libraries
->len
) {
592 for(i
= 0 ; i
< nb
; i
++) {
593 l
= locked_libraries
[i
];
594 library_unlock_loaded(l
);
596 g_free(locked_libraries
);
598 /* The library containing module.c may be locked by our caller */
600 g_assert(libraries
->len
<= 1);
605 LTTV_MODULE("module", "Modules in libraries", \
606 "Load libraries, list, require and initialize contained modules", \
This page took 0.043122 seconds and 4 git commands to generate.