2 /* module.c : Implementation of the module loading/unloading mechanism.
6 #include <lttv/module.h>
14 GPtrArray
*dependents
;
18 /* Table of loaded modules and paths where to search for modules */
20 static GHashTable
*modules
= NULL
;
22 static GPtrArray
*modulesPaths
= NULL
;
24 static void lttv_module_unload_all();
27 void lttv_module_init(int argc
, char **argv
)
29 modules
= g_hash_table_new(g_str_hash
, g_str_equal
);
30 modulesPaths
= g_ptr_array_new();
34 void lttv_module_destroy()
38 /* Unload all modules */
39 lttv_module_unload_all();
41 /* Free the modules paths pointer array as well as the elements */
42 for(i
= 0; i
< modulesPaths
->len
; i
++) {
43 g_free(modulesPaths
->pdata
[i
]);
45 g_ptr_array_free(modulesPaths
,TRUE
) ;
48 /* destroy the hash table */
49 g_hash_table_destroy(modules
) ;
54 /* Add a new pathname to the modules loading search path */
56 void lttv_module_path_add(const char *name
)
58 g_ptr_array_add(modulesPaths
,(char*)g_strdup(name
));
63 module_load(const char *name
, int argc
, char **argv
)
73 const char *module_name
;
75 LttvModuleInit init_function
;
77 /* Try to find the module along all the user specified paths */
79 for(i
= 0 ; i
< modulesPaths
->len
; i
++) {
80 pathname
= g_module_build_path(modulesPaths
->pdata
[i
],name
);
81 gm
= g_module_open(pathname
,G_MODULE_BIND_LAZY
);
82 g_critical("module : %s", pathname
);
83 g_critical("erreur : %s", g_module_error());
89 /* Try the default system path */
92 pathname
= g_module_build_path(NULL
,name
);
93 gm
= g_module_open(pathname
,G_MODULE_BIND_LAZY
);
94 g_critical("module : %s", pathname
);
98 /* Module cannot be found */
100 g_critical("module est null");
101 if(gm
== NULL
) return NULL
;
103 /* Check if the module was already opened using the hopefully canonical name
104 returned by g_module_name. */
106 module_name
= g_module_name(gm
);
108 m
= g_hash_table_lookup(modules
, module_name
);
112 /* Module loaded for the first time. Insert it in the table and call the
113 init function if any. */
115 m
= g_new(LttvModule
, 1);
119 m
->dependents
= g_ptr_array_new();
120 g_hash_table_insert(modules
, (gpointer
)module_name
, m
);
122 if(!g_module_symbol(gm
, "init", (gpointer
)&init_function
)) {
123 g_warning("module %s (%s) has no init function", name
, pathname
);
125 else init_function(m
, argc
, argv
);
129 /* Module was already opened, check that it really is the same and
130 undo the extra g_module_open */
132 if(m
->module
!= gm
) g_error("Two gmodules with the same pathname");
142 lttv_module_load(const char *name
, int argc
, char **argv
)
144 LttvModule
*m
= module_load(name
, argc
, argv
);
145 if(m
!= NULL
) m
->load_count
++;
151 lttv_module_require(LttvModule
*m
, const char *name
, int argc
, char **argv
)
155 module
= module_load(name
, argc
, argv
);
156 if(module
!= NULL
) g_ptr_array_add(m
->dependents
, module
);
161 static void module_unload(LttvModule
*m
)
163 LttvModuleDestroy destroy_function
;
169 /* Decrement the reference count */
172 if(m
->ref_count
> 0) return;
174 /* We really have to unload the module, first unload its dependents */
176 len
= m
->dependents
->len
;
178 for(i
= 0 ; i
< len
; i
++) {
179 module_unload(m
->dependents
->pdata
[i
]);
182 if(len
!= m
->dependents
->len
) g_error("dependents list modified");
184 /* Unload the module itself */
186 if(!g_module_symbol(m
->module
, "destroy", (gpointer
)&destroy_function
)) {
187 g_warning("module (%s) has no destroy function", pathname
);
189 else destroy_function();
191 g_hash_table_remove(modules
, g_module_name(m
->module
));
192 g_ptr_array_free(m
->dependents
, TRUE
);
193 g_module_close(m
->module
);
198 void lttv_module_unload(LttvModule
*m
)
200 if(m
->load_count
<= 0) {
201 g_error("more unload than load (%s)", g_module_name(m
->module
));
210 list_modules(gpointer key
, gpointer value
, gpointer user_data
)
212 g_ptr_array_add((GPtrArray
*)user_data
, value
);
217 lttv_module_list(guint
*nb
)
219 GPtrArray
*list
= g_ptr_array_new();
223 g_hash_table_foreach(modules
, list_modules
, list
);
225 array
= (LttvModule
**)list
->pdata
;
226 g_ptr_array_free(list
, FALSE
);
232 lttv_module_info(LttvModule
*m
, const char **name
,
233 guint
*ref_count
, guint
*load_count
, guint
*nb_dependents
)
235 guint i
, len
= m
->dependents
->len
;
237 LttvModule
**array
= g_new(LttvModule
*, len
);
239 *name
= g_module_name(m
->module
);
240 *ref_count
= m
->ref_count
;
241 *load_count
= m
->load_count
;
242 *nb_dependents
= len
;
243 for(i
= 0 ; i
< len
; i
++) array
[i
] = m
->dependents
->pdata
[i
];
249 list_independent(gpointer key
, gpointer value
, gpointer user_data
)
251 LttvModule
*m
= (LttvModule
*)value
;
253 if(m
->load_count
> 0) g_ptr_array_add((GPtrArray
*)user_data
, m
);
258 lttv_module_unload_all()
264 GPtrArray
*independent_modules
= g_ptr_array_new();
266 g_hash_table_foreach(modules
, list_independent
, independent_modules
);
268 for(i
= 0 ; i
< independent_modules
->len
; i
++) {
269 m
= (LttvModule
*)independent_modules
->pdata
[i
];
270 while(m
->load_count
> 0) lttv_module_unload(m
);
273 g_ptr_array_free(independent_modules
, TRUE
);
274 if(g_hash_table_size(modules
) != 0) g_warning("cannot unload all modules");