premilinary add of modular user interface implementation with a few test modules.
[lttv.git] / ltt / branches / poly / lttv / module.c
CommitLineData
eccb5352 1
2/* module.c : Implementation of the module loading/unloading mechanism.
3 *
4 */
5
6/* Initial draft by Michel Dagenais May 2003
7 * Reworked by Mathieu Desnoyers, May 2003
8 */
9
10#include <lttv/lttv.h>
11#include <lttv/module.h>
12#include <popt.h>
13
14/* Table of loaded modules and paths where to search for modules */
15
16static GHashTable *modules = NULL;
17
18static GPtrArray *modulesStandalone = NULL;
19
20static GPtrArray *modulesPaths = NULL;
21
22void lttv_module_init(int argc, char **argv) {
23 modules = g_hash_table_new(g_str_hash, g_str_equal);
24 modulesStandalone = g_ptr_array_new();
25 modulesPaths = g_ptr_array_new();
26}
27
28void lttv_module_destroy() {
29
30 int i;
31
32 /* Unload all modules */
33 lttv_module_unload_all();
34
35 /* Free the modules paths pointer array as well as the elements */
36 for(i = 0; i< modulesPaths->len; i++) {
37 g_free(modulesPaths->pdata[i]);
38 }
39 g_ptr_array_free(modulesPaths,TRUE) ;
40 g_ptr_array_free(modulesStandalone,TRUE) ;
41 modulesPaths = NULL;
42 modulesStandalone = NULL;
43
44 /* destroy the hash table */
45 g_hash_table_destroy(modules) ;
46 modules = NULL;
47}
48
49/* Add a new pathname to the modules loading search path */
50
51void lttv_module_path_add(const char *name) {
52 g_ptr_array_add(modulesPaths,(char*)g_strdup(name));
53}
54
55
56/* Load (if not already loaded) the named module. Its init function is
57 called. We pass the options of the command line to it in case it has
58 preliminary things to get from it. Note that the normal way to add a
59 command line option for a module is through the options parsing mecanism.
60 */
61
62lttv_module_info *lttv_module_load(const char *name, int argc, char **argv, loadtype load) {
63
64 GModule *gmodule;
65
66 lttv_module_info *moduleInfo;
67
68 int i;
69
70 char *pathname;
71
72 lttv_module_load_init init_Function;
73
74 /* Find and load the module, It will increase the usage counter
75 * If the module is already loaded, only the reference counter will
76 * be incremented. It's part of the gmodule architecture. Very useful
77 * for modules dependencies.
78 */
79
80 g_assert(name != NULL);
81
82 for(i = 0 ; i < modulesPaths->len ; i++) {
83 pathname = g_module_build_path(modulesPaths->pdata[i],name);
84 gmodule = g_module_open(pathname,0) ;
85
86
87 if(gmodule != NULL) {
88 g_message("Loading module %s ... found!",pathname);
89
90 /* Was the module already opened? */
91 moduleInfo = g_hash_table_lookup(modules,g_module_name(gmodule));
92
93 /* First time the module is opened */
94
95 if(moduleInfo == NULL ) {
96 moduleInfo = g_new(lttv_module_info, 1);
97 moduleInfo->module = gmodule;
98 moduleInfo->pathname = g_module_name(gmodule);
99 moduleInfo->directory = modulesPaths->pdata[i];
100 moduleInfo->name = (char *)g_strdup(name);
101 moduleInfo->ref_count = 0;
102 moduleInfo->index_standalone = -1;
103 g_hash_table_insert(modules, moduleInfo->pathname, moduleInfo);
104 if(!g_module_symbol(gmodule, "init", (gpointer) &init_Function)) {
105 g_critical("module %s (%s) does not have init function",
106 moduleInfo->pathname,moduleInfo->name);
107 }
108 else {
109 init_Function(argc,argv);
110 }
111 }
112
113 /* Add the module in the standalone array if the module is
114 * standalone and not in the array. Otherwise, set index to
115 * -1 (dependant only).
116 */
117 if(load == STANDALONE) {
118
119 if(moduleInfo->index_standalone == -1) {
120
121 g_ptr_array_add(modulesStandalone, moduleInfo);
122 moduleInfo->index_standalone = modulesStandalone->len - 1;
123
124 moduleInfo->ref_count++ ;
125 }
126 else {
127 g_warning("Module %s is already loaded standalone.",pathname);
128 /* Decrease the gmodule use_count. Has previously been increased in the g_module_open. */
129 g_module_close(moduleInfo->module) ;
130 }
131 }
132 else { /* DEPENDANT */
133 moduleInfo->ref_count++ ;
134 }
135
136 return moduleInfo;
137 }
138 g_message("Loading module %s ... missing.",pathname);
139 g_free(pathname);
140 }
141 g_critical("module %s not found",name);
142 return NULL;
143}
144
145/* Unload the named module. */
146
147int lttv_module_unload_pathname(const char *pathname, loadtype load) {
148
149 lttv_module_info *moduleInfo;
150
151 moduleInfo = g_hash_table_lookup(modules, pathname);
152
153 /* If no module of that name is loaded, nothing to unload. */
154 if(moduleInfo != NULL) {
155 g_message("Unloading module %s : is loaded.\n", pathname) ;
156 lttv_module_unload(moduleInfo, load) ;
157 return 1;
158 }
159 else {
160 g_message("Unloading module %s : is not loaded.\n", pathname) ;
161 return 0;
162 }
163
164}
165
166int lttv_module_unload_name(const char *name, loadtype load) {
167
168 int i;
169
170 char *pathname;
171
172 /* Find and load the module, It will increase the usage counter
173 * If the module is already loaded, only the reference counter will
174 * be incremented. It's part of the gmodule architecture. Very useful
175 * for modules dependencies.
176 */
177
178 g_assert(name != NULL);
179
180 for(i = 0 ; i < modulesPaths->len ; i++) {
181
182 pathname = g_module_build_path(modulesPaths->pdata[i],name);
183
184 if(lttv_module_unload_pathname(pathname, load) == TRUE)
185 return TRUE ;
186 }
187 g_critical("module %s not found",name);
188 return FALSE;
189}
190
191
192
193/* Unload the module. We use a call_gclose boolean to keep the g_module_close call
194 * after the call to the module's destroy function. */
195
196int lttv_module_unload(lttv_module_info *moduleInfo, loadtype load) {
197
198 lttv_module_unload_destroy destroy_Function;
199
200 char *moduleName ;
201
202 gboolean call_gclose = FALSE;
203
204 if(moduleInfo == NULL) return FALSE;
205
206 /* Closing the module decrements the usage counter if previously higher than
207 * 1. If 1, it unloads the module.
208 */
209
210 /* Add the module in the standalone array if the module is
211 * standalone and not in the array. Otherwise, set index to
212 * -1 (dependant only).
213 */
214 if(load == STANDALONE) {
215
216 if(moduleInfo->index_standalone == -1) {
217
218 g_warning("Module %s is not loaded standalone.",moduleInfo->pathname);
219 }
220 else {
221 /* We do not remove the element of the array, it would change
222 * the index orders. We will have to check if index is -1 in
223 * unload all modules.
224 */
225 moduleInfo->index_standalone = -1;
226 g_message("Unloading module %s, reference count passes from %u to %u",
227 moduleInfo->pathname,moduleInfo->ref_count,
228 moduleInfo->ref_count-1);
229
230 moduleInfo->ref_count-- ;
231 call_gclose = TRUE ;
232 }
233 }
234 else { /* DEPENDANT */
235 g_message("Unloading module %s, reference count passes from %u to %u",
236 moduleInfo->pathname,
237 moduleInfo->ref_count,moduleInfo->ref_count-1);
238
239 moduleInfo->ref_count-- ;
240 call_gclose = TRUE ;
241 }
242
243 /* The module is really closing if ref_count is 0 */
244 if(!moduleInfo->ref_count) {
245 g_message("Unloading module %s : closing module.",moduleInfo->pathname);
246
247 /* Call the destroy function of the module */
248 if(!g_module_symbol(moduleInfo->module, "destroy", (gpointer) &destroy_Function)) {
249 g_critical("module %s (%s) does not have destroy function",
250 moduleInfo->pathname,moduleInfo->name);
251 }
252 else {
253 destroy_Function();
254 }
255
256 /* If the module will effectively be closed, remove the moduleInfo from
257 * the hash table and free the module name.
258 */
259 g_free(moduleInfo->name) ;
260
261 g_hash_table_remove(modules, moduleInfo->pathname);
262 }
263
264 if(call_gclose) g_module_close(moduleInfo->module) ;
265
266 return TRUE ;
267}
268
269#define MODULE_I ((lttv_module_info *)modulesStandalone->pdata[i])
270
271/* unload all the modules in the hash table, calling module_destroy for
272 * each of them.
273 *
274 * We first take all the moduleInfo in the hash table, put it in an
275 * array. We use qsort on the array to have the use count of 1 first.
276 */
277void lttv_module_unload_all() {
278
279 int i = 0;
280
281 /* call the unload for each module.
282 */
283 for(i = 0; i < modulesStandalone->len; i++) {
284
285 if(MODULE_I->index_standalone != -1) {
286 lttv_module_unload(MODULE_I,STANDALONE) ;
287 }
288 }
289
290}
This page took 0.032201 seconds and 4 git commands to generate.