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