2 * ion/ioncore/modules.c
4 * Copyright (c) Arnout Engelen 2011
5 * Copyright (c) Tuomo Valkonen 1999-2009.
7 * See the included file LICENSE for details.
16 #include <libextl/readconfig.h>
20 #include "../version.h"
23 #ifndef CF_PRELOAD_MODULES
29 typedef void *dlhandle
;
32 static Rb_node modules
=NULL
;
35 static dlhandle
get_handle(const char *name
)
40 nd
=rb_find_key_n(modules
, name
, &found
);
47 static const char *get_name(dlhandle handle
)
51 rb_traverse(nd
, modules
){
53 return (const char *)(nd
->k
.key
);
59 static Rb_node
add_module(char *name
, dlhandle handle
)
61 return rb_insert(modules
, name
, handle
);
68 /*{{{ Module symbol access */
71 static void *get_module_symbol(dlhandle handle
,
72 const char *modulename
,
78 p
=scat(modulename
, name
);
90 static void (*get_module_fptr(dlhandle handle
,
91 const char *modulename
,
92 const char *name
))(void **)
94 /* This is not valid ISO C. However, it is 'tried and tested'. The
95 * workaround originally recommended[1] is not alias-safe[2]. The approach
96 * we chose, while not valid ISO C, *is* valid under POSIX 2008[3]. Newer
97 * versions of GCC should not warn about it anymore[4].
99 * [1] http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html#tag_03_112_06)
100 * [2] http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45289#c1
101 * [3] http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_12_03
102 * [4] http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45289#c10
104 return (void (*)(void**)) get_module_symbol(handle
, modulename
, name
);
107 static char *get_version(dlhandle handle
, const char *modulename
)
109 return (char*)get_module_symbol(handle
, modulename
,
113 static bool check_has_version(dlhandle handle
, const char *modulename
)
115 return get_version(handle
, modulename
) != NULL
;
118 static bool check_version(dlhandle handle
, const char *modulename
)
120 char *versionstr
=get_version(handle
, modulename
);
123 return (strcmp(versionstr
, NOTION_API_VERSION
)==0);
127 static bool call_init(dlhandle handle
, const char *modulename
)
129 bool (*initfn
)(void);
131 initfn
=(bool (*)())get_module_fptr(handle
, modulename
, "_init");
140 static void call_deinit(dlhandle handle
, const char *modulename
)
142 void (*deinitfn
)(void);
144 deinitfn
=(void (*)())get_module_fptr(handle
, modulename
, "_deinit");
157 bool ioncore_init_module_support()
160 return (modules
!=NULL
);
164 static int try_load(const char *file
, void *param
)
166 dlhandle handle
=NULL
;
167 const char *slash
, *dot
;
171 if(access(file
, F_OK
)!=0)
172 return EXTL_TRYCONFIG_NOTFOUND
;
174 slash
=strrchr(file
, '/');
175 dot
=strrchr(file
, '.');
183 warn(TR("Invalid module name."));
187 name
=ALLOC_N(char, dot
-slash
+1);
191 strncpy(name
, slash
, dot
-slash
);
192 name
[dot
-slash
]='\0';
194 if(get_handle(name
)){
195 warn_obj(file
, TR("The module is already loaded."));
199 handle
=dlopen(file
, RTLD_NOW
|RTLD_GLOBAL
);
202 warn_obj(file
, "%s", dlerror());
207 return EXTL_TRYCONFIG_OK
;
209 if(!check_has_version(handle
, name
)){
210 warn_obj(file
, TR("Module version information for %s not found. "
211 "Refusing to use."), name
);
215 if(!check_version(handle
, name
)){
216 warn_obj(file
, TR("Module version mismatch: expected '%s', found '%s'."
217 " Refusing to use."),
218 NOTION_API_VERSION
, get_version(handle
, name
));
222 mod
=add_module(name
, handle
);
227 if(!call_init(handle
, name
)){
228 warn_obj(file
, TR("Unable to initialise module %s."), name
);
233 return EXTL_TRYCONFIG_OK
;
240 return EXTL_TRYCONFIG_LOAD_FAILED
;
243 static bool do_load_module(const char *modname
)
246 const char *extension
= "so";
248 retval
=extl_try_config(modname
, NULL
, (ExtlTryConfigFn
*)try_load
,
249 NULL
, extension
, NULL
);
251 if(retval
==EXTL_TRYCONFIG_NOTFOUND
)
252 warn(TR("Unable to find '%s.%s' on search path."), modname
, extension
);
254 return (retval
==EXTL_TRYCONFIG_OK
);
264 static void do_unload_module(Rb_node mod
)
266 char *name
=(char*)mod
->k
.key
;
267 dlhandle handle
=mod
->v
.val
;
269 call_deinit(handle
, name
);
276 void ioncore_unload_modules()
280 rb_traverse(mod
, modules
){
281 do_unload_module(mod
);
292 /*{{{ Static module support */
295 static bool call_init(WStaticModuleInfo
*handle
)
297 if(handle
->init
!=NULL
)
298 return handle
->init();
303 static void call_deinit(WStaticModuleInfo
*handle
)
305 if(handle
->deinit
!=NULL
)
310 extern WStaticModuleInfo ioncore_static_modules
[];
313 static bool do_load_module(const char *name
)
315 WStaticModuleInfo
*mod
;
317 for(mod
=ioncore_static_modules
; mod
->name
!=NULL
; mod
++){
318 if(strcmp(mod
->name
, name
)==0)
323 warn_obj(name
, TR("Unknown module."));
331 warn_obj(name
, TR("Unable to initialise module."));
341 void ioncore_unload_modules()
343 WStaticModuleInfo
*mod
;
345 for(mod
=ioncore_static_modules
; mod
->name
!=NULL
; mod
++){
354 bool ioncore_init_module_support()
370 * Attempt to load a C-side module.
373 bool ioncore_load_module(const char *modname
)
376 warn(TR("No module to load given."));
379 return do_load_module(modname
);