2 /* module.c : Implementation of the module loading/unloading mechanism.
6 /* Initial draft by Michel Dagenais May 2003
7 * Reworked by Mathieu Desnoyers, May 2003
14 /* Table of loaded modules and paths where to search for modules */
16 static GHashTable
*modules
= NULL
;
18 static GPtrArray
*modulesStandalone
= NULL
;
20 static GPtrArray
*modulesPaths
= NULL
;
22 void lttv_module_init(int argc
, char **argv
) {
23 modules
= g_hash_table_new(g_str_hash
, g_str_equal
);
24 modulesStandalone
= g_ptr_array_new();
25 modulesPaths
= g_ptr_array_new();
28 void lttv_module_destroy() {
32 /* Unload all modules */
33 lttv_module_unload_all();
35 /* Free the modules paths pointer array as well as the elements */
36 for(i
= 0; i
< modulesPaths
->len
; i
++) {
37 g_free(modulesPaths
->pdata
[i
]);
39 g_ptr_array_free(modulesPaths
,TRUE
) ;
40 g_ptr_array_free(modulesStandalone
,TRUE
) ;
42 modulesStandalone
= NULL
;
44 /* destroy the hash table */
45 g_hash_table_destroy(modules
) ;
49 /* Add a new pathname to the modules loading search path */
51 void lttv_module_path_add(const char *name
) {
52 g_ptr_array_add(modulesPaths
,(char*)g_strdup(name
));
56 /* Load (if not already loaded) the named module. Its init function is
57 called. We pass the options of the command line to it in case it has
58 preliminary things to get from it. Note that the normal way to add a
59 command line option for a module is through the options parsing mecanism.
62 lttv_module_info
*lttv_module_load(const char *name
, int argc
, char **argv
, loadtype load
) {
66 lttv_module_info
*moduleInfo
;
72 lttv_module_load_init init_Function
;
74 /* Find and load the module, It will increase the usage counter
75 * If the module is already loaded, only the reference counter will
76 * be incremented. It's part of the gmodule architecture. Very useful
77 * for modules dependencies.
80 g_assert(name
!= NULL
);
82 for(i
= 0 ; i
< modulesPaths
->len
; i
++) {
83 pathname
= g_module_build_path(modulesPaths
->pdata
[i
],name
);
84 gmodule
= g_module_open(pathname
,0) ;
88 g_message("Loading module %s ... found!",pathname
);
90 /* Was the module already opened? */
91 moduleInfo
= g_hash_table_lookup(modules
,g_module_name(gmodule
));
93 /* First time the module is opened */
95 if(moduleInfo
== NULL
) {
96 moduleInfo
= g_new(lttv_module_info
, 1);
97 moduleInfo
->module
= gmodule
;
98 moduleInfo
->pathname
= g_module_name(gmodule
);
99 moduleInfo
->directory
= modulesPaths
->pdata
[i
];
100 moduleInfo
->name
= (char *)g_strdup(name
);
101 moduleInfo
->ref_count
= 0;
102 moduleInfo
->index_standalone
= -1;
103 g_hash_table_insert(modules
, moduleInfo
->pathname
, moduleInfo
);
104 if(!g_module_symbol(gmodule
, "init", (gpointer
) &init_Function
)) {
105 g_critical("module %s (%s) does not have init function",
106 moduleInfo
->pathname
,moduleInfo
->name
);
109 init_Function(argc
,argv
);
113 /* Add the module in the standalone array if the module is
114 * standalone and not in the array. Otherwise, set index to
115 * -1 (dependant only).
117 if(load
== STANDALONE
) {
119 if(moduleInfo
->index_standalone
== -1) {
121 g_ptr_array_add(modulesStandalone
, moduleInfo
);
122 moduleInfo
->index_standalone
= modulesStandalone
->len
- 1;
124 moduleInfo
->ref_count
++ ;
127 g_warning("Module %s is already loaded standalone.",pathname
);
128 /* Decrease the gmodule use_count. Has previously been increased in the g_module_open. */
129 g_module_close(moduleInfo
->module
) ;
132 else { /* DEPENDANT */
133 moduleInfo
->ref_count
++ ;
138 g_message("Loading module %s ... missing.",pathname
);
141 g_critical("module %s not found",name
);
145 /* Unload the named module. */
147 int lttv_module_unload_pathname(const char *pathname
, loadtype load
) {
149 lttv_module_info
*moduleInfo
;
151 moduleInfo
= g_hash_table_lookup(modules
, pathname
);
153 /* If no module of that name is loaded, nothing to unload. */
154 if(moduleInfo
!= NULL
) {
155 g_message("Unloading module %s : is loaded.\n", pathname
) ;
156 lttv_module_unload(moduleInfo
, load
) ;
160 g_message("Unloading module %s : is not loaded.\n", pathname
) ;
166 int lttv_module_unload_name(const char *name
, loadtype load
) {
172 /* Find and load the module, It will increase the usage counter
173 * If the module is already loaded, only the reference counter will
174 * be incremented. It's part of the gmodule architecture. Very useful
175 * for modules dependencies.
178 g_assert(name
!= NULL
);
180 for(i
= 0 ; i
< modulesPaths
->len
; i
++) {
182 pathname
= g_module_build_path(modulesPaths
->pdata
[i
],name
);
184 if(lttv_module_unload_pathname(pathname
, load
) == TRUE
)
187 g_critical("module %s not found",name
);
193 /* Unload the module. We use a call_gclose boolean to keep the g_module_close call
194 * after the call to the module's destroy function. */
196 int lttv_module_unload(lttv_module_info
*moduleInfo
, loadtype load
) {
198 lttv_module_unload_destroy destroy_Function
;
202 gboolean call_gclose
= FALSE
;
204 if(moduleInfo
== NULL
) return FALSE
;
206 /* Closing the module decrements the usage counter if previously higher than
207 * 1. If 1, it unloads the module.
210 /* Add the module in the standalone array if the module is
211 * standalone and not in the array. Otherwise, set index to
212 * -1 (dependant only).
214 if(load
== STANDALONE
) {
216 if(moduleInfo
->index_standalone
== -1) {
218 g_warning("Module %s is not loaded standalone.",moduleInfo
->pathname
);
221 /* We do not remove the element of the array, it would change
222 * the index orders. We will have to check if index is -1 in
223 * unload all modules.
225 moduleInfo
->index_standalone
= -1;
226 g_message("Unloading module %s, reference count passes from %u to %u",
227 moduleInfo
->pathname
,moduleInfo
->ref_count
,
228 moduleInfo
->ref_count
-1);
230 moduleInfo
->ref_count
-- ;
234 else { /* DEPENDANT */
235 g_message("Unloading module %s, reference count passes from %u to %u",
236 moduleInfo
->pathname
,
237 moduleInfo
->ref_count
,moduleInfo
->ref_count
-1);
239 moduleInfo
->ref_count
-- ;
243 /* The module is really closing if ref_count is 0 */
244 if(!moduleInfo
->ref_count
) {
245 g_message("Unloading module %s : closing module.",moduleInfo
->pathname
);
247 /* Call the destroy function of the module */
248 if(!g_module_symbol(moduleInfo
->module
, "destroy", (gpointer
) &destroy_Function
)) {
249 g_critical("module %s (%s) does not have destroy function",
250 moduleInfo
->pathname
,moduleInfo
->name
);
256 /* If the module will effectively be closed, remove the moduleInfo from
257 * the hash table and free the module name.
259 g_free(moduleInfo
->name
) ;
261 g_hash_table_remove(modules
, moduleInfo
->pathname
);
264 if(call_gclose
) g_module_close(moduleInfo
->module
) ;
269 #define MODULE_I ((lttv_module_info *)modulesStandalone->pdata[i])
271 /* unload all the modules in the hash table, calling module_destroy for
274 * We first take all the moduleInfo in the hash table, put it in an
275 * array. We use qsort on the array to have the use count of 1 first.
277 void lttv_module_unload_all() {
281 /* call the unload for each module.
283 for(i
= 0; i
< modulesStandalone
->len
; i
++) {
285 if(MODULE_I
->index_standalone
!= -1) {
286 lttv_module_unload(MODULE_I
,STANDALONE
) ;