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