1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
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;
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.
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,
20 /* module.c : Implementation of the module loading/unloading mechanism.
24 #include <lttv/module.h>
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)
34 GPtrArray
*dependents
;
38 /* Table of loaded modules and paths where to search for modules */
40 static GHashTable
*modules
= NULL
;
42 static GPtrArray
*modulesPaths
= NULL
;
44 static void lttv_module_unload_all();
47 void lttv_module_init(int argc
, char **argv
)
49 g_info("Init module.c");
50 modules
= g_hash_table_new(g_str_hash
, g_str_equal
);
51 modulesPaths
= g_ptr_array_new();
55 void lttv_module_destroy()
59 g_info("Destroy module.c");
61 /* Unload all modules */
62 lttv_module_unload_all();
64 /* Free the modules paths pointer array as well as the elements */
65 for(i
= 0; i
< modulesPaths
->len
; i
++) {
66 g_free(modulesPaths
->pdata
[i
]);
68 g_ptr_array_free(modulesPaths
,TRUE
) ;
71 /* destroy the hash table */
72 g_hash_table_destroy(modules
) ;
77 /* Add a new pathname to the modules loading search path */
79 void lttv_module_path_add(const char *name
)
81 g_info("Add module path %s", name
);
82 g_ptr_array_add(modulesPaths
,(char*)g_strdup(name
));
87 module_load(const char *name
, int argc
, char **argv
)
97 const char *module_name
;
99 LttvModuleInit init_function
;
101 g_info("Load module %s", name
);
103 /* Try to find the module along all the user specified paths */
105 for(i
= 0 ; i
< modulesPaths
->len
; i
++) {
106 pathname
= g_module_build_path(modulesPaths
->pdata
[i
],name
);
107 g_info("Try path %s", pathname
);
108 gm
= g_module_open(pathname
,0);
111 if(gm
!= NULL
) break;
112 g_info("Trial failed, %s", g_module_error());
115 /* Try the default system path */
118 pathname
= g_module_build_path(NULL
,name
);
119 g_info("Try default path");
120 gm
= g_module_open(pathname
,0);
124 /* Module cannot be found */
126 g_info("Trial failed, %s", g_module_error());
127 g_info("Failed to load %s", name
);
131 /* Check if the module was already opened using the hopefully canonical name
132 returned by g_module_name. */
134 module_name
= g_module_name(gm
);
136 m
= g_hash_table_lookup(modules
, module_name
);
139 g_info("Module %s (%s) loaded, call its init function", name
, module_name
);
141 /* Module loaded for the first time. Insert it in the table and call the
142 init function if any. */
144 m
= g_new(LttvModule
, 1);
148 m
->dependents
= g_ptr_array_new();
149 g_hash_table_insert(modules
, (gpointer
)module_name
, m
);
151 if(!g_module_symbol(gm
, "init", (gpointer
)&init_function
)) {
152 g_warning("module %s (%s) has no init function", name
, pathname
);
154 else init_function(m
, argc
, argv
);
158 /* Module was already opened, check that it really is the same and
159 undo the extra g_module_open */
161 g_info("Module %s (%s) was already loaded, no need to call init function",
163 if(m
->module
!= gm
) g_error("Two gmodules with the same pathname");
173 lttv_module_load(const char *name
, int argc
, char **argv
)
175 g_info("Load module %s explicitly", name
);
176 LttvModule
*m
= module_load(name
, argc
, argv
);
177 if(m
!= NULL
) m
->load_count
++;
183 lttv_module_require(LttvModule
*m
, const char *name
, int argc
, char **argv
)
187 g_info("Load module %s, as %s is a dependent requiring it", name
,
188 g_module_name(m
->module
));
189 module
= module_load(name
, argc
, argv
);
190 if(module
!= NULL
) g_ptr_array_add(module
->dependents
, m
);
195 static void module_unload(LttvModule
*m
)
197 LttvModuleDestroy destroy_function
;
203 /* Decrement the reference count */
205 g_info("Unload module %s", g_module_name(m
->module
));
207 if(m
->ref_count
> 0) {
208 g_info("Module usage count decremented to %d", m
->ref_count
);
211 /* We really have to unload the module, first unload its dependents */
213 len
= m
->dependents
->len
;
214 g_info("Unload dependent modules");
216 for(i
= 0 ; i
< len
; i
++) {
217 module_unload(m
->dependents
->pdata
[i
]);
220 if(len
!= m
->dependents
->len
) g_error("dependents list modified");
222 /* Unload the module itself */
224 g_info("Call the destroy function and unload the module");
225 if(!g_module_symbol(m
->module
, "destroy", (gpointer
)&destroy_function
)) {
226 g_warning("module (%s) has no destroy function", pathname
);
228 else destroy_function();
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
);
237 void lttv_module_unload(LttvModule
*m
)
239 g_info("Explicitly unload module %s", g_module_name(m
->module
));
240 if(m
->load_count
<= 0) {
241 g_error("more unload than load (%s)", g_module_name(m
->module
));
250 list_modules(gpointer key
, gpointer value
, gpointer user_data
)
252 g_ptr_array_add((GPtrArray
*)user_data
, value
);
257 lttv_module_list(guint
*nb
)
259 GPtrArray
*list
= g_ptr_array_new();
263 g_hash_table_foreach(modules
, list_modules
, list
);
265 array
= (LttvModule
**)list
->pdata
;
266 g_ptr_array_free(list
, FALSE
);
272 lttv_module_info(LttvModule
*m
, const char **name
,
273 guint
*ref_count
, guint
*load_count
, guint
*nb_dependents
)
275 guint i
, len
= m
->dependents
->len
;
277 LttvModule
**array
= g_new(LttvModule
*, len
);
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
];
288 lttv_module_name(LttvModule
*m
)
290 return g_module_name(m
->module
);
294 list_independent(gpointer key
, gpointer value
, gpointer user_data
)
296 LttvModule
*m
= (LttvModule
*)value
;
298 if(m
->load_count
> 0) g_ptr_array_add((GPtrArray
*)user_data
, m
);
303 lttv_module_unload_all()
309 GPtrArray
*independent_modules
= g_ptr_array_new();
311 g_hash_table_foreach(modules
, list_independent
, independent_modules
);
313 for(i
= 0 ; i
< independent_modules
->len
; i
++) {
314 m
= (LttvModule
*)independent_modules
->pdata
[i
];
315 while(m
->load_count
> 0) lttv_module_unload(m
);
318 g_ptr_array_free(independent_modules
, TRUE
);
319 if(g_hash_table_size(modules
) != 0) g_warning("cannot unload all modules");