summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2009-09-15 22:14:18 +0200
committerLennart Poettering <lennart@poettering.net>2009-09-15 22:14:18 +0200
commit89c9711bfe4429b9fa67f80448f59644e15f8ba4 (patch)
tree11ee1fa5b52c53fadb5d87ed043d426bffdcfe41
parente969f57cd1dfd65611db753ed64ed21e88be6b41 (diff)
handle mutexes properly that are taken before we are initialized
-rw-r--r--mutrace.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/mutrace.c b/mutrace.c
index 0e69f14..069fd72 100644
--- a/mutrace.c
+++ b/mutrace.c
@@ -95,6 +95,7 @@ static int (*real_pthread_mutex_timedlock)(pthread_mutex_t *mutex, const struct
static int (*real_pthread_mutex_unlock)(pthread_mutex_t *mutex) = NULL;
static int (*real_pthread_cond_wait)(pthread_cond_t *cond, pthread_mutex_t *mutex) = NULL;
static int (*real_pthread_cond_timedwait)(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) = NULL;
+static int (*real_pthread_create)(pthread_t *newthread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) = NULL;
static void (*real_exit)(int status) __attribute__((noreturn)) = NULL;
static void (*real__exit)(int status) __attribute__((noreturn)) = NULL;
static void (*real__Exit)(int status) __attribute__((noreturn)) = NULL;
@@ -105,6 +106,7 @@ static pthread_mutex_t *mutexes_lock = NULL;
static __thread bool recursive = false;
static volatile bool initialized = false;
+static volatile bool threads_existing = false;
static uint64_t nsec_timestamp_setup;
@@ -178,6 +180,8 @@ static void load_functions(void) {
if (loaded)
return;
+ recursive = true;
+
/* If someone uses a shared library constructor that is called
* before ours we might not be initialized yet when the first
* lock related operation is executed. To deal with this we'll
@@ -191,6 +195,7 @@ static void load_functions(void) {
LOAD_FUNC(pthread_mutex_trylock);
LOAD_FUNC(pthread_mutex_timedlock);
LOAD_FUNC(pthread_mutex_unlock);
+ LOAD_FUNC(pthread_create);
/* There's some kind of weird incompatibility problem causing
* pthread_cond_timedwait() to freeze if we don't ask for this
@@ -203,6 +208,7 @@ static void load_functions(void) {
LOAD_FUNC(_Exit);
loaded = true;
+ recursive = false;
}
static void setup(void) {
@@ -212,6 +218,9 @@ static void setup(void) {
load_functions();
+ if (initialized)
+ return;
+
t = hash_size;
if (parse_env("MUTRACE_HASH_SIZE", &t) < 0 || t <= 0)
fprintf(stderr, "mutrace: WARNING: Failed to parse $MUTRACE_HASH_SIZE.\n");
@@ -667,6 +676,14 @@ int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexa
int r;
unsigned long u;
+ if (!initialized && recursive) {
+ static const pthread_mutex_t template = PTHREAD_MUTEX_INITIALIZER;
+ /* Now this is incredibly ugly. */
+
+ memcpy(mutex, &template, sizeof(pthread_mutex_t));
+ return 0;
+ }
+
load_functions();
r = real_pthread_mutex_init(mutex, mutexattr);
@@ -701,6 +718,8 @@ int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexa
int pthread_mutex_destroy(pthread_mutex_t *mutex) {
unsigned long u;
+ assert(initialized || !recursive);
+
load_functions();
if (initialized && !recursive) {
@@ -761,6 +780,18 @@ int pthread_mutex_lock(pthread_mutex_t *mutex) {
int r;
bool busy;
+ if (!initialized && recursive) {
+ /* During the initialization phase we might be called
+ * inside of dlsym(). Since we'd enter an endless loop
+ * if we tried to resolved the real
+ * pthread_mutex_lock() here then we simply fake the
+ * lock which should be safe since no thread can be
+ * running yet. */
+
+ assert(!threads_existing);
+ return 0;
+ }
+
load_functions();
r = real_pthread_mutex_trylock(mutex);
@@ -782,6 +813,11 @@ int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *absti
int r;
bool busy;
+ if (!initialized && recursive) {
+ assert(!threads_existing);
+ return 0;
+ }
+
load_functions();
r = real_pthread_mutex_trylock(mutex);
@@ -804,6 +840,11 @@ int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *absti
int pthread_mutex_trylock(pthread_mutex_t *mutex) {
int r;
+ if (!initialized && recursive) {
+ assert(!threads_existing);
+ return 0;
+ }
+
load_functions();
r = real_pthread_mutex_trylock(mutex);
@@ -846,6 +887,11 @@ static void mutex_unlock(pthread_mutex_t *mutex) {
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
+ if (!initialized && recursive) {
+ assert(!threads_existing);
+ return 0;
+ }
+
load_functions();
mutex_unlock(mutex);
@@ -856,6 +902,8 @@ int pthread_mutex_unlock(pthread_mutex_t *mutex) {
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
int r;
+ assert(initialized || !recursive);
+
load_functions();
mutex_unlock(mutex);
@@ -871,6 +919,8 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) {
int r;
+ assert(initialized || !recursive);
+
load_functions();
mutex_unlock(mutex);
@@ -879,3 +929,18 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const s
return r;
}
+
+int pthread_create(pthread_t *newthread,
+ const pthread_attr_t *attr,
+ void *(*start_routine) (void *),
+ void *arg) {
+
+ load_functions();
+
+ if (!threads_existing) {
+ threads_existing = true;
+ setup();
+ }
+
+ return real_pthread_create(newthread, attr, start_routine, arg);
+}