Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
sthread: correctly switch to within simgrid when calling shtread API
[simgrid.git] / src / sthread / sthread.c
1 /* SimGrid's pthread interposer. Redefinition of the pthread symbols (see the comment in sthread.h) */
2
3 #define _GNU_SOURCE
4 #include "src/sthread/sthread.h"
5 #include "src/internal_config.h"
6 #include <dlfcn.h>
7 #include <pthread.h>
8 #include <semaphore.h>
9 #include <stdio.h>
10 #include <unistd.h>
11
12 #if HAVE_VALGRIND_H
13 #include <stdlib.h>
14 #include <valgrind/valgrind.h>
15 #endif
16
17 /* We don't want to intercept pthread within simgrid. Instead we should provide the real implem to simgrid */
18 static int (*raw_pthread_create)(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*);
19 static int (*raw_pthread_join)(pthread_t, void**);
20 static int (*raw_mutex_init)(pthread_mutex_t*, const pthread_mutexattr_t*) = NULL;
21 static int (*raw_mutex_lock)(pthread_mutex_t*)                             = NULL;
22 static int (*raw_mutex_trylock)(pthread_mutex_t*)                          = NULL;
23 static int (*raw_mutex_unlock)(pthread_mutex_t*)                           = NULL;
24 static int (*raw_mutex_destroy)(pthread_mutex_t*)                          = NULL;
25
26 static unsigned int (*raw_sleep)(unsigned int)         = NULL;
27 static int (*raw_usleep)(useconds_t)                   = NULL;
28 static int (*raw_gettimeofday)(struct timeval*, void*) = NULL;
29
30 static sem_t* (*raw_sem_open)(const char*, int)                            = NULL;
31 static int (*raw_sem_init)(sem_t*, int, unsigned int)                      = NULL;
32 static int (*raw_sem_wait)(sem_t*)                                         = NULL;
33 static int (*raw_sem_post)(sem_t*)                                         = NULL;
34
35 static void intercepter_init()
36 {
37   raw_pthread_create = (typeof(raw_pthread_create))dlsym(RTLD_NEXT, "pthread_create");
38   raw_pthread_join   = (typeof(raw_pthread_join))dlsym(RTLD_NEXT, "pthread_join");
39   raw_mutex_init    = (int (*)(pthread_mutex_t*, const pthread_mutexattr_t*))dlsym(RTLD_NEXT, "pthread_mutex_init");
40   raw_mutex_lock    = (int (*)(pthread_mutex_t*))dlsym(RTLD_NEXT, "pthread_mutex_lock");
41   raw_mutex_trylock = (int (*)(pthread_mutex_t*))dlsym(RTLD_NEXT, "pthread_mutex_trylock");
42   raw_mutex_unlock  = (int (*)(pthread_mutex_t*))dlsym(RTLD_NEXT, "pthread_mutex_unlock");
43   raw_mutex_destroy = (int (*)(pthread_mutex_t*))dlsym(RTLD_NEXT, "pthread_mutex_destroy");
44
45   raw_sleep        = (unsigned int (*)(unsigned int))dlsym(RTLD_NEXT, "sleep");
46   raw_usleep       = (int (*)(useconds_t usec))dlsym(RTLD_NEXT, "usleep");
47   raw_gettimeofday = (int (*)(struct timeval*, void*))dlsym(RTLD_NEXT, "gettimeofday");
48
49   raw_sem_open = (sem_t * (*)(const char*, int)) dlsym(RTLD_NEXT, "sem_open");
50   raw_sem_init = (int (*)(sem_t*, int, unsigned int))dlsym(RTLD_NEXT, "sem_init");
51   raw_sem_wait = (int (*)(sem_t*))dlsym(RTLD_NEXT, "sem_wait");
52   raw_sem_post = (int (*)(sem_t*))dlsym(RTLD_NEXT, "sem_post");
53 }
54
55 static int sthread_inside_simgrid = 1;
56 void sthread_enable(void)
57 { // Start intercepting all pthread calls
58   sthread_inside_simgrid = 0;
59 }
60 void sthread_disable(void)
61 { // Stop intercepting all pthread calls
62   sthread_inside_simgrid = 1;
63 }
64 int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg)
65 {
66   if (raw_pthread_create == NULL)
67     intercepter_init();
68
69   if (sthread_inside_simgrid)
70     return raw_pthread_create(thread, attr, start_routine, arg);
71
72   sthread_inside_simgrid = 1;
73   int res                = sthread_create(thread, attr, start_routine, arg);
74   sthread_inside_simgrid = 0;
75   return res;
76 }
77 int pthread_join(pthread_t thread, void** retval)
78 {
79   if (raw_pthread_join == NULL)
80     intercepter_init();
81
82   if (sthread_inside_simgrid)
83     return raw_pthread_join(thread, retval);
84
85   sthread_inside_simgrid = 1;
86   int res                = sthread_join(thread, retval);
87   sthread_inside_simgrid = 0;
88   return res;
89 }
90
91 int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr)
92 {
93   if (raw_mutex_init == NULL)
94     intercepter_init();
95
96   if (sthread_inside_simgrid)
97     return raw_mutex_init(mutex, attr);
98
99   sthread_inside_simgrid = 1;
100   int res                = sthread_mutex_init((sthread_mutex_t*)mutex, attr);
101   sthread_inside_simgrid = 0;
102   return res;
103 }
104
105 int pthread_mutex_lock(pthread_mutex_t* mutex)
106 {
107   if (raw_mutex_lock == NULL)
108     intercepter_init();
109
110   if (sthread_inside_simgrid)
111     return raw_mutex_lock(mutex);
112
113   sthread_inside_simgrid = 1;
114   int res                = sthread_mutex_lock((sthread_mutex_t*)mutex);
115   sthread_inside_simgrid = 0;
116   return res;
117 }
118
119 int pthread_mutex_trylock(pthread_mutex_t* mutex)
120 {
121   if (raw_mutex_trylock == NULL)
122     intercepter_init();
123
124   if (sthread_inside_simgrid)
125     return raw_mutex_trylock(mutex);
126
127   sthread_inside_simgrid = 1;
128   int res                = sthread_mutex_trylock((sthread_mutex_t*)mutex);
129   sthread_inside_simgrid = 0;
130   return res;
131 }
132
133 int pthread_mutex_unlock(pthread_mutex_t* mutex)
134 {
135   if (raw_mutex_unlock == NULL)
136     intercepter_init();
137
138   if (sthread_inside_simgrid)
139     return raw_mutex_unlock(mutex);
140
141   sthread_inside_simgrid = 1;
142   int res                = sthread_mutex_unlock((sthread_mutex_t*)mutex);
143   sthread_inside_simgrid = 0;
144   return res;
145 }
146 int pthread_mutex_destroy(pthread_mutex_t* mutex)
147 {
148   if (raw_mutex_destroy == NULL)
149     intercepter_init();
150
151   if (sthread_inside_simgrid)
152     return raw_mutex_destroy(mutex);
153
154   sthread_inside_simgrid = 1;
155   int res                = sthread_mutex_destroy((sthread_mutex_t*)mutex);
156   sthread_inside_simgrid = 0;
157   return res;
158 }
159
160 /* Glibc < 2.31 uses type "struct timezone *" for the second parameter of gettimeofday.
161    Other implementations use "void *" instead. */
162 #ifdef __GLIBC__
163 #if !__GLIBC_PREREQ(2, 31)
164 #define TIMEZONE_TYPE struct timezone
165 #endif
166 #endif
167 #ifndef TIMEZONE_TYPE
168 #define TIMEZONE_TYPE void
169 #endif
170
171 int gettimeofday(struct timeval* tv, XBT_ATTRIB_UNUSED TIMEZONE_TYPE* tz)
172 {
173   if (raw_gettimeofday == NULL)
174     intercepter_init();
175
176   if (sthread_inside_simgrid)
177     return raw_gettimeofday(tv, (void*)tz);
178
179   sthread_inside_simgrid = 1;
180   int res                = sthread_gettimeofday(tv);
181   sthread_inside_simgrid = 0;
182   return res;
183 }
184
185 unsigned int sleep(unsigned int seconds)
186 {
187   if (raw_sleep == NULL)
188     intercepter_init();
189
190   if (sthread_inside_simgrid)
191     return raw_sleep(seconds);
192
193   sthread_inside_simgrid = 1;
194   sthread_sleep(seconds);
195   sthread_inside_simgrid = 0;
196   return 0;
197 }
198
199 int usleep(useconds_t usec)
200 {
201   if (raw_usleep == NULL)
202     intercepter_init();
203
204   if (sthread_inside_simgrid)
205     return raw_usleep(usec);
206
207   sthread_inside_simgrid = 1;
208   sthread_sleep(((double)usec) / 1000000.);
209   sthread_inside_simgrid = 0;
210   return 0;
211 }
212
213 #if 0
214 int sem_init(sem_t *sem, int pshared, unsigned int value) {
215         int res;
216
217         res=raw_sem_init(sem,pshared,value);
218         return res;
219 }
220
221 int sem_wait(sem_t *sem) {
222         int res;
223
224         res = raw_sem_wait(sem);
225         return res;
226 }
227
228 int sem_post(sem_t *sem) {
229         return raw_sem_post(sem);
230 }
231
232 int pthread_join(pthread_t thread, void **retval) {
233         sg_actor_join(thread, -1);
234     return 0;
235 }
236
237 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr) {
238     *cond = sg_cond_init();
239     return 0;
240 }
241
242 int pthread_cond_signal(pthread_cond_t *cond) {
243         sg_cond_notify_one(*cond);
244     return 0;
245 }
246
247 int pthread_cond_broadcast(pthread_cond_t *cond) {
248         sg_cond_notify_all(*cond);
249     return 0;
250 }
251
252 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
253         sg_cond_wait(*cond, *mutex);
254     return 0;
255 }
256
257 int pthread_cond_destroy(pthread_cond_t *cond) {
258         sg_cond_destroy(*cond);
259     return 0;
260 }
261 #endif
262
263 /* Trampoline for the real main() */
264 static int (*raw_main)(int, char**, char**);
265
266 /* Our fake main() that gets called by __libc_start_main() */
267 static int main_hook(int argc, char** argv, char** envp)
268 {
269   return sthread_main(argc, argv, envp, raw_main);
270 }
271
272 /* Wrapper for __libc_start_main() that replaces the real main function with our hooked version. */
273 int __libc_start_main(int (*main)(int, char**, char**), int argc, char** argv, int (*init)(int, char**, char**),
274                       void (*fini)(void), void (*rtld_fini)(void), void* stack_end);
275
276 int __libc_start_main(int (*main)(int, char**, char**), int argc, char** argv, int (*init)(int, char**, char**),
277                       void (*fini)(void), void (*rtld_fini)(void), void* stack_end)
278 {
279   /* Save the real main function address */
280   raw_main = main;
281
282   /* Find the real __libc_start_main()... */
283   typeof(&__libc_start_main) orig = dlsym(RTLD_NEXT, "__libc_start_main");
284   /* ... and call it with our custom main function */
285 #if HAVE_VALGRIND_H
286   /* ... unless valgrind is used, and this instance is not the target program (but the valgrind launcher) */
287   if (getenv("VALGRIND_LIB") && !RUNNING_ON_VALGRIND)
288     return orig(raw_main, argc, argv, init, fini, rtld_fini, stack_end);
289 #endif
290   return orig(main_hook, argc, argv, init, fini, rtld_fini, stack_end);
291 }