summaryrefslogtreecommitdiffhomepage
path: root/src/core/lt_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lt_core.c')
-rw-r--r--src/core/lt_core.c80
1 files changed, 77 insertions, 3 deletions
diff --git a/src/core/lt_core.c b/src/core/lt_core.c
index df9f58f..8c26ff3 100644
--- a/src/core/lt_core.c
+++ b/src/core/lt_core.c
@@ -4,12 +4,36 @@
/* Released under the Standard MIT License; see COPYING.SLTDL. */
/*******************************************************************/
+#include <dlfcn.h>
+#include <errno.h>
#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
#include <pthread.h>
+
#include <sltdl/sltdl.h>
+#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 pthread_mutex_t lt_lock = PTHREAD_MUTEX_INITIALIZER;
+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)
{
@@ -28,6 +52,7 @@ int lt_dlexit(void)
return 1;
if (!lt_refs) {
+ lt_error = SLTDL_DLEXIT_REF_COUNT;
pthread_mutex_unlock(&lt_lock);
return 1;
}
@@ -48,8 +73,57 @@ void lt_slock(void)
} while (locked);
}
-int lt_sunlock(int ret)
+int lt_sunlock(int ret, int error)
{
+ if (error == 0) {
+ pthread_mutex_unlock(&lt_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(&lt_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;
+}