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