Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / gprof-helper.c
1 /* gprof-helper.c -- preload library to profile pthread-enabled programs
2  *
3  * Authors: Sam Hocevar <sam at zoy dot org>
4  *          Daniel Jönsson <danieljo at fagotten dot org>
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the Do What The Fuck You Want To
8  *  Public License as published by Banlu Kemiyatorn. See
9  *  http://sam.zoy.org/projects/COPYING.WTFPL for more details.
10  *
11  * Compilation example:
12  * gcc -shared -fPIC gprof-helper.c -o gprof-helper.so -lpthread -ldl
13  *
14  * Usage example:
15  * LD_PRELOAD=./gprof-helper.so your_program
16  */
17
18 #include <sys/time.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <dlfcn.h>
22 #include <pthread.h>
23
24 static void * wrapper_routine(void *);
25
26 /* Original pthread function */
27 static int (*pthread_create_orig)(pthread_t *__restrict,
28                                   __const pthread_attr_t *__restrict,
29                                   void *(*)(void *),
30                                   void *__restrict) = NULL;
31
32 /* Library initialization function */
33 void wooinit(void) __attribute__((constructor));
34
35 void wooinit(void)
36 {
37     pthread_create_orig = dlsym(RTLD_NEXT, "pthread_create");
38     fprintf(stderr, "pthreads: using profiling hooks for gprof\n");
39     if(pthread_create_orig == NULL)
40     {
41         char *error = dlerror();
42         if(error == NULL)
43         {
44             error = "pthread_create is NULL";
45         }
46         fprintf(stderr, "%s\n", error);
47         exit(EXIT_FAILURE);
48     }
49 }
50
51 /* Our data structure passed to the wrapper */
52 typedef struct wrapper_s
53 {
54     void * (*start_routine)(void *);
55     void * arg;
56
57     pthread_mutex_t lock;
58     pthread_cond_t  wait;
59
60     struct itimerval itimer;
61
62 } wrapper_t;
63
64 /* The wrapper function in charge for setting the itimer value */
65 static void * wrapper_routine(void * data)
66 {
67     /* Put user data in thread-local variables */
68     void * (*start_routine)(void *) = ((wrapper_t*)data)->start_routine;
69     void * arg = ((wrapper_t*)data)->arg;
70
71     /* Set the profile timer value */
72     setitimer(ITIMER_PROF, &((wrapper_t*)data)->itimer, NULL);
73
74     /* Tell the calling thread that we don't need its data anymore */
75     pthread_mutex_lock(&((wrapper_t*)data)->lock);
76     pthread_cond_signal(&((wrapper_t*)data)->wait);
77     pthread_mutex_unlock(&((wrapper_t*)data)->lock);
78
79     /* Call the real function */
80     return start_routine(arg);
81 }
82
83 /* Our wrapper function for the real pthread_create() */
84 int pthread_create(pthread_t *__restrict thread,
85                    __const pthread_attr_t *__restrict attr,
86                    void * (*start_routine)(void *),
87                    void *__restrict arg)
88 {
89     wrapper_t wrapper_data;
90     int i_return;
91
92     /* Initialize the wrapper structure */
93     wrapper_data.start_routine = start_routine;
94     wrapper_data.arg = arg;
95     getitimer(ITIMER_PROF, &wrapper_data.itimer);
96     pthread_cond_init(&wrapper_data.wait, NULL);
97     pthread_mutex_init(&wrapper_data.lock, NULL);
98     pthread_mutex_lock(&wrapper_data.lock);
99
100     /* The real pthread_create call */
101     i_return = pthread_create_orig(thread,
102                                    attr,
103                                    &wrapper_routine,
104                                    &wrapper_data);
105
106     /* If the thread was successfully spawned, wait for the data
107      * to be released */
108     if(i_return == 0)
109     {
110         pthread_cond_wait(&wrapper_data.wait, &wrapper_data.lock);
111     }
112
113     pthread_mutex_unlock(&wrapper_data.lock);
114     pthread_mutex_destroy(&wrapper_data.lock);
115     pthread_cond_destroy(&wrapper_data.wait);
116
117     return i_return;
118 }
119