diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | mutrace.c | 115 |
2 files changed, 69 insertions, 48 deletions
@@ -1,5 +1,5 @@ SONAME=libmutrace.so -CFLAGS=-Wextra -Wall -O0 -g -DPACKAGE_VERSION=\"0.1\" -fPIC -DSONAME=\"$(SONAME)\" +CFLAGS=-pipe -pthread -Wextra -Wall -O0 -g -DPACKAGE_VERSION=\"0.1\" -fPIC -DSONAME=\"$(SONAME)\" LIBS=-lrt -ldl $(SONAME): mutrace.o @@ -1,5 +1,24 @@ /*-*- Mode: C; c-basic-offset: 8 -*-*/ +/*** + This file is part of mutrace. + + Copyright 2009 Lennart Poettering + + mutrace is free software: you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + mutrace is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with mutrace. If not, see <http://www.gnu.org/licenses/>. +***/ + #define _GNU_SOURCE #include <pthread.h> @@ -19,7 +38,6 @@ /* FIXMES: * * - we probably should cover rwlocks, too - * - and conds, too! * */ @@ -29,8 +47,6 @@ #define DEBUG_TRAP raise(SIGTRAP) #endif -typedef void (*fnptr_t)(void); - struct mutex_info { pthread_mutex_t *mutex; @@ -79,6 +95,7 @@ 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 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; static struct mutex_info **alive_mutexes = NULL, **dead_mutexes = NULL; @@ -91,13 +108,6 @@ static uint64_t nsec_timestamp_setup; static void setup(void) __attribute ((constructor)); static void shutdown(void) __attribute ((destructor)); -/* dlsym() violates ISO C, so confide the breakage into this function - * to avoid warnings. */ - -static inline fnptr_t dlsym_fn(void *handle, const char *symbol) { - return (fnptr_t) (long) dlsym(handle, symbol); -} - static pid_t _gettid(void) { return (pid_t) syscall(SYS_gettid); } @@ -135,32 +145,38 @@ static int parse_env(const char *n, unsigned *t) { return 0; } +#define LOAD_FUNC(name) \ + do { \ + *(void**) (&real_##name) = dlsym(RTLD_NEXT, #name); \ + assert(real_##name); \ + } while (false) + +#define LOAD_FUNC_VERSIONED(name, version) \ + do { \ + *(void**) (&real_##name) = dlvsym(RTLD_NEXT, #name, version); \ + assert(real_##name); \ + } while (false) + static void setup(void) { pthread_mutex_t *m, *last; int r; unsigned t; - real_pthread_mutex_init = dlsym_fn(RTLD_NEXT, "pthread_mutex_init"); - real_pthread_mutex_destroy = dlsym_fn(RTLD_NEXT, "pthread_mutex_destroy"); - real_pthread_mutex_lock = dlsym_fn(RTLD_NEXT, "pthread_mutex_lock"); - real_pthread_mutex_trylock = dlsym_fn(RTLD_NEXT, "pthread_mutex_trylock"); - real_pthread_mutex_timedlock = dlsym_fn(RTLD_NEXT, "pthread_mutex_timedlock"); - real_pthread_mutex_unlock = dlsym_fn(RTLD_NEXT, "pthread_mutex_unlock"); - real_pthread_cond_wait = dlsym_fn(RTLD_NEXT, "pthread_cond_wait"); - real_pthread_cond_timedwait = dlsym_fn(RTLD_NEXT, "pthread_cond_timedwait"); - real_exit = dlsym_fn(RTLD_NEXT, "exit"); - real__Exit = dlsym_fn(RTLD_NEXT, "_Exit"); - - assert(real_pthread_mutex_init); - assert(real_pthread_mutex_destroy); - assert(real_pthread_mutex_lock); - assert(real_pthread_mutex_trylock); - assert(real_pthread_mutex_timedlock); - assert(real_pthread_mutex_unlock); - assert(real_pthread_cond_wait); - assert(real_pthread_cond_timedwait); - assert(real_exit); - assert(real__Exit); + LOAD_FUNC(pthread_mutex_init); + LOAD_FUNC(pthread_mutex_destroy); + LOAD_FUNC(pthread_mutex_lock); + LOAD_FUNC(pthread_mutex_trylock); + LOAD_FUNC(pthread_mutex_timedlock); + LOAD_FUNC(pthread_mutex_unlock); + + /* There's some kind of weird incompatibility problem if we + * don't ask for this explicit version of these functions */ + LOAD_FUNC_VERSIONED(pthread_cond_wait, "GLIBC_2.3.2"); + LOAD_FUNC_VERSIONED(pthread_cond_timedwait, "GLIBC_2.3.2"); + + LOAD_FUNC(exit); + LOAD_FUNC(_exit); + LOAD_FUNC(_Exit); t = hash_size; if (parse_env("MUTRACE_HASH_SIZE", &t) < 0 || t <= 0) @@ -469,6 +485,11 @@ void exit(int status) { real_exit(status); } +void _exit(int status) { + show_summary(); + real_exit(status); +} + void _Exit(int status) { show_summary(); real__Exit(status); @@ -775,25 +796,25 @@ int pthread_mutex_unlock(pthread_mutex_t *mutex) { return real_pthread_mutex_unlock(mutex); } -/* int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { */ -/* int r; */ +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { + int r; -/* mutex_unlock(mutex); */ -/* r = real_pthread_cond_wait(cond, mutex); */ + mutex_unlock(mutex); + r = real_pthread_cond_wait(cond, mutex); -/* /\* Unfortunately we cannot distuingish mutex contention and */ -/* * the condition not being signalled here. *\/ */ -/* mutex_lock(mutex, false); */ + /* Unfortunately we cannot distuingish mutex contention and + * the condition not being signalled here. */ + mutex_lock(mutex, false); -/* return r; */ -/* } */ + return r; +} -/* int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) { */ -/* int r; */ +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) { + int r; -/* mutex_unlock(mutex); */ -/* r = real_pthread_cond_timedwait(cond, mutex, abstime); */ -/* mutex_lock(mutex, false); */ + mutex_unlock(mutex); + r = real_pthread_cond_timedwait(cond, mutex, abstime); + mutex_lock(mutex, false); -/* return r; */ -/* } */ + return r; +} |