/*******************************************************************/ /* sltdl: a surrogate ltdl implementation */ /* Copyright (C) 2019 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLTDL. */ /*******************************************************************/ #include #include #include #include #include #include #include #include "sltdl_core.h" static const char * lt_dlerror_desc[] = { [SLTDL_OK] = 0, [SLTDL_SYSTEM_ERROR] = 0, [SLTDL_DLFCN_ERROR] = 0, [SLTDL_SLTDL_ERROR] = "sltdl internal error", [SLTDL_DLEXIT_REF_COUNT] = "lt_dlexit() reference count already zero", [SLTDL_MODULE_REF_COUNT] = "module reference count already zero", [SLTDL_MODULE_PTR_INVALID] = "module handle invalid", [SLTDL_PATH_INVALID_FIRST_CHAR] = "invalid path (does not begin with a forward slash)", [SLTDL_PATH_INVALID_SEPARATTOR_CHAR] = "invalid path (separator character is not a colon)", [SLTDL_PATH_INVALID_MARK] = "invalid path (mark not within range)", [SLTDL_PATH_INVALID_LEN] = "invalid path (string too long)", [SLTDL_PATH_NO_ENTRY] = "invalid path (not found)", }; static int lt_refs = 0; static int lt_error = 0; static int lt_errno = 0; static char * lt_dlerr = 0; static pthread_mutex_t lt_lock = PTHREAD_MUTEX_INITIALIZER; int lt_dlinit(void) { if (pthread_mutex_lock(<_lock)) return 1; lt_refs++; pthread_mutex_unlock(<_lock); return 0; } int lt_dlexit(void) { if (pthread_mutex_lock(<_lock)) return 1; if (!lt_refs) { lt_error = SLTDL_DLEXIT_REF_COUNT; pthread_mutex_unlock(<_lock); return 1; } lt_refs--; pthread_mutex_unlock(<_lock); return 0; } void lt_slock(void) { int locked; do { locked = pthread_mutex_lock(<_lock); } while (locked); } int lt_sunlock(int ret, int error) { if (error == 0) { pthread_mutex_unlock(<_lock); return 0; } if ((error < 0) || (error >= SLTDL_ERROR_CAP)) { error = SLTDL_SLTDL_ERROR; } else if (error == SLTDL_SYSTEM_ERROR) { lt_errno = errno; } else if (error == SLTDL_DLFCN_ERROR) { if (lt_dlerr) free(lt_dlerr); lt_dlerr = strdup(dlerror()); } lt_error = error; pthread_mutex_unlock(<_lock); return ret; } const char * lt_dlerror(void) { const char * errdesc; lt_slock(); switch (lt_error) { case SLTDL_OK: errdesc = 0; break; case SLTDL_SYSTEM_ERROR: errdesc = strerror(lt_errno); break; case SLTDL_DLFCN_ERROR: errdesc = lt_dlerr; break; default: errdesc = lt_dlerror_desc[lt_error]; break; } lt_error = 0; lt_sunlock(0,0); return errdesc; }