diff options
author | Taybin Rutkin <taybin@taybin.com> | 2005-09-25 18:42:24 +0000 |
---|---|---|
committer | Taybin Rutkin <taybin@taybin.com> | 2005-09-25 18:42:24 +0000 |
commit | 209d967b1bb80a9735d690d8f4f0455ecb9970ca (patch) | |
tree | 9d76ddcd7c1ac9d91bb2b1a33d31b66ce4ded5de /gtk2_ardour/gprofhelper.c | |
parent | e4b9aed743fc765219ac775905a221c017c88fba (diff) |
Initial import of gtk2_ardour.
git-svn-id: svn://localhost/trunk/ardour2@24 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour/gprofhelper.c')
-rw-r--r-- | gtk2_ardour/gprofhelper.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/gtk2_ardour/gprofhelper.c b/gtk2_ardour/gprofhelper.c new file mode 100644 index 0000000000..b806a073c6 --- /dev/null +++ b/gtk2_ardour/gprofhelper.c @@ -0,0 +1,117 @@ +/* gprof-helper.c -- preload library to profile pthread-enabled programs + * + * Authors: Sam Hocevar <sam at zoy dot org> + * Daniel Jönsson <danieljo at fagotten dot org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Do What The Fuck You Want To + * Public License as published by Banlu Kemiyatorn. See + * http://sam.zoy.org/projects/COPYING.WTFPL for more details. + * + * Compilation example: + * gcc -shared -nostdlib -fPIC gprof-helper.c -o gprof-helper.so -lpthread -ldl + * + * Usage example: + * LD_PRELOAD=./gprof-helper.so your_program + */ + +#define _GNU_SOURCE +#include <sys/time.h> +#include <stdio.h> +#include <stdlib.h> +#include <dlfcn.h> +#include <pthread.h> + +static void * wrapper_routine(void *); + +/* Original pthread function */ +static int (*pthread_create_orig)(pthread_t *__restrict, + __const pthread_attr_t *__restrict, + void *(*)(void *), + void *__restrict) = NULL; + +/* Library initialization function */ +void _init(void) +{ + pthread_create_orig = dlsym(RTLD_NEXT, "pthread_create"); + fprintf(stderr, "pthreads: using profiling hooks for gprof\n"); + if(pthread_create_orig == NULL) + { + char *error = dlerror(); + if(error == NULL) + { + error = "pthread_create is NULL"; + } + fprintf(stderr, "%s", error); + exit(EXIT_FAILURE); + } +} + +/* Our data structure passed to the wrapper */ +typedef struct wrapper_s +{ + void * (*start_routine)(void *); + void * arg; + + pthread_mutex_t lock; + pthread_cond_t wait; + + struct itimerval itimer; + +} wrapper_t; + +/* The wrapper function in charge for setting the itimer value */ +static void * wrapper_routine(void * data) +{ + /* Put user data in thread-local variables */ + void * (*start_routine)(void *) = ((wrapper_t*)data)->start_routine; + void * arg = ((wrapper_t*)data)->arg; + + /* Set the profile timer value */ + setitimer(ITIMER_PROF, &((wrapper_t*)data)->itimer, NULL); + + /* Tell the calling thread that we don't need its data anymore */ + pthread_mutex_lock(&((wrapper_t*)data)->lock); + pthread_cond_signal(&((wrapper_t*)data)->wait); + pthread_mutex_unlock(&((wrapper_t*)data)->lock); + + /* Call the real function */ + return start_routine(arg); +} + +/* Our wrapper function for the real pthread_create() */ +int pthread_create(pthread_t *__restrict thread, + __const pthread_attr_t *__restrict attr, + void * (*start_routine)(void *), + void *__restrict arg) +{ + wrapper_t wrapper_data; + int i_return; + + /* Initialize the wrapper structure */ + wrapper_data.start_routine = start_routine; + wrapper_data.arg = arg; + getitimer(ITIMER_PROF, &wrapper_data.itimer); + pthread_cond_init(&wrapper_data.wait, NULL); + pthread_mutex_init(&wrapper_data.lock, NULL); + pthread_mutex_lock(&wrapper_data.lock); + + /* The real pthread_create call */ + i_return = pthread_create_orig(thread, + attr, + &wrapper_routine, + &wrapper_data); + + /* If the thread was successfully spawned, wait for the data + * to be released */ + if(i_return == 0) + { + pthread_cond_wait(&wrapper_data.wait, &wrapper_data.lock); + } + + pthread_mutex_unlock(&wrapper_data.lock); + pthread_mutex_destroy(&wrapper_data.lock); + pthread_cond_destroy(&wrapper_data.wait); + + return i_return; +} |