old files clean
[lttv.git] / ltt / branches / poly / lttv / main / module.c
CommitLineData
eccb5352 1
2/* module.c : Implementation of the module loading/unloading mechanism.
3 *
4 */
5
3d218f2a 6#include <lttv/module.h>
dc877563 7
b445142a 8#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
9#define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
dc877563 10
11struct _LttvModule
12{
13 GModule *module;
14 guint ref_count;
15 guint load_count;
16 GPtrArray *dependents;
17};
18
eccb5352 19
20/* Table of loaded modules and paths where to search for modules */
21
22static GHashTable *modules = NULL;
23
eccb5352 24static GPtrArray *modulesPaths = NULL;
25
dc877563 26static void lttv_module_unload_all();
27
28
29void lttv_module_init(int argc, char **argv)
30{
b445142a 31 g_info("Init module.c");
eccb5352 32 modules = g_hash_table_new(g_str_hash, g_str_equal);
eccb5352 33 modulesPaths = g_ptr_array_new();
34}
35
dc877563 36
37void lttv_module_destroy()
38{
eccb5352 39 int i;
40
b445142a 41 g_info("Destroy module.c");
42
eccb5352 43 /* Unload all modules */
44 lttv_module_unload_all();
45
46 /* Free the modules paths pointer array as well as the elements */
dc877563 47 for(i = 0; i < modulesPaths->len ; i++) {
eccb5352 48 g_free(modulesPaths->pdata[i]);
49 }
50 g_ptr_array_free(modulesPaths,TRUE) ;
eccb5352 51 modulesPaths = NULL;
eccb5352 52
53 /* destroy the hash table */
54 g_hash_table_destroy(modules) ;
55 modules = NULL;
56}
57
dc877563 58
eccb5352 59/* Add a new pathname to the modules loading search path */
60
dc877563 61void lttv_module_path_add(const char *name)
62{
b445142a 63 g_info("Add module path %s", name);
eccb5352 64 g_ptr_array_add(modulesPaths,(char*)g_strdup(name));
65}
66
67
ffd54a90 68static LttvModule *
dc877563 69module_load(const char *name, int argc, char **argv)
70{
71 GModule *gm;
eccb5352 72
dc877563 73 LttvModule *m;
eccb5352 74
75 int i;
76
77 char *pathname;
ffd54a90 78
79 const char *module_name;
eccb5352 80
dc877563 81 LttvModuleInit init_function;
eccb5352 82
b445142a 83 g_info("Load module %s", name);
84
dc877563 85 /* Try to find the module along all the user specified paths */
eccb5352 86
87 for(i = 0 ; i < modulesPaths->len ; i++) {
88 pathname = g_module_build_path(modulesPaths->pdata[i],name);
b445142a 89 g_info("Try path %s", pathname);
90 gm = g_module_open(pathname,0);
dc877563 91 g_free(pathname);
eccb5352 92
dc877563 93 if(gm != NULL) break;
b445142a 94 g_info("Trial failed, %s", g_module_error());
dc877563 95 }
96
97 /* Try the default system path */
98
99 if(gm == NULL) {
100 pathname = g_module_build_path(NULL,name);
b445142a 101 g_info("Try default path");
102 gm = g_module_open(pathname,0);
eccb5352 103 g_free(pathname);
104 }
eccb5352 105
dc877563 106 /* Module cannot be found */
b445142a 107 if(gm == NULL) {
108 g_info("Trial failed, %s", g_module_error());
109 g_info("Failed to load %s", name);
110 return NULL;
111 }
dc877563 112
113 /* Check if the module was already opened using the hopefully canonical name
114 returned by g_module_name. */
115
ffd54a90 116 module_name = g_module_name(gm);
eccb5352 117
ffd54a90 118 m = g_hash_table_lookup(modules, module_name);
eccb5352 119
dc877563 120 if(m == NULL) {
b445142a 121 g_info("Module %s (%s) loaded, call its init function", name, module_name);
eccb5352 122
dc877563 123 /* Module loaded for the first time. Insert it in the table and call the
124 init function if any. */
eccb5352 125
ffd54a90 126 m = g_new(LttvModule, 1);
dc877563 127 m->module = gm;
128 m->ref_count = 0;
129 m->load_count = 0;
130 m->dependents = g_ptr_array_new();
ffd54a90 131 g_hash_table_insert(modules, (gpointer)module_name, m);
dc877563 132
133 if(!g_module_symbol(gm, "init", (gpointer)&init_function)) {
134 g_warning("module %s (%s) has no init function", name, pathname);
135 }
c432246e 136 else init_function(m, argc, argv);
eccb5352 137 }
138 else {
dc877563 139
140 /* Module was already opened, check that it really is the same and
141 undo the extra g_module_open */
142
b445142a 143 g_info("Module %s (%s) was already loaded, no need to call init function",
144 name, module_name);
dc877563 145 if(m->module != gm) g_error("Two gmodules with the same pathname");
146 g_module_close(gm);
eccb5352 147 }
148
dc877563 149 m->ref_count++;
150 return m;
eccb5352 151}
152
eccb5352 153
ffd54a90 154LttvModule *
dc877563 155lttv_module_load(const char *name, int argc, char **argv)
156{
b445142a 157 g_info("Load module %s explicitly", name);
dc877563 158 LttvModule *m = module_load(name, argc, argv);
dc877563 159 if(m != NULL) m->load_count++;
160 return m;
161}
eccb5352 162
eccb5352 163
dc877563 164LttvModule *
165lttv_module_require(LttvModule *m, const char *name, int argc, char **argv)
166{
167 LttvModule *module;
eccb5352 168
b445142a 169 g_info("Load module %s, as %s is a dependent requiring it", name,
170 g_module_name(m->module));
dc877563 171 module = module_load(name, argc, argv);
86e73802 172 if(module != NULL) g_ptr_array_add(module->dependents, m);
dc877563 173 return module;
eccb5352 174}
175
176
dc877563 177static void module_unload(LttvModule *m)
178{
179 LttvModuleDestroy destroy_function;
eccb5352 180
dc877563 181 char *pathname;
eccb5352 182
ffd54a90 183 guint i, len;
eccb5352 184
dc877563 185 /* Decrement the reference count */
eccb5352 186
b445142a 187 g_info("Unload module %s", g_module_name(m->module));
dc877563 188 m->ref_count--;
b445142a 189 if(m->ref_count > 0) {
190 g_info("Module usage count decremented to %d", m->ref_count);
191 return;
192 }
dc877563 193 /* We really have to unload the module, first unload its dependents */
eccb5352 194
dc877563 195 len = m->dependents->len;
b445142a 196 g_info("Unload dependent modules");
eccb5352 197
dc877563 198 for(i = 0 ; i < len ; i++) {
199 module_unload(m->dependents->pdata[i]);
eccb5352 200 }
eccb5352 201
dc877563 202 if(len != m->dependents->len) g_error("dependents list modified");
203
204 /* Unload the module itself */
205
b445142a 206 g_info("Call the destroy function and unload the module");
dc877563 207 if(!g_module_symbol(m->module, "destroy", (gpointer)&destroy_function)) {
208 g_warning("module (%s) has no destroy function", pathname);
eccb5352 209 }
dc877563 210 else destroy_function();
eccb5352 211
dc877563 212 g_hash_table_remove(modules, g_module_name(m->module));
213 g_ptr_array_free(m->dependents, TRUE);
214 g_module_close(m->module);
215 g_free(m);
216}
eccb5352 217
eccb5352 218
dc877563 219void lttv_module_unload(LttvModule *m)
220{
b445142a 221 g_info("Explicitly unload module %s", g_module_name(m->module));
dc877563 222 if(m->load_count <= 0) {
223 g_error("more unload than load (%s)", g_module_name(m->module));
224 return;
eccb5352 225 }
dc877563 226 m->load_count--;
227 module_unload(m);
228}
229
eccb5352 230
dc877563 231static void
232list_modules(gpointer key, gpointer value, gpointer user_data)
233{
234 g_ptr_array_add((GPtrArray *)user_data, value);
eccb5352 235}
236
dc877563 237
238LttvModule **
239lttv_module_list(guint *nb)
240{
241 GPtrArray *list = g_ptr_array_new();
242
243 LttvModule **array;
244
245 g_hash_table_foreach(modules, list_modules, list);
246 *nb = list->len;
247 array = (LttvModule **)list->pdata;
248 g_ptr_array_free(list, FALSE);
249 return array;
250}
251
252
253LttvModule **
254lttv_module_info(LttvModule *m, const char **name,
255 guint *ref_count, guint *load_count, guint *nb_dependents)
256{
257 guint i, len = m->dependents->len;
258
259 LttvModule **array = g_new(LttvModule *, len);
260
261 *name = g_module_name(m->module);
262 *ref_count = m->ref_count;
263 *load_count = m->load_count;
264 *nb_dependents = len;
265 for(i = 0 ; i < len ; i++) array[i] = m->dependents->pdata[i];
266 return array;
267}
268
36b3c068 269char *
270lttv_module_name(LttvModule *m)
271{
272 return g_module_name(m->module);
273}
dc877563 274
275static void
276list_independent(gpointer key, gpointer value, gpointer user_data)
277{
278 LttvModule *m = (LttvModule *)value;
279
280 if(m->load_count > 0) g_ptr_array_add((GPtrArray *)user_data, m);
281}
282
283
284void
285lttv_module_unload_all()
286{
287 guint i;
288
289 LttvModule *m;
290
291 GPtrArray *independent_modules = g_ptr_array_new();
292
293 g_hash_table_foreach(modules, list_independent, independent_modules);
294
295 for(i = 0 ; i < independent_modules->len ; i++) {
ffd54a90 296 m = (LttvModule *)independent_modules->pdata[i];
dc877563 297 while(m->load_count > 0) lttv_module_unload(m);
eccb5352 298 }
dc877563 299
300 g_ptr_array_free(independent_modules, TRUE);
301 if(g_hash_table_size(modules) != 0) g_warning("cannot unload all modules");
eccb5352 302}
This page took 0.041708 seconds and 4 git commands to generate.