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 if(l
!= NULL
) 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 /* 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
--;
287 static void library_lock_loaded(LttvLibrary
*l
)
293 static void library_unlock_loaded(LttvLibrary
*l
)
300 static LttvModule
*module_require(char *name
, GError
**error
)
302 GError
*tmp_error
= NULL
;
306 LttvModule
*m
, *required
;
308 LttvLibrary
*l
= NULL
;
312 /* Insure that module.c is initialized */
316 /* Check if the module is already loaded */
318 modules
= g_hash_table_lookup(modules_by_name
, name
);
320 /* Try to load a library having the module name */
322 if(modules
== NULL
) {
323 l
= library_load(name
, error
);
324 if(l
== NULL
) return NULL
;
325 else library_lock_loaded(l
);
327 /* A library was found, does it contain the named module */
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
);
337 m
= (LttvModule
*)(modules
->pdata
[modules
->len
- 1]);
339 /* We have the module */
343 /* First use of the module. Initialize after getting the prerequisites */
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
);
349 /* A prerequisite could not be found, undo everything and fail */
351 if(required
== NULL
) {
352 for(j
= 0 ; j
< m
->prerequisites
->len
; j
++) {
353 module_release((LttvModule
*)(m
->prerequisites
->pdata
[j
]));
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
,
360 g_clear_error(&tmp_error
);
363 g_ptr_array_add(m
->prerequisites
, required
);
365 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Module %s: init()", m
->info
.name
);
369 /* Decrement the load count of the library. It will not really be
370 unloaded since it contains a currently used module. */
372 if(l
!= NULL
) library_unlock_loaded(l
);
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. */
382 LttvModule
*lttv_module_require(char *name
, GError
**error
)
384 LttvModule
*m
= module_require(name
, error
);
385 if(m
!= NULL
) m
->info
.require_count
++;
390 static void module_release(LttvModule
*m
)
394 library_lock_loaded(m
->info
.library
);
397 if(m
->info
.use_count
== 0) {
398 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Module %s: destroy()",m
->info
.name
);
400 for(i
= 0 ; i
< m
->prerequisites
->len
; i
++) {
401 module_release((LttvModule
*)(m
->prerequisites
->pdata
[i
]));
403 g_ptr_array_set_size(m
->prerequisites
, 0);
405 library_unlock_loaded(m
->info
.library
);
409 void lttv_module_release(LttvModule
*m
)
411 m
->info
.require_count
--;
416 void lttv_module_info(LttvModule
*m
, LttvModuleInfo
*info
)
422 unsigned lttv_module_prerequisite_number(LttvModule
*m
)
424 return m
->prerequisites
->len
;
428 LttvModule
*lttv_module_prerequisite_get(LttvModule
*m
, unsigned i
)
430 return (LttvModule
*)(m
->prerequisites
->pdata
[i
]);
434 void lttv_library_info(LttvLibrary
*l
, LttvLibraryInfo
*info
)
440 unsigned lttv_library_module_number(LttvLibrary
*l
)
442 return l
->modules
->len
;
446 LttvModule
*lttv_library_module_get(LttvLibrary
*l
, unsigned i
)
448 return (LttvModule
*)(l
->modules
->pdata
[i
]);
452 unsigned lttv_library_number()
454 return libraries
->len
;
458 LttvLibrary
*lttv_library_get(unsigned i
)
460 return (LttvLibrary
*)(libraries
->pdata
[i
]);
464 void lttv_library_path_add(const char *name
)
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
));
471 void lttv_library_path_remove(const char *name
)
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
);
485 unsigned lttv_library_path_number()
487 return library_paths
->len
;
491 char *lttv_library_path_get(unsigned i
)
493 return (char *)(library_paths
->pdata
[library_paths
->len
- i
- 1]);
497 void lttv_module_register(struct _LttvModuleDescription
*d
)
500 module_next
= &(d
->next
);
506 if(initialized
) return;
509 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Init module.c");
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();
519 if(builtin_chain
== NULL
) builtin_chain
= module_chain
;
520 module_chain
= builtin_chain
;
521 library_add("builtin", NULL
, NULL
);
525 static finish_destroy()
529 if(initialized
) return;
530 g_assert(!destroyed
);
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
]);
539 g_ptr_array_free(library_paths
, TRUE
);
544 static void destroy()
548 LttvLibrary
*l
, **locked_libraries
;
552 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_INFO
, "Destroy module.c");
554 /* Unload all libraries */
557 locked_libraries
= g_new(LttvLibrary
*, nb
);
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
);
567 while(l
->info
.load_count
> 0) lttv_library_unload(l
);
570 for(i
= 0 ; i
< nb
; i
++) {
571 l
= locked_libraries
[i
];
572 library_unlock_loaded(l
);
574 g_free(locked_libraries
);
576 /* The library containing module.c may be locked by our caller */
578 g_assert(libraries
->len
<= 1);
583 LTTV_MODULE("module", "Modules in libraries", \
584 "Load libraries, list, require and initialize contained modules", \
This page took 0.119718 seconds and 4 git commands to generate.