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. */
23 #include <lttv/module.h>
39 char **prerequisites_names
;
40 GPtrArray
*prerequisites
;
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.
48 Libraries correspond to glib modules. The g_module function is
49 responsible for loading each library only once. */
51 static GHashTable
*modules_by_name
= NULL
;
53 static GPtrArray
*libraries
= NULL
;
55 static GHashTable
*libraries_by_g_module
= NULL
;
57 static GPtrArray
*library_paths
= NULL
;
59 static gboolean initialized
= FALSE
;
61 static gboolean destroyed
= TRUE
;
63 static struct _LttvModuleDescription
*builtin_chain
= NULL
;
65 static struct _LttvModuleDescription
*module_chain
= NULL
;
67 static struct _LttvModuleDescription
**module_next
= &module_chain
;
69 static GQuark lttv_module_error
;
73 static void finish_destroy();
75 static void module_release(LttvModule
*m
);
78 static LttvLibrary
*library_add(char *name
, char *path
, GModule
*gm
)
84 struct _LttvModuleDescription
*link
;
88 l
= g_new(LttvLibrary
, 1);
89 l
->modules
= g_ptr_array_new();
92 l
->info
.name
= g_strdup(name
);
93 l
->info
.path
= g_strdup(path
);
94 l
->info
.load_count
= 0;
96 g_ptr_array_add(libraries
, l
);
97 g_hash_table_insert(libraries_by_g_module
, gm
, l
);
100 for(link
= module_chain
; link
!= NULL
; link
= link
->next
) {
101 m
= g_new(LttvModule
, 1);
102 g_ptr_array_add(l
->modules
, m
);
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
);
109 g_ptr_array_add(modules
, m
);
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
;
119 m
->info
.require_count
= 0;
120 m
->info
.use_count
= 0;
121 m
->info
.prerequisites_number
= link
->prerequisites_number
;
127 static void library_remove(LttvLibrary
*l
)
132 GPtrArray
**modules_ptr
= &modules
; /* for strict aliasing */
136 char **key_ptr
= &key
; /* for strict aliasing */
138 for(i
= 0 ; i
< l
->modules
->len
; i
++) {
139 m
= (LttvModule
*)(l
->modules
->pdata
[i
]);
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
);
151 g_ptr_array_free(m
->prerequisites
, TRUE
);
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
);
164 static LttvLibrary
*library_load(char *name
, GError
**error
)
170 /* path is always initialized, checked */
171 char *path
= NULL
, *pathname
;
175 GString
*messages
= g_string_new("");
177 /* insure that module.c is initialized */
181 /* Try to find the library along all the user specified paths */
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
);
189 pathname
= g_module_build_path(path
,name
);
190 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Try path %s", pathname
);
192 module_next
= &module_chain
;
193 gm
= g_module_open(pathname
,0);
196 if(gm
!= NULL
) break;
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());
203 /* Module cannot be found */
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
);
212 g_string_free(messages
, TRUE
);
214 /* Check if the library was already loaded */
216 l
= g_hash_table_lookup(libraries_by_g_module
, gm
);
218 /* This library was not already loaded */
221 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Library %s (%s) loaded", name
,
223 l
= library_add(name
, path
, gm
);
229 LttvLibrary
*lttv_library_load(char *name
, GError
**error
)
231 LttvLibrary
*l
= library_load(name
, error
);
232 if(l
!= NULL
) l
->info
.load_count
++;
237 static void library_unload(LttvLibrary
*l
)
245 if(l
->locked_loaded
> 0) {
246 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Unload library %s: locked loaded",
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
);
257 /* Check if all its modules have been released */
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
);
268 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Unload library %s: close the GModule",
272 if(gm
!= NULL
) g_module_close(gm
);
274 /* insure that module.c will be finalized */
280 void lttv_library_unload(LttvLibrary
*l
)
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
--;
289 static void library_lock_loaded(LttvLibrary
*l
)
295 static void library_unlock_loaded(LttvLibrary
*l
)
302 static LttvModule
*module_require(char *name
, GError
**error
)
304 GError
*tmp_error
= NULL
;
308 LttvModule
*m
, *required
;
310 LttvLibrary
*l
= NULL
;
314 /* Insure that module.c is initialized */
318 /* Check if the module is already loaded */
320 modules
= g_hash_table_lookup(modules_by_name
, name
);
322 /* Try to load a library having the module name */
324 if(modules
== NULL
) {
325 l
= library_load(name
, error
);
326 if(l
== NULL
) return NULL
;
327 else library_lock_loaded(l
);
329 /* A library was found, does it contain the named module */
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
);
339 m
= (LttvModule
*)(modules
->pdata
[modules
->len
- 1]);
341 /* We have the module */
345 /* First use of the module. Initialize after getting the prerequisites */
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
);
351 /* A prerequisite could not be found, undo everything and fail */
353 if(required
== NULL
) {
354 for(j
= 0 ; j
< m
->prerequisites
->len
; j
++) {
355 module_release((LttvModule
*)(m
->prerequisites
->pdata
[j
]));
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
,
362 g_clear_error(&tmp_error
);
365 g_ptr_array_add(m
->prerequisites
, required
);
367 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Module %s: init()", m
->info
.name
);
371 /* Decrement the load count of the library. It will not really be
372 unloaded since it contains a currently used module. */
374 if(l
!= NULL
) library_unlock_loaded(l
);
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. */
384 LttvModule
*lttv_module_require(char *name
, GError
**error
)
386 LttvModule
*m
= module_require(name
, error
);
387 if(m
!= NULL
) m
->info
.require_count
++;
392 static void module_release(LttvModule
*m
)
396 library_lock_loaded(m
->info
.library
);
399 if(m
->info
.use_count
== 0) {
400 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Module %s: destroy()",m
->info
.name
);
402 for(i
= 0 ; i
< m
->prerequisites
->len
; i
++) {
403 module_release((LttvModule
*)(m
->prerequisites
->pdata
[i
]));
405 g_ptr_array_set_size(m
->prerequisites
, 0);
407 library_unlock_loaded(m
->info
.library
);
411 void lttv_module_release(LttvModule
*m
)
413 m
->info
.require_count
--;
418 void lttv_module_info(LttvModule
*m
, LttvModuleInfo
*info
)
424 unsigned lttv_module_prerequisite_number(LttvModule
*m
)
426 return m
->prerequisites
->len
;
430 LttvModule
*lttv_module_prerequisite_get(LttvModule
*m
, unsigned i
)
432 return (LttvModule
*)(m
->prerequisites
->pdata
[i
]);
436 void lttv_library_info(LttvLibrary
*l
, LttvLibraryInfo
*info
)
442 unsigned lttv_library_module_number(LttvLibrary
*l
)
444 return l
->modules
->len
;
448 LttvModule
*lttv_library_module_get(LttvLibrary
*l
, unsigned i
)
450 return (LttvModule
*)(l
->modules
->pdata
[i
]);
454 unsigned lttv_library_number()
456 return libraries
->len
;
460 LttvLibrary
*lttv_library_get(unsigned i
)
462 return (LttvLibrary
*)(libraries
->pdata
[i
]);
466 void lttv_library_path_add(const char *name
)
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
));
473 void lttv_library_path_remove(const char *name
)
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
);
487 unsigned lttv_library_path_number()
489 return library_paths
->len
;
493 char *lttv_library_path_get(unsigned i
)
495 return (char *)(library_paths
->pdata
[library_paths
->len
- i
- 1]);
499 void lttv_module_register(struct _LttvModuleDescription
*d
)
502 module_next
= &(d
->next
);
508 if(initialized
) return;
511 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Init module.c");
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();
521 if(builtin_chain
== NULL
) builtin_chain
= module_chain
;
522 module_chain
= builtin_chain
;
523 library_add("builtin", NULL
, NULL
);
527 static void finish_destroy()
531 if(initialized
) return;
532 g_assert(!destroyed
);
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
]);
541 g_ptr_array_free(library_paths
, TRUE
);
546 static void destroy()
550 LttvLibrary
*l
, **locked_libraries
;
554 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Destroy module.c");
556 /* Unload all libraries */
559 locked_libraries
= g_new(LttvLibrary
*, nb
);
561 for(i
= 0 ; i
< nb
; i
++) {
562 //g_assert(nb == libraries->len);
563 l
= (LttvLibrary
*)(libraries
->pdata
[i
]);
564 locked_libraries
[i
] = l
;
565 library_lock_loaded(l
);
566 for(j
= 0 ; j
< l
->modules
->len
; j
++) {
567 m
= (LttvModule
*)(l
->modules
->pdata
[j
]);
568 while(m
->info
.require_count
> 0) lttv_module_release(m
);
570 library_unlock_loaded(l
);
571 while(l
->info
.load_count
> 0) lttv_library_unload(l
);
573 /* If the number of librairies loaded have changed, restart from the
575 if(nb
!= libraries
->len
) {
582 for(i
= 0 ; i
< nb
; i
++) {
583 l
= locked_libraries
[i
];
584 library_unlock_loaded(l
);
586 g_free(locked_libraries
);
588 /* The library containing module.c may be locked by our caller */
590 g_assert(libraries
->len
<= 1);
595 LTTV_MODULE("module", "Modules in libraries", \
596 "Load libraries, list, require and initialize contained modules", \
This page took 0.041404 seconds and 4 git commands to generate.