? COPYING ? 2001-02-22-mutex-lock.patch ? INSTALL ? mkinstalldirs ? missing ? install-sh ? libltdl/arse Index: ChangeLog from Gary Vaughan <gvv@techie.com> * NEWS: Updated. * doc/libtool.texi (Thread Safety in libltdl): New node describing the application the new MT API. * libltdl/ltdl.h: Prototypes. * libltdl/ltdl.c: Use these functions throughout the rest of the file to provide thread locking. (lt_dlmutex_register): New function to set callbacks for multi-threaded calls into libltdl. (lt_dl_mutex_lock): Type of a locking callback function. (lt_dl_mutex_lock): Type of an unlocking callback function. (lt_dl_mutex_seterror): Type of a callback function to save the last libltdl error message in thread local storage. (lt_dl_mutex_geterror): Type of a callback function to retrieve the last saved error message from thread local storage. Index: NEWS =================================================================== RCS file: /cvsroot/libtool/libtool/NEWS,v retrieving revision 1.85 diff -u -r1.85 NEWS --- NEWS 2001/01/08 01:52:11 1.85 +++ NEWS 2001/02/23 00:14:07 @@ -3,6 +3,7 @@ New in 1.3d: 2000-??-??; CVS version 1.3c, Libtool team: * ltconfig is no more. Generation of libtool happens directly from the configure file. +* Multithread safe with lt_dlmutex_register callback registration. * New -no-install flag to avoid the use of executable wrapper scripts. * New --with-pic, -prefer-pic and -prefer-non-pic flags to control the generation of PIC/non-PIC code. Index: doc/libtool.texi =================================================================== RCS file: /cvsroot/libtool/libtool/doc/libtool.texi,v retrieving revision 1.114 diff -u -r1.114 libtool.texi --- doc/libtool.texi 2001/01/08 01:52:11 1.114 +++ doc/libtool.texi 2001/02/23 00:15:16 @@ -165,6 +165,7 @@ * Libltdl interface:: How to use libltdl in your programs. * Modules for libltdl:: Creating modules that can be @code{dlopen}ed. +* Thread Saftey in libltdl:: Registering callbacks for multi-thread safety. * User defined module data:: Associating data with loaded modules. * Module loaders for libltdl:: Creating user defined module loaders. * Distributing libltdl:: How to distribute libltdl with your package. @@ -2635,6 +2636,7 @@ @menu * Libltdl interface:: How to use libltdl in your programs. * Modules for libltdl:: Creating modules that can be @code{dlopen}ed. +* Thread Saftey in libltdl:: Registering callbacks for multi-thread safety. * User defined module data:: Associating data with loaded modules. * Module loaders for libltdl:: Creating user defined module loaders. * Distributing libltdl:: How to distribute libltdl with your package. @@ -2929,6 +2931,55 @@ foo1_la_LDFLAGS = -module ... @end example + + +@node Thread Saftey in libltdl +@section Using libtldl in a multi threaded environment + +Using the @code{lt_dlmutex_register()} function, and by providing some +appropriate callback function definitions, libltdl can be used in a +multi-threaded environment. + +@deftypefn {Type} void lt_dlmutex_lock (void) +This is the type of a function pointer holding the address of a function +which will be called at the start of parts of the libltdl implementation +code which require a mutex lock. + +Because libltdl is inherantly recursive, it is important that the +locking mechanism employed by these callback functions are reentrant, or +else strange problems will occur. +@end deftypefn + +@deftypefn {Type} void lt_dlmutex_unlock (void) +The type of a matching unlock function. +@end deftypefn + +@deftypefn {Type} void lt_dlmutex_seterror @w{(const char *@var{error});} +Many of the functions in the libltdl @sc{api} have a special return +value to indicate to the client that an error has occured. Normally (in +single threaded applications) a string describing that error can be +retrieved from internal storage with @code{lt_dlerror()}. + +A function of this type must be registered with the library in order for +it to work in a multi-threaded context. The function should store any +error message passed in thread local storage. +@end deftypefn + +@deftypefn {Type} {const char *} lt_dlmutex_geterror (void) +The type of a matching callback function to retrieve the last stored +error message from thread local storage. + +When regeistered correctly this function will be used by +@code{lt_dlerror())} from all threads to retrieve error messages for the +client. +@end deftypefn + +@deftypefn {Function} int lt_dlmutex_register (@w{lt_dlmutex_lock *@var{lock}}, @w{lt_dlmutex_unlock *@var{unlock}}, @w{lt_dlmutex_set_error *@var{seterror}}, @w{lt_dlmutex_geterror *@var{geterror})} +Use this function to register one of each of function ttypes described +above in preparation for multi-threaded use of libltdl. All arguments +must be valid non-@code{NULL} function addresses, or else all +@code{NULL} to return to single threaded operation. +@end deftypefn @node User defined module data Index: libltdl/ltdl.c =================================================================== RCS file: /cvsroot/libtool/libtool/libltdl/ltdl.c,v retrieving revision 1.125 diff -u -r1.125 ltdl.c --- libltdl/ltdl.c 2001/02/20 01:51:50 1.125 +++ libltdl/ltdl.c 2001/02/23 00:15:35 @@ -116,6 +116,18 @@ /* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */ +/* Extract the diagnostic strings from the error table macro in the same + order as the enumberated indices in ltdl.h. */ + +static const char *lt_dlerror_strings[] = + { +#define LT_ERROR(name, diagnostic) (diagnostic), + lt_dlerror_table +#undef LT_ERROR + + 0 + }; + /* This structure is used for the list of registered loaders. */ struct lt_dlloader { struct lt_dlloader *next; @@ -151,6 +163,8 @@ #define LT_DLIS_RESIDENT(handle) LT_DLGET_FLAG(handle, LT_DLRESIDENT_FLAG) +#define LT_DLSTRERROR(name) lt_dlerror_strings[LT_CONC(LT_ERROR_,name)] + static const char objdir[] = LTDL_OBJDIR; #ifdef LTDL_SHLIB_EXT static const char shlib_ext[] = LTDL_SHLIB_EXT; @@ -162,6 +176,76 @@ +/* --- MUTEX LOCKING --- */ + + +/* Macros to make it easier to run the lock functions only if they have + been registered. The reason for the complicated lock macro is to + ensure that the stored error message from the last error is not + accidentally erased if the current function doesn't generate an + error of its own. */ +#define MUTEX_LOCK() LT_STMT_START { \ + if (mutex_lock) (*mutex_lock)(); } LT_STMT_END +#define MUTEX_UNLOCK() LT_STMT_START { \ + if (mutex_unlock) (*mutex_unlock)(); } LT_STMT_END +#define MUTEX_SETERROR(errormsg) LT_STMT_START { \ + if (mutex_seterror) (*mutex_seterror) (errormsg); \ + else last_error = (errormsg); } LT_STMT_END +#define MUTEX_GETERROR(errormsg) LT_STMT_START { \ + if (mutex_seterror) errormsg = (*mutex_geterror)(); \ + else (errormsg) = last_error; } LT_STMT_END + +/* The mutex functions stored here are global, and are necessarily the + same for all threads that wish to share access to libltdl. */ +static lt_dlmutex_lock *mutex_lock = 0; +static lt_dlmutex_unlock *mutex_unlock = 0; +static lt_dlmutex_seterror *mutex_seterror = 0; +static lt_dlmutex_geterror *mutex_geterror = 0; +static const char *last_error = 0; + + +/* Either set or reset the mutex functions. Either all the arguments must + be valid functions, or else all can be NULL to turn off locking entirely. + The registered functions should be manipulating a static global lock + from the lock() and unlock() callbacks, which needs to be reentrant. */ +int +lt_dlmutex_register (lock, unlock, seterror, geterror) + lt_dlmutex_lock *lock; + lt_dlmutex_unlock *unlock; + lt_dlmutex_seterror *seterror; + lt_dlmutex_geterror *geterror; +{ + lt_dlmutex_unlock *old_unlock = unlock; + int errors = 0; + + /* Lock using the old lock() callback, if any. */ + MUTEX_LOCK (); + + if ((lock && unlock && geterror) || !(lock || unlock || geterror)) + { + mutex_lock = lock; + mutex_unlock = unlock; + mutex_geterror = geterror; + } + else + { + MUTEX_SETERROR (LT_DLSTRERROR (INVALID_MUTEX_ARGS)); + ++errors; + } + + /* Use the old unlock() callback we saved earlier, if any. Otherwise + record any errors using internal storage. */ + if (old_unlock) + (*old_unlock) (); + + /* Return the number of errors encountered during the execution of + this function. */ + return errors; +} + + + + /* --- MEMORY HANDLING --- */ @@ -187,67 +271,65 @@ /* --- ERROR MESSAGES --- */ -/* Extract the diagnostic strings from the error table macro in the same - order as the enumberated indices in ltdl.h. */ - -static const char *lt_dlerror_strings[] = - { -#define LT_ERROR(name, diagnostic) (diagnostic), - lt_dlerror_table -#undef LT_ERROR - - 0 - }; - -#define LT_DLSTRERROR(name) lt_dlerror_strings[LT_CONC(LT_ERROR_,name)] - -static const char *last_error = 0; static const char **user_error_strings = 0; -static int errorcode = LT_ERROR_MAX; +static int errorcount = LT_ERROR_MAX; int lt_dladderror (diagnostic) const char *diagnostic; { - int index = errorcode - LT_ERROR_MAX; - const char **temp = 0; + int index = 0; + int result = -1; + const char **temp = (const char **) 0; + MUTEX_LOCK (); + + index = errorcount - LT_ERROR_MAX; temp = LT_DLREALLOC (const char *, user_error_strings, 1 + index); if (temp == 0) { - last_error = LT_DLSTRERROR (NO_MEMORY); - return -1; + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); } else { - user_error_strings = temp; + user_error_strings = temp; + user_error_strings[index] = diagnostic; + result = errorcount++; } - user_error_strings[index] = diagnostic; + MUTEX_UNLOCK (); - return errorcode++; + return result; } int lt_dlseterror (index) int index; { - if (index >= errorcode || index < 0) + int errors = 0; + + MUTEX_LOCK (); + + if (index >= errorcount || index < 0) { - last_error = LT_DLSTRERROR (INVALID_ERRORCODE); - return 1; + /* Ack! Error setting the error message! */ + MUTEX_SETERROR (LT_DLSTRERROR (INVALID_ERRORCODE)); + ++errors; } - - if (index < LT_ERROR_MAX) + else if (index < LT_ERROR_MAX) { - last_error = lt_dlerror_strings[errorcode]; + /* No error setting the error message! */ + MUTEX_SETERROR (lt_dlerror_strings[errorcount]); } else { - last_error = user_error_strings[errorcode - LT_ERROR_MAX]; + /* No error setting the error message! */ + MUTEX_SETERROR (user_error_strings[errorcount - LT_ERROR_MAX]); } - return 0; + MUTEX_UNLOCK (); + + return errors; } @@ -493,11 +575,11 @@ lt_user_data loader_data; const char *filename; { - lt_module module = dlopen (filename, LT_GLOBAL | LT_LAZY_OR_NOW); + lt_module module = dlopen (filename, LT_GLOBAL | LT_LAZY_OR_NOW); if (!module) { - last_error = DLERROR (CANNOT_OPEN); + MUTEX_SETERROR (DLERROR (CANNOT_OPEN)); } return module; @@ -508,12 +590,15 @@ lt_user_data loader_data; lt_module module; { + int errors = 0; + if (dlclose (module) != 0) { - last_error = DLERROR (CANNOT_CLOSE); + MUTEX_SETERROR (DLERROR (CANNOT_CLOSE)); + ++errors; } - return 0; + return errors; } static lt_ptr @@ -526,7 +611,7 @@ if (!address) { - last_error = DLERROR (SYMBOL_NOT_FOUND); + MUTEX_SETERROR (DLERROR (SYMBOL_NOT_FOUND)); } return address; @@ -605,7 +690,7 @@ if (!module) { - last_error = LT_DLSTRERROR (CANNOT_OPEN); + MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); } return module; @@ -616,13 +701,15 @@ lt_user_data loader_data; lt_module module; { + int errors = 0; + if (shl_unload ((shl_t) (module)) != 0) { - last_error = LT_DLSTRERROR (CANNOT_CLOSE); - return 1; + MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + ++errors; } - return 0; + return errors; } static lt_ptr @@ -641,7 +728,7 @@ return address; } - last_error = LT_DLSTRERROR (SYMBOL_NOT_FOUND); + MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); } return 0; @@ -673,7 +760,8 @@ const char *filename; { lt_dlhandle cur; - lt_module module; + lt_module module = 0; + const char *errormsg = 0; char *searchname = 0; char *ext; char self_name_buf[MAX_PATH]; @@ -702,7 +790,7 @@ searchname = LT_DLMALLOC (char, 2+ strlen (filename)); if (!searchname) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return 0; } strcpy (searchname, filename); @@ -720,6 +808,7 @@ We check whether LoadLibrary is returning a handle to an already loaded module, and simulate failure if we find one. */ + MUTEX_LOCK (); cur = handles; while (cur) { @@ -736,11 +825,12 @@ cur = cur->next; } + MUTEX_UNLOCK (); if (cur || !module) { - last_error = LT_DLSTRERROR (CANNOT_OPEN); - return 0; + MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); + module = 0; } return module; @@ -751,13 +841,15 @@ lt_user_data loader_data; lt_module module; { + int errors = 0; + if (FreeLibrary(module) == 0) { - last_error = LT_DLSTRERROR (CANNOT_CLOSE); - return 1; + MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + ++errors; } - return 0; + return errors; } static lt_ptr @@ -766,11 +858,11 @@ lt_module module; const char *symbol; { - lt_ptr address = GetProcAddress (module, symbol); + lt_ptr address = GetProcAddress (module, symbol); if (!address) { - last_error = LT_DLSTRERROR (SYMBOL_NOT_FOUND); + MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); } return address; @@ -815,8 +907,8 @@ if (image <= 0) { - last_error = LT_DLSTRERROR (CANNOT_OPEN); - return 0; + MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); + image = 0; } return (lt_module) image; @@ -827,13 +919,15 @@ lt_user_data loader_data; lt_module module; { + int errors = 0; + if (unload_add_on ((image_id) module) != B_OK) { - last_error = LT_DLSTRERROR (CANNOT_CLOSE); - return 1; + MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + ++errors; } - return 0; + return errors; } static lt_ptr @@ -847,8 +941,8 @@ if (get_image_symbol (image, symbol, B_SYMBOL_TYPE_ANY, address) != B_OK) { - last_error = LT_DLSTRERROR (SYMBOL_NOT_FOUND); - return 0; + MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); + address = 0; } return address; @@ -883,15 +977,14 @@ if (!module) { - last_error = LT_DLSTRERROR (NO_MEMORY); - return 0; + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + module = 0; } - - if (dld_link (filename) != 0) + else if (dld_link (filename) != 0) { - last_error = LT_DLSTRERROR (CANNOT_OPEN); + MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_OPEN)); LT_DLFREE (module); - return 0; + module = 0; } return module; @@ -902,14 +995,19 @@ lt_user_data loader_data; lt_module module; { + int errors = 0; + if (dld_unlink_by_file ((char*)(module), 1) != 0) { - last_error = LT_DLSTRERROR (CANNOT_CLOSE); - return 1; + MUTEX_SETERROR (LT_DLSTRERROR (CANNOT_CLOSE)); + ++errors; } - LT_DLFREE (module); + else + { + LT_DLFREE (module); + } - return 0; + return errors; } static lt_ptr @@ -922,7 +1020,7 @@ if (!address) { - last_error = LT_DLSTRERROR (SYMBOL_NOT_FOUND); + MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); } return address; @@ -955,21 +1053,29 @@ presym_init (loader_data) lt_user_data loader_data; { - preloaded_symbols = 0; + int errors = 0; + MUTEX_LOCK (); + + preloaded_symbols = 0; if (default_preloaded_symbols) { - return lt_dlpreload (default_preloaded_symbols); + errors = lt_dlpreload (default_preloaded_symbols); } - return 0; + MUTEX_UNLOCK (); + + return errors; } static int presym_free_symlists () { - lt_dlsymlists_t *lists = preloaded_symbols; + lt_dlsymlists_t *lists; + + MUTEX_LOCK (); + lists = preloaded_symbols; while (lists) { lt_dlsymlists_t *tmp = lists; @@ -979,6 +1085,8 @@ } preloaded_symbols = 0; + MUTEX_UNLOCK (); + return 0; } @@ -995,28 +1103,37 @@ const lt_dlsymlist *preloaded; { lt_dlsymlists_t *tmp; - lt_dlsymlists_t *lists = preloaded_symbols; + lt_dlsymlists_t *lists; + int errors = 0; + + MUTEX_LOCK (); + lists = preloaded_symbols; while (lists) { if (lists->syms == preloaded) { - return 0; + goto done; } lists = lists->next; } tmp = LT_DLMALLOC (lt_dlsymlists_t, 1); - if (!tmp) + if (tmp) { - last_error = LT_DLSTRERROR (NO_MEMORY); - return 1; + tmp->syms = preloaded; + tmp->next = preloaded_symbols; + preloaded_symbols = tmp; + } + else + { + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + ++errors; } - tmp->syms = preloaded; - tmp->next = preloaded_symbols; - preloaded_symbols = tmp; - return 0; + done: + MUTEX_UNLOCK (); + return errors; } static lt_module @@ -1024,12 +1141,16 @@ lt_user_data loader_data; const char *filename; { - lt_dlsymlists_t *lists = preloaded_symbols; + lt_dlsymlists_t *lists; + lt_module module = (lt_module) 0; + MUTEX_LOCK (); + lists = preloaded_symbols; + if (!lists) { - last_error = LT_DLSTRERROR (NO_SYMBOLS); - return 0; + MUTEX_SETERROR (LT_DLSTRERROR (NO_SYMBOLS)); + goto done; } if (!filename) @@ -1045,7 +1166,8 @@ { if (!syms->address && strcmp(syms->name, filename) == 0) { - return (lt_module) syms; + module = (lt_module) syms; + goto done; } ++syms; } @@ -1053,9 +1175,11 @@ lists = lists->next; } - last_error = LT_DLSTRERROR (FILE_NOT_FOUND); + MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); - return 0; + done: + MUTEX_UNLOCK (); + return module; } static int @@ -1087,7 +1211,7 @@ ++syms; } - last_error = LT_DLSTRERROR (SYMBOL_NOT_FOUND); + MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); return 0; } @@ -1108,11 +1232,13 @@ static lt_dlhandle handles = 0; static int initialized = 0; +/* Initialize libltdl. */ int lt_dlinit () { - /* initialize libltdl */ - int errors = 0; + int errors = 0; + + MUTEX_LOCK (); /* Initialize only at first call. */ if (++initialized == 1) @@ -1139,20 +1265,18 @@ if (presym_init (presym.dlloader_data)) { - last_error = LT_DLSTRERROR (INIT_LOADER); + MUTEX_SETERROR (LT_DLSTRERROR (INIT_LOADER)); ++errors; } else if (errors != 0) { - last_error = LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED); + MUTEX_SETERROR (LT_DLSTRERROR (DLOPEN_NOT_SUPPORTED)); ++errors; } - else - { - last_error = 0; - } } + MUTEX_UNLOCK (); + return errors; } @@ -1160,25 +1284,36 @@ lt_dlpreload (preloaded) const lt_dlsymlist *preloaded; { + int errors = 0; + if (preloaded) { - return presym_add_symlist (preloaded); + errors = presym_add_symlist (preloaded); } - - presym_free_symlists(); - if (default_preloaded_symbols) + else { - return lt_dlpreload (default_preloaded_symbols); + const char *errormsg = 0; + + presym_free_symlists(); + + MUTEX_LOCK (); + if (default_preloaded_symbols) + { + errors = lt_dlpreload (default_preloaded_symbols); + } + MUTEX_UNLOCK (); } - return 0; + return errors; } int lt_dlpreload_default (preloaded) const lt_dlsymlist *preloaded; { + MUTEX_LOCK (); default_preloaded_symbols = preloaded; + MUTEX_UNLOCK (); return 0; } @@ -1186,13 +1321,18 @@ lt_dlexit () { /* shut down libltdl */ - lt_dlloader *loader = loaders; - int errors = 0; + lt_dlloader *loader; + const char *errormsg; + int errors = 0; + + MUTEX_LOCK (); + loader = loaders; if (!initialized) { - last_error = LT_DLSTRERROR (SHUTDOWN); - return 1; + MUTEX_SETERROR (LT_DLSTRERROR (SHUTDOWN)); + ++errors; + goto done; } /* shut down only at last call. */ @@ -1239,6 +1379,8 @@ loaders = 0; } + done: + MUTEX_UNLOCK (); return errors; } @@ -1247,10 +1389,17 @@ lt_dlhandle *handle; const char *filename; { - lt_dlhandle cur = handles; - lt_dlloader *loader = loaders; - const char *saved_error = last_error; + lt_dlhandle cur; + lt_dlloader *loader; + const char *saved_error; + int errors = 0; + + MUTEX_GETERROR (saved_error); + MUTEX_LOCK (); + cur = handles; + loader = loaders; + /* check whether the module was already opened */ while (cur) { @@ -1273,7 +1422,7 @@ { ++cur->info.ref_count; *handle = cur; - return 0; + goto done; } cur = *handle; @@ -1282,8 +1431,9 @@ cur->info.filename = strdup (filename); if (!cur->info.filename) { - last_error = LT_DLSTRERROR (NO_MEMORY); - return 1; + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + ++errors; + goto done; } } else @@ -1307,13 +1457,17 @@ if (!loader) { LT_DLFREE (cur->info.filename); - return 1; + ++errors; + goto done; } cur->loader = loader; last_error = saved_error; + + done: + MUTEX_UNLOCK (); - return 0; + return errors; } static int @@ -1349,7 +1503,7 @@ if (!filename) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return 1; } @@ -1371,7 +1525,7 @@ if (!filename) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return 1; } @@ -1451,8 +1605,8 @@ char **pdir; lt_dlhandle *handle; { - /* when handle != NULL search a library, otherwise a file */ - /* return NULL on failure, otherwise the file/handle */ + /* When handle != NULL search a library, otherwise a file + return NULL on failure, otherwise the file/handle. */ lt_ptr result = 0; char *filename = 0; @@ -1461,16 +1615,18 @@ char *canonical = 0; char *next = 0; + MUTEX_LOCK (); + if (!search_path || !*search_path) { - last_error = LT_DLSTRERROR (FILE_NOT_FOUND); - return 0; + MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); + goto cleanup; } canonical = canonicalize_path (search_path); if (!canonical) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); goto cleanup; } @@ -1509,7 +1665,7 @@ if (!filename) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); goto cleanup; } } @@ -1551,12 +1707,14 @@ } } - last_error = LT_DLSTRERROR (FILE_NOT_FOUND); + MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); cleanup: LT_DLFREE (filename); LT_DLFREE (canonical); + MUTEX_UNLOCK (); + return result; } @@ -1571,22 +1729,23 @@ int i; char **names = 0; #endif - int ret = 0; + int errors = 0; handle->depcount = 0; #if LTDL_DLOPEN_DEPLIBS - ret = 1; if (!deplibs) { - return 0; + return errors; } + ++errors; + MUTEX_LOCK (); save_search_path = strdup (user_search_path); if (user_search_path && !save_search_path) { - last_error = LT_DLSTRERROR (NO_MEMORY); - return 1; + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + goto cleanup; } /* extract search paths and count deplibs */ @@ -1624,9 +1783,15 @@ } } + /* restore the old search path */ + LT_DLFREE (user_search_path); + user_search_path = save_search_path; + + MUTEX_UNLOCK (); + if (!depcount) { - ret = 0; + errors = 0; goto cleanup; } @@ -1710,7 +1875,7 @@ } handle->depcount = j; /* Number of successfully loaded deplibs */ - ret = 0; + errors = 0; } cleanup_names: @@ -1721,13 +1886,9 @@ cleanup: LT_DLFREE (names); - - /* restore the old search path */ - LT_DLFREE (user_search_path); - user_search_path = save_search_path; #endif - return ret; + return errors; } static int @@ -1806,16 +1967,18 @@ { lt_dlhandle handle = 0, newhandle; const char *ext; - const char *saved_error = last_error; + const char *saved_error; char *canonical = 0, *basename = 0, *dir = 0, *name = 0; + MUTEX_GETERROR (saved_error); + /* dlopen self? */ if (!filename) { handle = (lt_dlhandle) LT_DLMALLOC (struct lt_dlhandle_struct, 1); if (!handle) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return 0; } @@ -1839,7 +2002,7 @@ canonical = canonicalize_path (filename); if (!canonical) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); LT_DLFREE (handle); return 0; } @@ -1853,7 +2016,7 @@ dir = LT_DLMALLOC (char, basename - canonical + 1); if (!dir) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); handle = 0; goto cleanup; } @@ -1866,7 +2029,7 @@ basename = canonical; } - /* check whether we open a libtool module (.la extension) */ + /* Check whether we are opening a libtool module (.la extension). */ ext = strrchr(basename, '.'); if (ext && strcmp(ext, ".la") == 0) { @@ -1883,13 +2046,13 @@ of libtool */ int installed = 1; - /* extract the module name from the file name */ - name = LT_DLMALLOC (char, ext - basename + 1); - if (!name) - { - last_error = LT_DLSTRERROR (NO_MEMORY); - handle = 0; - goto cleanup; + /* extract the module name from the file name */ + name = LT_DLMALLOC (char, ext - basename + 1); + if (!name) + { + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + handle = 0; + goto cleanup; } /* canonicalize the module name */ @@ -1940,7 +2103,7 @@ } if (!file) { - last_error = LT_DLSTRERROR (FILE_NOT_FOUND); + MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); } if (!file) @@ -1953,7 +2116,7 @@ if (!line) { fclose (file); - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); handle = 0; goto cleanup; } @@ -2039,7 +2202,7 @@ LT_DLFREE (handle); if (!error) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); } free_vars (dlname, old_name, libdir, deplibs); @@ -2081,7 +2244,7 @@ handle = (lt_dlhandle) LT_DLMALLOC (struct lt_dlhandle_struct, 1); if (!handle) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); /* handle is already set to 0 */ goto cleanup; } @@ -2120,12 +2283,16 @@ handle->info.ref_count = 1; handle->info.name = name; handle->next = handles; + + MUTEX_LOCK (); handles = handle; + MUTEX_UNLOCK (); name = 0; /* don't free this during `cleanup' */ } - last_error = saved_error; + MUTEX_SETERROR (saved_error); + cleanup: LT_DLFREE (dir); LT_DLFREE (name); @@ -2141,7 +2308,9 @@ lt_dlhandle handle; char *tmp; int len; - const char *saved_error = last_error; + const char *saved_error; + + MUTEX_GETERROR (saved_error); if (!filename) { @@ -2151,7 +2320,7 @@ len = strlen (filename); if (!len) { - last_error = LT_DLSTRERROR (FILE_NOT_FOUND); + MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); return 0; } @@ -2159,7 +2328,7 @@ tmp = LT_DLMALLOC (char, len+4); if (!tmp) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return 0; } strcpy (tmp, filename); @@ -2167,7 +2336,7 @@ handle = lt_dlopen (tmp); if (handle) { - last_error = saved_error; + MUTEX_SETERROR (saved_error); LT_DLFREE (tmp); return handle; } @@ -2180,7 +2349,7 @@ tmp = LT_DLMALLOC (char, len + strlen (shlib_ext) + 1); if (!tmp) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return 0; } strcpy (tmp, filename); @@ -2194,7 +2363,7 @@ handle = lt_dlopen (tmp); if (handle) { - last_error = saved_error; + MUTEX_SETERROR (saved_error); LT_DLFREE (tmp); return handle; } @@ -2207,7 +2376,7 @@ return handle; } - last_error = LT_DLSTRERROR (FILE_NOT_FOUND); + MUTEX_SETERROR (LT_DLSTRERROR (FILE_NOT_FOUND)); LT_DLFREE (tmp); return 0; } @@ -2217,7 +2386,10 @@ lt_dlhandle handle; { lt_dlhandle cur, last; + int errors = 0; + MUTEX_LOCK (); + /* check whether the handle is valid */ last = cur = handles; while (cur && handle != cur) @@ -2228,8 +2400,9 @@ if (!cur) { - last_error = LT_DLSTRERROR (INVALID_HANDLE); - return 1; + MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + ++errors; + goto done; } handle->info.ref_count--; @@ -2240,7 +2413,6 @@ moment). */ if (handle->info.ref_count <= 0 && !LT_DLIS_RESIDENT (handle)) { - int error; lt_user_data data = handle->loader->dlloader_data; if (handle != handles) @@ -2252,24 +2424,26 @@ handles = handle->next; } - error = handle->loader->module_close (data, handle->module); - error += unload_deplibs(handle); + errors += handle->loader->module_close (data, handle->module); + errors += unload_deplibs(handle); LT_DLFREE (handle->info.filename); LT_DLFREE (handle->info.name); - LT_DLFREE (handle); - return error; + goto done; } if (LT_DLIS_RESIDENT (handle)) { - last_error = LT_DLSTRERROR (CLOSE_RESIDENT_MODULE); - return 1; + MUTEX_SETERROR (LT_DLSTRERROR (CLOSE_RESIDENT_MODULE)); + ++errors; } - return 0; + done: + MUTEX_UNLOCK (); + + return errors; } lt_ptr @@ -2285,13 +2459,13 @@ if (!handle) { - last_error = LT_DLSTRERROR (INVALID_HANDLE); + MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); return 0; } if (!symbol) { - last_error = LT_DLSTRERROR (SYMBOL_NOT_FOUND); + MUTEX_SETERROR (LT_DLSTRERROR (SYMBOL_NOT_FOUND)); return 0; } @@ -2317,14 +2491,16 @@ if (!sym) { - last_error = LT_DLSTRERROR (BUFFER_OVERFLOW); + MUTEX_SETERROR (LT_DLSTRERROR (BUFFER_OVERFLOW)); return 0; } data = handle->loader->dlloader_data; if (handle->info.name) { - const char *saved_error = last_error; + const char *saved_error; + + MUTEX_GETERROR (saved_error); /* this is a libtool module */ if (handle->loader->sym_prefix) @@ -2350,7 +2526,7 @@ } return address; } - last_error = saved_error; + MUTEX_SETERROR (saved_error); } /* otherwise try "symbol" */ @@ -2376,9 +2552,11 @@ const char * lt_dlerror () { - const char *error = last_error; + const char *error; - last_error = 0; + MUTEX_GETERROR (error); + MUTEX_SETERROR (0); + return error; } @@ -2386,18 +2564,21 @@ lt_dladdsearchdir (search_dir) const char *search_dir; { + int errors = 0; + if (!search_dir || !strlen(search_dir)) { - return 0; + return errors; } + MUTEX_LOCK (); if (!user_search_path) { user_search_path = strdup (search_dir); if (!user_search_path) { last_error = LT_DLSTRERROR (NO_MEMORY); - return 1; + ++errors; } } else @@ -2407,58 +2588,77 @@ if (!new_search_path) { - last_error = LT_DLSTRERROR (NO_MEMORY); - return 1; + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + ++errors; } - - sprintf (new_search_path, "", user_search_path, - LT_PATHSEP_CHAR, search_dir); + else + { + sprintf (new_search_path, "", user_search_path, + LT_PATHSEP_CHAR, search_dir); - LT_DLMEM_REASSIGN (user_search_path, new_search_path); + LT_DLMEM_REASSIGN (user_search_path, new_search_path); + } } + MUTEX_UNLOCK (); - return 0; + return errors; } int lt_dlsetsearchpath (search_path) const char *search_path; { + int errors = 0; + + MUTEX_LOCK (); LT_DLFREE (user_search_path); + MUTEX_UNLOCK (); if (!search_path || !strlen (search_path)) { - return 0; + return errors; } + MUTEX_LOCK (); user_search_path = strdup (search_path); if (!user_search_path) { - return 1; + ++errors; } + MUTEX_UNLOCK (); - return 0; + return errors; } const char * lt_dlgetsearchpath () { - return user_search_path; + const char *saved_path; + + MUTEX_LOCK (); + saved_path = user_search_path; + MUTEX_UNLOCK (); + + return saved_path; } int lt_dlmakeresident (handle) lt_dlhandle handle; { + int errors = 0; + if (!handle) { - last_error = LT_DLSTRERROR (INVALID_HANDLE); - return -1; + MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); + ++errors; } - - LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG); + else + { + LT_DLSET_FLAG (handle, LT_DLRESIDENT_FLAG); + } - return 0; + return errors; } int @@ -2467,7 +2667,7 @@ { if (!handle) { - last_error = LT_DLSTRERROR (INVALID_HANDLE); + MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); return -1; } @@ -2485,7 +2685,7 @@ { if (!handle) { - last_error = LT_DLSTRERROR (INVALID_HANDLE); + MUTEX_SETERROR (LT_DLSTRERROR (INVALID_HANDLE)); return 0; } @@ -2504,8 +2704,12 @@ int (*func) LT_PARAMS((lt_dlhandle handle, lt_ptr data)); lt_ptr data; { - lt_dlhandle cur = handles; + int errors = 0; + lt_dlhandle cur; + MUTEX_LOCK (); + + cur = handles; while (cur) { lt_dlhandle tmp = cur; @@ -2513,19 +2717,27 @@ cur = cur->next; if ((*func) (tmp, data)) { - return 1; + ++errors; + break; } } - return 0; + MUTEX_UNLOCK (); + + return errors; } lt_dlcaller_id lt_dlcaller_register () { static int last_caller_id = -1; + int result; - return ++last_caller_id; + MUTEX_LOCK (); + result = ++last_caller_id; + MUTEX_UNLOCK (); + + return result; } #define N_ELEMENTS(a) (sizeof(a) / sizeof(*(a))) @@ -2540,6 +2752,10 @@ lt_ptr stale = (lt_ptr) 0; int i; + /* This needs to be locked so that the caller data can be updated + simultaneously by different threads. */ + MUTEX_LOCK (); + if (handle->caller_data) n_elements = N_ELEMENTS (handle->caller_data); @@ -2561,8 +2777,9 @@ if (temp == 0) { - last_error = LT_DLSTRERROR (NO_MEMORY); - return (lt_ptr) 0; + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); + stale = (lt_ptr) 0; + goto done; } else { @@ -2575,6 +2792,9 @@ handle->caller_data[i].data = data; + done: + MUTEX_UNLOCK (); + return stale; } @@ -2586,6 +2806,10 @@ lt_ptr result = (lt_ptr) 0; int n_elements = 0; + /* This needs to be locked so that the caller data isn't updated by + another thread part way through this function. */ + MUTEX_LOCK (); + if (handle->caller_data) n_elements = N_ELEMENTS (handle->caller_data); @@ -2602,6 +2826,8 @@ } } + MUTEX_UNLOCK (); + return result; } @@ -2616,6 +2842,7 @@ const struct lt_user_dlloader *dlloader; const char *loader_name; { + int errors = 0; lt_dlloader *node = 0, *ptr = 0; if ((dlloader == 0) /* diagnose null parameters */ @@ -2623,7 +2850,7 @@ || (dlloader->module_close == 0) || (dlloader->find_sym == 0)) { - last_error = LT_DLSTRERROR (INVALID_LOADER); + MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); return 1; } @@ -2631,9 +2858,10 @@ node = LT_DLMALLOC (lt_dlloader, 1); if (node == 0) { - last_error = LT_DLSTRERROR (NO_MEMORY); + MUTEX_SETERROR (LT_DLSTRERROR (NO_MEMORY)); return 1; } + node->next = 0; node->loader_name = loader_name; node->sym_prefix = dlloader->sym_prefix; @@ -2643,6 +2871,7 @@ node->find_sym = dlloader->find_sym; node->dlloader_data = dlloader->dlloader_data; + MUTEX_LOCK (); if (!loaders) { /* If there are no loaders, NODE becomes the list! */ @@ -2676,15 +2905,19 @@ if (ptr->next != place) { last_error = LT_DLSTRERROR (INVALID_LOADER); - return 1; + ++errors; } - - /* Insert NODE between PTR and PLACE. */ - node->next = place; - ptr->next = node; + else + { + /* Insert NODE between PTR and PLACE. */ + node->next = place; + ptr->next = node; + } } - return 0; + MUTEX_UNLOCK (); + + return errors; } int @@ -2693,21 +2926,24 @@ { lt_dlloader *place = lt_dlloader_find (loader_name); lt_dlhandle handle; - int result = 0; + int errors = 0; if (!place) { - last_error = LT_DLSTRERROR (INVALID_LOADER); + MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); return 1; } + MUTEX_LOCK (); + /* Fail if there are any open modules which use this loader. */ for (handle = handles; handle; handle = handle->next) { if (handle->loader == place) { - last_error = LT_DLSTRERROR (REMOVE_LOADER); - return 1; + MUTEX_SETERROR (LT_DLSTRERROR (REMOVE_LOADER)); + ++errors; + goto done; } } @@ -2734,43 +2970,68 @@ if (place->dlloader_exit) { - result = place->dlloader_exit (place->dlloader_data); + errors = place->dlloader_exit (place->dlloader_data); } LT_DLFREE (place); - return result; + done: + MUTEX_UNLOCK (); + + return errors; } lt_dlloader * lt_dlloader_next (place) lt_dlloader *place; { - return place ? place->next : loaders; + lt_dlloader *next; + + MUTEX_LOCK (); + next = place ? place->next : loaders; + MUTEX_UNLOCK (); + + return next; } const char * lt_dlloader_name (place) lt_dlloader *place; { - if (!place) + const char *name = 0; + + if (place) { - last_error = LT_DLSTRERROR (INVALID_LOADER); + MUTEX_LOCK (); + name = place ? place->loader_name : 0; + MUTEX_UNLOCK (); } + else + { + MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); + } - return place ? place->loader_name : 0; + return name; } lt_user_data * lt_dlloader_data (place) lt_dlloader *place; { - if (!place) + lt_user_data *data = 0; + + if (place) + { + MUTEX_LOCK (); + data = place ? &(place->dlloader_data) : 0; + MUTEX_UNLOCK (); + } + else { - last_error = LT_DLSTRERROR (INVALID_LOADER); + MUTEX_SETERROR (LT_DLSTRERROR (INVALID_LOADER)); } - return place ? &(place->dlloader_data) : 0; + return data; } lt_dlloader * @@ -2779,6 +3040,7 @@ { lt_dlloader *place = 0; + MUTEX_LOCK (); for (place = loaders; place; place = place->next) { if (strcmp (place->loader_name, loader_name) == 0) @@ -2786,6 +3048,7 @@ break; } } + MUTEX_UNLOCK (); return place; } Index: libltdl/ltdl.h =================================================================== RCS file: /cvsroot/libtool/libtool/libltdl/ltdl.h,v retrieving revision 1.52 diff -u -r1.52 ltdl.h --- libltdl/ltdl.h 2001/01/08 01:52:12 1.52 +++ libltdl/ltdl.h 2001/02/23 00:15:38 @@ -163,6 +163,28 @@ extern int lt_dlmakeresident LT_PARAMS((lt_dlhandle handle)); extern int lt_dlisresident LT_PARAMS((lt_dlhandle handle)); + + + +/* --- MUTEX LOCKING --- */ + + +typedef void lt_dlmutex_lock LT_PARAMS((void)); +typedef void lt_dlmutex_unlock LT_PARAMS((void)); +typedef void lt_dlmutex_seterror LT_PARAMS((const char *error)); +typedef const char *lt_dlmutex_geterror LT_PARAMS((void)); + +extern int lt_dlmutex_register LT_PARAMS((lt_dlmutex_lock *lock, + lt_dlmutex_unlock *unlock, + lt_dlmutex_seterror *seterror, + lt_dlmutex_geterror *geterror)); + + + + +/* --- MEMORY HANDLING --- */ + + /* Pointers to memory management functions to be used by libltdl. */ LT_SCOPE lt_ptr (*lt_dlmalloc) LT_PARAMS((size_t size)); LT_SCOPE void (*lt_dlfree) LT_PARAMS((lt_ptr ptr)); @@ -284,7 +306,8 @@ LT_ERROR(BUFFER_OVERFLOW, "internal buffer overflow") \ LT_ERROR(INVALID_ERRORCODE, "invalid errorcode") \ LT_ERROR(SHUTDOWN, "library already shutdown") \ - LT_ERROR(CLOSE_RESIDENT_MODULE, "can't close resident module") + LT_ERROR(CLOSE_RESIDENT_MODULE, "can't close resident module") \ + LT_ERROR(INVALID_MUTEX_ARGS, "invalid mutex handler registration") /* Enumerate the symbolic error names. */ enum {