Changed automake files to reflect the new header files.
[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
dc877563 62static LttvModuleInfo *
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;
72
dc877563 73 LttvModuleInit init_function;
eccb5352 74
dc877563 75 /* Try to find the module along all the user specified paths */
eccb5352 76
77 for(i = 0 ; i < modulesPaths->len ; i++) {
78 pathname = g_module_build_path(modulesPaths->pdata[i],name);
dc877563 79 gm = g_module_open(pathname,0);
80 g_free(pathname);
eccb5352 81
dc877563 82 if(gm != NULL) break;
83 }
84
85 /* Try the default system path */
86
87 if(gm == NULL) {
88 pathname = g_module_build_path(NULL,name);
89 gm = g_module_open(pathname,0);
eccb5352 90 g_free(pathname);
91 }
eccb5352 92
dc877563 93 /* Module cannot be found */
94
95 if(gm == NULL) return NULL;
96
97 /* Check if the module was already opened using the hopefully canonical name
98 returned by g_module_name. */
99
100 pathname = g_module_name(gm);
eccb5352 101
dc877563 102 m = g_hash_table_lookup(modules, pathname);
eccb5352 103
dc877563 104 if(m == NULL) {
eccb5352 105
dc877563 106 /* Module loaded for the first time. Insert it in the table and call the
107 init function if any. */
eccb5352 108
dc877563 109 m = g_new(LttvModule);
110 m->module = gm;
111 m->ref_count = 0;
112 m->load_count = 0;
113 m->dependents = g_ptr_array_new();
114 g_hash_table_insert(modules, pathname, m);
115
116 if(!g_module_symbol(gm, "init", (gpointer)&init_function)) {
117 g_warning("module %s (%s) has no init function", name, pathname);
118 }
996acd92 119 else init_Function(m, argc, argv);
eccb5352 120 }
121 else {
dc877563 122
123 /* Module was already opened, check that it really is the same and
124 undo the extra g_module_open */
125
126 if(m->module != gm) g_error("Two gmodules with the same pathname");
127 g_module_close(gm);
eccb5352 128 }
129
dc877563 130 m->ref_count++;
131 return m;
eccb5352 132}
133
eccb5352 134
dc877563 135LttvModuleInfo *
136lttv_module_load(const char *name, int argc, char **argv)
137{
138 LttvModule *m = module_load(name, argc, argv);
eccb5352 139
dc877563 140 if(m != NULL) m->load_count++;
141 return m;
142}
eccb5352 143
eccb5352 144
dc877563 145LttvModule *
146lttv_module_require(LttvModule *m, const char *name, int argc, char **argv)
147{
148 LttvModule *module;
eccb5352 149
dc877563 150 module = module_load(name, argc, argv);
151 if(module != NULL) g_ptr_array_add(m->dependents, module);
152 return module;
eccb5352 153}
154
155
dc877563 156static void module_unload(LttvModule *m)
157{
158 LttvModuleDestroy destroy_function;
eccb5352 159
dc877563 160 char *pathname;
eccb5352 161
dc877563 162 guint len;
eccb5352 163
dc877563 164 /* Decrement the reference count */
eccb5352 165
dc877563 166 m->ref_count--;
167 if(m->ref_count > 0) return;
eccb5352 168
dc877563 169 /* We really have to unload the module, first unload its dependents */
eccb5352 170
dc877563 171 len = m->dependents->len;
eccb5352 172
dc877563 173 for(i = 0 ; i < len ; i++) {
174 module_unload(m->dependents->pdata[i]);
eccb5352 175 }
eccb5352 176
dc877563 177 if(len != m->dependents->len) g_error("dependents list modified");
178
179 /* Unload the module itself */
180
181 if(!g_module_symbol(m->module, "destroy", (gpointer)&destroy_function)) {
182 g_warning("module (%s) has no destroy function", pathname);
eccb5352 183 }
dc877563 184 else destroy_function();
eccb5352 185
dc877563 186 g_hash_table_remove(modules, g_module_name(m->module));
187 g_ptr_array_free(m->dependents, TRUE);
188 g_module_close(m->module);
189 g_free(m);
190}
eccb5352 191
eccb5352 192
dc877563 193void lttv_module_unload(LttvModule *m)
194{
195 if(m->load_count <= 0) {
196 g_error("more unload than load (%s)", g_module_name(m->module));
197 return;
eccb5352 198 }
dc877563 199 m->load_count--;
200 module_unload(m);
201}
202
eccb5352 203
dc877563 204static void
205list_modules(gpointer key, gpointer value, gpointer user_data)
206{
207 g_ptr_array_add((GPtrArray *)user_data, value);
eccb5352 208}
209
dc877563 210
211LttvModule **
212lttv_module_list(guint *nb)
213{
214 GPtrArray *list = g_ptr_array_new();
215
216 LttvModule **array;
217
218 g_hash_table_foreach(modules, list_modules, list);
219 *nb = list->len;
220 array = (LttvModule **)list->pdata;
221 g_ptr_array_free(list, FALSE);
222 return array;
223}
224
225
226LttvModule **
227lttv_module_info(LttvModule *m, const char **name,
228 guint *ref_count, guint *load_count, guint *nb_dependents)
229{
230 guint i, len = m->dependents->len;
231
232 LttvModule **array = g_new(LttvModule *, len);
233
234 *name = g_module_name(m->module);
235 *ref_count = m->ref_count;
236 *load_count = m->load_count;
237 *nb_dependents = len;
238 for(i = 0 ; i < len ; i++) array[i] = m->dependents->pdata[i];
239 return array;
240}
241
242
243static void
244list_independent(gpointer key, gpointer value, gpointer user_data)
245{
246 LttvModule *m = (LttvModule *)value;
247
248 if(m->load_count > 0) g_ptr_array_add((GPtrArray *)user_data, m);
249}
250
251
252void
253lttv_module_unload_all()
254{
255 guint i;
256
257 LttvModule *m;
258
259 GPtrArray *independent_modules = g_ptr_array_new();
260
261 g_hash_table_foreach(modules, list_independent, independent_modules);
262
263 for(i = 0 ; i < independent_modules->len ; i++) {
264 m = (LttvModule)independent_modules->pdata[i];
265 while(m->load_count > 0) lttv_module_unload(m);
eccb5352 266 }
dc877563 267
268 g_ptr_array_free(independent_modules, TRUE);
269 if(g_hash_table_size(modules) != 0) g_warning("cannot unload all modules");
eccb5352 270}
This page took 0.03461 seconds and 4 git commands to generate.