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