gmodule.c revision 0df89d51a4a9c5cdefa0a9f4c754958b054e9256
1/* GMODULE - GLIB wrapper code for dynamic module loading 2 * Copyright (C) 1998 Tim Janik 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public 15 * License along with this library; if not, write to the 16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 * Boston, MA 02111-1307, USA. 18 */ 19 20/* 21 * MT safe 22 */ 23 24#include "gmodule.h" 25#include "gmoduleconf.h" 26#include <errno.h> 27#include <string.h> 28 29 30/* We maintain a list of modules, so we can reference count them. 31 * That's needed because some platforms don't support refernce counts on 32 * modules e.g. the shl_* implementation of HP-UX 33 * (http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html). 34 * Also, the module for the program itself is kept seperatedly for 35 * faster access and because it has special semantics. 36 */ 37 38 39/* --- structures --- */ 40struct _GModule 41{ 42 gchar *file_name; 43 gpointer handle; 44 guint ref_count : 31; 45 guint is_resident : 1; 46 GModuleUnload unload; 47 GModule *next; 48}; 49 50 51/* --- prototypes --- */ 52static gpointer _g_module_open (const gchar *file_name, 53 gboolean bind_lazy); 54static void _g_module_close (gpointer handle, 55 gboolean is_unref); 56static gpointer _g_module_self (void); 57static gpointer _g_module_symbol (gpointer handle, 58 const gchar *symbol_name); 59static gchar* _g_module_build_path (const gchar *directory, 60 const gchar *module_name); 61static inline void g_module_set_error (const gchar *error); 62static inline GModule* g_module_find_by_handle (gpointer handle); 63static inline GModule* g_module_find_by_name (const gchar *name); 64 65 66/* --- variables --- */ 67G_LOCK_DEFINE_STATIC (GModule); 68const char *g_log_domain_gmodule = "GModule"; 69static GModule *modules = NULL; 70static GModule *main_module = NULL; 71static GStaticPrivate module_error_private = G_STATIC_PRIVATE_INIT; 72 73 74/* --- inline functions --- */ 75static inline GModule* 76g_module_find_by_handle (gpointer handle) 77{ 78 GModule *module; 79 GModule *retval = NULL; 80 81 G_LOCK (GModule); 82 if (main_module && main_module->handle == handle) 83 retval = main_module; 84 else 85 for (module = modules; module; module = module->next) 86 if (handle == module->handle) 87 { 88 retval = module; 89 break; 90 } 91 G_UNLOCK (GModule); 92 93 return retval; 94} 95 96static inline GModule* 97g_module_find_by_name (const gchar *name) 98{ 99 GModule *module; 100 GModule *retval = NULL; 101 102 G_LOCK (GModule); 103 for (module = modules; module; module = module->next) 104 if (strcmp (name, module->file_name) == 0) 105 { 106 retval = module; 107 break; 108 } 109 G_UNLOCK (GModule); 110 111 return retval; 112} 113 114static inline void 115g_module_set_error (const gchar *error) 116{ 117 g_static_private_set (&module_error_private, g_strdup (error), g_free); 118 errno = 0; 119} 120 121 122/* --- include platform specifc code --- */ 123#define CHECK_ERROR(rv) { g_module_set_error (NULL); } 124#if (G_MODULE_IMPL == G_MODULE_IMPL_DL) 125#include "gmodule-dl.c" 126#elif (G_MODULE_IMPL == G_MODULE_IMPL_DLD) 127#include "gmodule-dld.c" 128#elif (G_MODULE_IMPL == G_MODULE_IMPL_WIN32) 129#include "gmodule-win32.c" 130#else 131#undef CHECK_ERROR 132#define CHECK_ERROR(rv) { g_module_set_error ("dynamic modules are " \ 133 "not supported by this system"); return rv; } 134static gpointer 135_g_module_open (const gchar *file_name, 136 gboolean bind_lazy) 137{ 138 return NULL; 139} 140static void 141_g_module_close (gpointer handle, 142 gboolean is_unref) 143{ 144} 145static gpointer 146_g_module_self (void) 147{ 148 return NULL; 149} 150static gpointer 151_g_module_symbol (gpointer handle, 152 const gchar *symbol_name) 153{ 154 return NULL; 155} 156static gchar* 157_g_module_build_path (const gchar *directory, 158 const gchar *module_name) 159{ 160 return NULL; 161} 162#endif /* no implementation */ 163 164#if defined (NATIVE_WIN32) && defined (__LCC__) 165int __stdcall 166LibMain (void *hinstDll, 167 unsigned long dwReason, 168 void *reserved) 169{ 170 return 1; 171} 172#endif /* NATIVE_WIN32 && __LCC__ */ 173 174 175/* --- functions --- */ 176gboolean 177g_module_supported (void) 178{ 179 CHECK_ERROR (FALSE); 180 181 return TRUE; 182} 183 184GModule* 185g_module_open (const gchar *file_name, 186 GModuleFlags flags) 187{ 188 GModule *module; 189 gpointer handle; 190 191 CHECK_ERROR (NULL); 192 193 if (!file_name) 194 { 195 G_LOCK (GModule); 196 if (!main_module) 197 { 198 handle = _g_module_self (); 199 if (handle) 200 { 201 main_module = g_new (GModule, 1); 202 main_module->file_name = NULL; 203 main_module->handle = handle; 204 main_module->ref_count = 1; 205 main_module->is_resident = TRUE; 206 main_module->unload = NULL; 207 main_module->next = NULL; 208 } 209 } 210 G_UNLOCK (GModule); 211 212 return main_module; 213 } 214 215 /* we first search the module list by name */ 216 module = g_module_find_by_name (file_name); 217 if (module) 218 { 219 module->ref_count++; 220 221 return module; 222 } 223 224 /* open the module */ 225 handle = _g_module_open (file_name, (flags & G_MODULE_BIND_LAZY) != 0); 226 if (handle) 227 { 228 gchar *saved_error; 229 GModuleCheckInit check_init; 230 const gchar *check_failed = NULL; 231 232 /* search the module list by handle, since file names are not unique */ 233 module = g_module_find_by_handle (handle); 234 if (module) 235 { 236 _g_module_close (module->handle, TRUE); 237 module->ref_count++; 238 g_module_set_error (NULL); 239 240 return module; 241 } 242 243 saved_error = g_strdup (g_module_error ()); 244 g_module_set_error (NULL); 245 246 module = g_new (GModule, 1); 247 module->file_name = g_strdup (file_name); 248 module->handle = handle; 249 module->ref_count = 1; 250 module->is_resident = FALSE; 251 module->unload = NULL; 252 G_LOCK (GModule); 253 module->next = modules; 254 modules = module; 255 G_UNLOCK (GModule); 256 257 /* check initialization */ 258 if (g_module_symbol (module, "g_module_check_init", (gpointer) &check_init)) 259 check_failed = check_init (module); 260 261 /* we don't call unload() if the initialization check failed. */ 262 if (!check_failed) 263 g_module_symbol (module, "g_module_unload", (gpointer) &module->unload); 264 265 if (check_failed) 266 { 267 gchar *error; 268 269 error = g_strconcat ("GModule initialization check failed: ", check_failed, NULL); 270 g_module_close (module); 271 module = NULL; 272 g_module_set_error (error); 273 g_free (error); 274 } 275 else 276 g_module_set_error (saved_error); 277 278 g_free (saved_error); 279 } 280 281 return module; 282} 283 284gboolean 285g_module_close (GModule *module) 286{ 287 CHECK_ERROR (FALSE); 288 289 g_return_val_if_fail (module != NULL, FALSE); 290 g_return_val_if_fail (module->ref_count > 0, FALSE); 291 292 module->ref_count--; 293 294 if (!module->ref_count && !module->is_resident && module->unload) 295 { 296 GModuleUnload unload; 297 298 unload = module->unload; 299 module->unload = NULL; 300 unload (module); 301 } 302 303 if (!module->ref_count && !module->is_resident) 304 { 305 GModule *last; 306 GModule *node; 307 308 last = NULL; 309 310 G_LOCK (GModule); 311 node = modules; 312 while (node) 313 { 314 if (node == module) 315 { 316 if (last) 317 last->next = node->next; 318 else 319 modules = node->next; 320 break; 321 } 322 last = node; 323 node = last->next; 324 } 325 module->next = NULL; 326 G_UNLOCK (GModule); 327 328 _g_module_close (module->handle, FALSE); 329 g_free (module->file_name); 330 331 g_free (module); 332 } 333 334 return g_module_error() == NULL; 335} 336 337void 338g_module_make_resident (GModule *module) 339{ 340 g_return_if_fail (module != NULL); 341 342 module->is_resident = TRUE; 343} 344 345gchar* 346g_module_error (void) 347{ 348 return g_static_private_get (&module_error_private); 349} 350 351gboolean 352g_module_symbol (GModule *module, 353 const gchar *symbol_name, 354 gpointer *symbol) 355{ 356 gchar *module_error; 357 if (symbol) 358 *symbol = NULL; 359 CHECK_ERROR (FALSE); 360 361 g_return_val_if_fail (module != NULL, FALSE); 362 g_return_val_if_fail (symbol_name != NULL, FALSE); 363 g_return_val_if_fail (symbol != NULL, FALSE); 364 365#ifdef G_MODULE_NEED_USCORE 366 { 367 gchar *name; 368 369 name = g_strconcat ("_", symbol_name, NULL); 370 *symbol = _g_module_symbol (module->handle, name); 371 g_free (name); 372 } 373#else /* !G_MODULE_NEED_USCORE */ 374 *symbol = _g_module_symbol (module->handle, symbol_name); 375#endif /* !G_MODULE_NEED_USCORE */ 376 377 if ((module_error = g_module_error())) 378 { 379 gchar *error; 380 381 error = g_strconcat ("`", symbol_name, "': ", module_error, NULL); 382 g_module_set_error (error); 383 g_free (error); 384 *symbol = NULL; 385 return FALSE; 386 } 387 388 return TRUE; 389} 390 391gchar* 392g_module_name (GModule *module) 393{ 394 g_return_val_if_fail (module != NULL, NULL); 395 396 if (module == main_module) 397 return "main"; 398 399 return module->file_name; 400} 401 402gchar* 403g_module_build_path (const gchar *directory, 404 const gchar *module_name) 405{ 406 g_return_val_if_fail (module_name != NULL, NULL); 407 408 return _g_module_build_path (directory, module_name); 409} 410