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 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
)
137 for(i
= 0 ; i
< l
->modules
->len
; i
++) {
138 m
= (LttvModule
*)(l
->modules
->pdata
[i
]);
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
);
150 g_ptr_array_free(m
->prerequisites
, TRUE
);
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
);
163 static LttvLibrary
*library_load(char *name
, GError
**error
)
169 char *path
, *pathname
;
173 GString
*messages
= g_string_new("");
175 /* insure that module.c is initialized */
179 /* Try to find the library along all the user specified paths */
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
);
187 pathname
= g_module_build_path(path
,name
);
188 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Try path %s", pathname
);
190 module_next
= &module_chain
;
191 gm
= g_module_open(pathname
,0);
194 if(gm
!= NULL
) break;
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());
201 /* Module cannot be found */
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
);
210 g_string_free(messages
, TRUE
);
212 /* Check if the library was already loaded */
214 l
= g_hash_table_lookup(libraries_by_g_module
, gm
);
216 /* This library was not already loaded */
219 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Library %s (%s) loaded", name
,
221 l
= library_add(name
, path
, gm
);
227 LttvLibrary
*lttv_library_load(char *name
, GError
**error
)
229 LttvLibrary
*l
= library_load(name
, error
);
230 l
->info
.load_count
++;
235 static void library_unload(LttvLibrary
*l
)
243 if(l
->locked_loaded
> 0) {
244 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Unload library %s: locked loaded",
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
);
255 /* Check if all its modules have been released */
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
);
266 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Unload library %s: close the GModule",
270 if(gm
!= NULL
) g_module_close(gm
);
272 /* insure that module.c will be finalized */
278 void lttv_library_unload(LttvLibrary
*l
)
280 l
->info
.load_count
--;
285 static void library_lock_loaded(LttvLibrary
*l
)
291 static void library_unlock_loaded(LttvLibrary
*l
)
298 static LttvModule
*module_require(char *name
, GError
**error
)
300 GError
*tmp_error
= NULL
;
304 LttvModule
*m
, *required
;
306 LttvLibrary
*l
= NULL
;
310 /* Insure that module.c is initialized */
314 /* Check if the module is already loaded */
316 modules
= g_hash_table_lookup(modules_by_name
, name
);
318 /* Try to load a library having the module name */
320 if(modules
== NULL
) {
321 l
= library_load(name
, error
);
322 if(l
== NULL
) return NULL
;
323 else library_lock_loaded(l
);
325 /* A library was found, does it contain the named module */
327 modules
= g_hash_table_lookup(modules_by_name
, name
);
328 if(modules
== NULL
) {
329 g_set_error(error
, lttv_module_error
, LTTV_MODULE_NOT_FOUND
,
330 "Module %s not found in library %s", name
, l
->info
.name
);
331 library_unlock_loaded(l
);
335 m
= (LttvModule
*)(modules
->pdata
[modules
->len
- 1]);
337 /* We have the module */
341 /* First use of the module. Initialize after getting the prerequisites */
343 if(m
->info
.use_count
== 1) {
344 for(i
= 0 ; i
< m
->info
.prerequisites_number
; i
++) {
345 required
= module_require(m
->prerequisites_names
[i
], &tmp_error
);
347 /* A prerequisite could not be found, undo everything and fail */
349 if(required
== NULL
) {
350 for(j
= 0 ; j
< m
->prerequisites
->len
; j
++) {
351 module_release((LttvModule
*)(m
->prerequisites
->pdata
[j
]));
353 g_ptr_array_set_size(m
->prerequisites
, 0);
354 if(l
!= NULL
) library_unlock_loaded(l
);
355 g_set_error(error
, lttv_module_error
, LTTV_MODULE_NOT_FOUND
,
356 "Cannot find prerequisite for module %s: %s", name
,
358 g_clear_error(&tmp_error
);
361 g_ptr_array_add(m
->prerequisites
, required
);
363 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Module %s: init()", m
->info
.name
);
367 /* Decrement the load count of the library. It will not really be
368 unloaded since it contains a currently used module. */
370 if(l
!= NULL
) library_unlock_loaded(l
);
376 /* The require_count for a module is the number of explicit calls to
377 lttv_module_require, while the use_count also counts the number of times
378 a module is needed as a prerequisite. */
380 LttvModule
*lttv_module_require(char *name
, GError
**error
)
382 LttvModule
*m
= module_require(name
, error
);
383 if(m
!= NULL
) m
->info
.require_count
++;
388 static void module_release(LttvModule
*m
)
392 library_lock_loaded(m
->info
.library
);
395 if(m
->info
.use_count
== 0) {
396 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Module %s: destroy()",m
->info
.name
);
398 for(i
= 0 ; i
< m
->prerequisites
->len
; i
++) {
399 module_release((LttvModule
*)(m
->prerequisites
->pdata
[i
]));
401 g_ptr_array_set_size(m
->prerequisites
, 0);
403 library_unlock_loaded(m
->info
.library
);
407 void lttv_module_release(LttvModule
*m
)
409 m
->info
.require_count
--;
414 void lttv_module_info(LttvModule
*m
, LttvModuleInfo
*info
)
420 unsigned lttv_module_prerequisite_number(LttvModule
*m
)
422 return m
->prerequisites
->len
;
426 LttvModule
*lttv_module_prerequisite_get(LttvModule
*m
, unsigned i
)
428 return (LttvModule
*)(m
->prerequisites
->pdata
[i
]);
432 void lttv_library_info(LttvLibrary
*l
, LttvLibraryInfo
*info
)
438 unsigned lttv_library_module_number(LttvLibrary
*l
)
440 return l
->modules
->len
;
444 LttvModule
*lttv_library_module_get(LttvLibrary
*l
, unsigned i
)
446 return (LttvModule
*)(l
->modules
->pdata
[i
]);
450 unsigned lttv_library_number()
452 return libraries
->len
;
456 LttvLibrary
*lttv_library_get(unsigned i
)
458 return (LttvLibrary
*)(libraries
->pdata
[i
]);
462 void lttv_library_path_add(const char *name
)
464 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Add library path %s", name
);
465 g_ptr_array_add(library_paths
,(char*)g_strdup(name
));
469 void lttv_library_path_remove(const char *name
)
473 for(i
= 0 ; i
< library_paths
->len
; i
++) {
474 if(g_str_equal(name
, library_paths
->pdata
[i
])) {
475 g_free(library_paths
->pdata
[i
]);
476 g_ptr_array_remove_index(library_paths
,i
);
483 unsigned lttv_library_path_number()
485 return library_paths
->len
;
489 char *lttv_library_path_get(unsigned i
)
491 return (char *)(library_paths
->pdata
[library_paths
->len
- i
- 1]);
495 void lttv_module_register(struct _LttvModuleDescription
*d
)
498 module_next
= &(d
->next
);
504 if(initialized
) return;
507 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Init module.c");
511 lttv_module_error
= g_quark_from_string("LTTV_MODULE_ERROR");
512 modules_by_name
= g_hash_table_new(g_str_hash
, g_str_equal
);
513 libraries
= g_ptr_array_new();
514 libraries_by_g_module
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
515 library_paths
= g_ptr_array_new();
517 if(builtin_chain
== NULL
) builtin_chain
= module_chain
;
518 module_chain
= builtin_chain
;
519 library_add("builtin", NULL
, NULL
);
523 static finish_destroy()
527 if(initialized
) return;
528 g_assert(!destroyed
);
530 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Finish destroy module.c");
531 g_hash_table_destroy(modules_by_name
);
532 g_ptr_array_free(libraries
, TRUE
);
533 g_hash_table_destroy(libraries_by_g_module
);
534 for(i
= 0 ; i
< library_paths
->len
; i
++) {
535 g_free(library_paths
->pdata
[i
]);
537 g_ptr_array_free(library_paths
, TRUE
);
542 static void destroy()
546 LttvLibrary
*l
, **locked_libraries
;
550 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Destroy module.c");
552 /* Unload all libraries */
555 locked_libraries
= g_new(LttvLibrary
*, nb
);
557 for(i
= 0 ; i
< nb
; i
++) {
558 l
= (LttvLibrary
*)(libraries
->pdata
[i
]);
559 locked_libraries
[i
] = l
;
560 library_lock_loaded(l
);
561 for(j
= 0 ; j
< l
->modules
->len
; j
++) {
562 m
= (LttvModule
*)(l
->modules
->pdata
[j
]);
563 while(m
->info
.require_count
> 0) lttv_module_release(m
);
565 while(l
->info
.load_count
> 0) lttv_library_unload(l
);
568 for(i
= 0 ; i
< nb
; i
++) {
569 l
= locked_libraries
[i
];
570 library_unlock_loaded(l
);
572 g_free(locked_libraries
);
574 /* The library containing module.c may be locked by our caller */
576 g_assert(libraries
->len
<= 1);
581 LTTV_MODULE("module", "Modules in libraries", \
582 "Load libraries, list, require and initialize contained modules", \
This page took 0.040761 seconds and 4 git commands to generate.