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