drd_pthread_intercepts.c revision 5f5ef2ae9e7c2ce5ebc36c1e2fc98e5f81650be3
1/* -*- mode: C; c-basic-offset: 3; -*- */
2
3/*--------------------------------------------------------------------*/
4/*--- Client-space code for DRD.          drd_pthread_intercepts.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8  This file is part of DRD, a thread error detector.
9
10  Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
11
12  This program is free software; you can redistribute it and/or
13  modify it under the terms of the GNU General Public License as
14  published by the Free Software Foundation; either version 2 of the
15  License, or (at your option) any later version.
16
17  This program is distributed in the hope that it will be useful, but
18  WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  General Public License for more details.
21
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25  02111-1307, USA.
26
27  The GNU General Public License is contained in the file COPYING.
28*/
29
30/* ---------------------------------------------------------------------
31   ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
32
33   These functions are not called directly - they're the targets of code
34   redirection or load notifications (see pub_core_redir.h for info).
35   They're named weirdly so that the intercept code can find them when the
36   shared object is initially loaded.
37
38   Note that this filename has the "drd_" prefix because it can appear
39   in stack traces, and the "drd_" makes it a little clearer that it
40   originates from Valgrind.
41   ------------------------------------------------------------------ */
42
43/*
44 * Define _GNU_SOURCE to make sure that pthread_spinlock_t is available when
45 * compiling with older glibc versions (2.3 or before).
46 */
47#ifndef _GNU_SOURCE
48#define _GNU_SOURCE
49#endif
50
51#include <assert.h>         /* assert() */
52#include <pthread.h>        /* pthread_mutex_t */
53#include <semaphore.h>      /* sem_t */
54#include <stdio.h>          /* fprintf() */
55#include <stdlib.h>         /* malloc(), free() */
56#include <unistd.h>         /* confstr() */
57#include "config.h"         /* HAVE_PTHREAD_MUTEX_ADAPTIVE_NP etc. */
58#include "drd_basics.h"     /* DRD_() */
59#include "drd_clientreq.h"
60#include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
61
62
63/* Defines. */
64
65/*
66 * Do not undefine the two macro's below, or the following two subtle race
67 * conditions will be introduced in the data race detection algorithm:
68 * - sg_init() runs on the context of the created thread and copies the
69 *   vector clock of the creator thread. This only works reliably if
70 *   the creator thread waits until this copy has been performed.
71 * - Since DRD_(thread_compute_minimum_vc)() does not take the vector
72 *   clocks into account that are involved in thread creation but
73 *   for which the corresponding thread has not yet been created, by
74 *   undefining the macro below it becomes possible that segments get
75 *   discarded that should not yet be discarded. Or: some data races
76 *   are not detected.
77 */
78#define WAIT_UNTIL_CREATED_THREAD_STARTED
79#define ALLOCATE_THREAD_ARGS_ON_THE_STACK
80
81#define PTH_FUNC(ret_ty, f, args...)                            \
82   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args);  \
83   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
84
85
86/* Local data structures. */
87
88typedef struct
89{
90   void* (*start)(void*);
91   void* arg;
92   int   detachstate;
93#if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
94   int   wrapper_started;
95#endif
96} DrdPosixThreadArgs;
97
98
99/* Local function declarations. */
100
101static void DRD_(init)(void) __attribute__((constructor));
102static void DRD_(check_threading_library)(void);
103static void DRD_(set_main_thread_state)(void);
104
105
106/* Function definitions. */
107
108/**
109 * Shared library initialization function. The function init() is called after
110 * dlopen() has loaded the shared library with DRD client intercepts because
111 * the constructor attribute was specified in the declaration of this function.
112 * Note: do specify the -nostdlib option to gcc when linking this code into a
113 * shared library because doing so would cancel the effect of the constructor
114 * attribute ! Using the gcc option -nodefaultlibs is fine because this last
115 * option preserves the shared library initialization code that calls
116 * constructor and destructor functions.
117 */
118static void DRD_(init)(void)
119{
120   DRD_(check_threading_library)();
121   DRD_(set_main_thread_state)();
122}
123
124/**
125 * POSIX threads and DRD each have their own mutex type identification.
126 * Convert POSIX threads' mutex type to DRD's mutex type. In the code below
127 * if-statements are used to test the value of 'kind' instead of a switch
128 * statement because some of the PTHREAD_MUTEX_ macro's may have the same
129 * value.
130 */
131static MutexT DRD_(pthread_to_drd_mutex_type)(const int kind)
132{
133   if (kind == PTHREAD_MUTEX_RECURSIVE)
134      return mutex_type_recursive_mutex;
135   else if (kind == PTHREAD_MUTEX_ERRORCHECK)
136      return mutex_type_errorcheck_mutex;
137   else if (kind == PTHREAD_MUTEX_NORMAL)
138      return mutex_type_default_mutex;
139   else if (kind == PTHREAD_MUTEX_DEFAULT)
140      return mutex_type_default_mutex;
141#if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
142   else if (kind == PTHREAD_MUTEX_ADAPTIVE_NP)
143      return mutex_type_default_mutex;
144#endif
145   else
146   {
147      return mutex_type_invalid_mutex;
148   }
149}
150
151/**
152 * Read the mutex type stored in the client memory used for the mutex
153 * implementation.
154 *
155 * @note This function depends on the implementation of the POSIX threads
156 *   library -- the POSIX standard does not define the name of the member in
157 *   which the mutex type is stored.
158 * @note The function mutex_type() has been declared inline in order
159 *   to avoid that it shows up in call stacks (drd/tests/...exp* files).
160 * @note glibc stores the mutex type in the lowest two bits, and uses the
161 *   higher bits for flags like PTHREAD_MUTEXATTR_FLAG_ROBUST and
162 *   PTHREAD_MUTEXATTR_FLAG_PSHARED.
163 */
164static __inline__ MutexT DRD_(mutex_type)(pthread_mutex_t* mutex)
165{
166#if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
167   /* glibc + LinuxThreads. */
168   const int kind = mutex->__m_kind & 3;
169#elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
170   /* glibc + NPTL. */
171   const int kind = mutex->__data.__kind & 3;
172#else
173   /* Another POSIX threads implementation. Regression tests will fail. */
174   const int kind = PTHREAD_MUTEX_DEFAULT;
175   fprintf(stderr,
176           "Did not recognize your POSIX threads implementation. Giving up.\n");
177   assert(0);
178#endif
179   return DRD_(pthread_to_drd_mutex_type)(kind);
180}
181
182/**
183 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
184 */
185static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
186{
187   int res;
188   assert(joinable == 0 || joinable == 1);
189   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__SET_JOINABLE,
190                              tid, joinable, 0, 0, 0);
191}
192
193/**
194 * The function called from the thread created by pthread_create().
195 */
196static void* DRD_(thread_wrapper)(void* arg)
197{
198   int res;
199   DrdPosixThreadArgs* arg_ptr;
200   DrdPosixThreadArgs arg_copy;
201
202   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
203                              0, 0, 0, 0, 0);
204
205   arg_ptr = (DrdPosixThreadArgs*)arg;
206   arg_copy = *arg_ptr;
207#if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
208   arg_ptr->wrapper_started = 1;
209#else
210#if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
211#error Defining ALLOCATE_THREAD_ARGS_ON_THE_STACK but not \
212       WAIT_UNTIL_CREATED_THREAD_STARTED is not supported.
213#else
214   free(arg_ptr);
215#endif
216#endif
217
218   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
219                              pthread_self(), 0, 0, 0, 0);
220
221   DRD_(set_joinable)(pthread_self(),
222                      arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
223
224   return (arg_copy.start)(arg_copy.arg);
225}
226
227/**
228 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
229 * detected, and 0 otherwise.
230 *
231 * @see For more information about the confstr() function, see also
232 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
233 */
234static int DRD_(detected_linuxthreads)(void)
235{
236#if defined(linux)
237#if defined(_CS_GNU_LIBPTHREAD_VERSION)
238   /* Linux with a recent glibc. */
239   char buffer[256];
240   unsigned len;
241   len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
242   assert(len <= sizeof(buffer));
243   return len > 0 && buffer[0] == 'l';
244#else
245   /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
246   return 1;
247#endif
248#else
249   /* Another OS than Linux, hence no LinuxThreads. */
250   return 0;
251#endif
252}
253
254/**
255 * Stop and print an error message in case a non-supported threading
256 * library implementation (LinuxThreads) has been detected.
257 */
258static void DRD_(check_threading_library)(void)
259{
260   if (DRD_(detected_linuxthreads)())
261   {
262      if (getenv("LD_ASSUME_KERNEL"))
263      {
264         fprintf(stderr,
265"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
266"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
267"after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
268);
269      }
270      else
271      {
272         fprintf(stderr,
273"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
274"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
275"after having upgraded to a newer version of your Linux distribution.\n"
276"Giving up.\n"
277);
278      }
279      abort();
280   }
281}
282
283/**
284 * The main thread is the only thread not created by pthread_create().
285 * Update DRD's state information about the main thread.
286 */
287static void DRD_(set_main_thread_state)(void)
288{
289   int res;
290
291   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
292                              0, 0, 0, 0, 0);
293
294   // Make sure that DRD knows about the main thread's POSIX thread ID.
295   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
296                              pthread_self(), 0, 0, 0, 0);
297
298}
299
300
301/*
302 * Note: as of today there exist three different versions of pthread_create:
303 * - pthread_create@GLIBC_2.0
304 * - pthread_create@@GLIBC_2.1
305 * - pthread_create@@GLIBC_2.2.5
306 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
307 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
308 * versions have been implemented. In any glibc version where more than one
309 * pthread_create function has been implemented, older versions call the
310 * newer versions. Or: the pthread_create* wrapper defined below can be
311 * called recursively. Any code in this wrapper should take this in account.
312 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
313 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
314 * See also the implementation of pthread_create@GLIBC_2.0 in
315 * glibc-2.9/nptl/pthread_create.c.
316 */
317
318// pthread_create
319PTH_FUNC(int, pthreadZucreateZa, // pthread_create*
320         pthread_t *thread, const pthread_attr_t *attr,
321         void *(*start) (void *), void *arg)
322{
323   int    res;
324   int    ret;
325   OrigFn fn;
326#if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
327   DrdPosixThreadArgs thread_args;
328#endif
329   DrdPosixThreadArgs* thread_args_p;
330
331   VALGRIND_GET_ORIG_FN(fn);
332
333#if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
334   thread_args_p = &thread_args;
335#else
336   thread_args_p = malloc(sizeof(*thread_args_p));
337#endif
338   assert(thread_args_p);
339
340   thread_args_p->start           = start;
341   thread_args_p->arg             = arg;
342#if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
343   DRD_IGNORE_VAR(thread_args_p->wrapper_started);
344   thread_args_p->wrapper_started = 0;
345#endif
346   /*
347    * Find out whether the thread will be started as a joinable thread
348    * or as a detached thread. If no thread attributes have been specified,
349    * this means that the new thread will be started as a joinable thread.
350    */
351   thread_args_p->detachstate = PTHREAD_CREATE_JOINABLE;
352   if (attr)
353   {
354      if (pthread_attr_getdetachstate(attr, &thread_args_p->detachstate) != 0)
355      {
356         assert(0);
357      }
358   }
359   assert(thread_args_p->detachstate == PTHREAD_CREATE_JOINABLE
360          || thread_args_p->detachstate == PTHREAD_CREATE_DETACHED);
361
362   CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), thread_args_p);
363
364#if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
365   if (ret == 0)
366   {
367      /*
368       * Wait until the thread wrapper started.
369       * @todo Find out why some regression tests fail if thread arguments are
370       *   passed via dynamically allocated memory and if the loop below is
371       *   removed.
372       */
373      while (! thread_args_p->wrapper_started)
374      {
375         sched_yield();
376      }
377   }
378
379#if defined(ALLOCATE_THREAD_ARGS_DYNAMICALLY)
380   free(thread_args_p);
381#endif
382
383#endif
384
385   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_START_NEW_SEGMENT,
386                              pthread_self(), 0, 0, 0, 0);
387
388   return ret;
389}
390
391// pthread_join
392PTH_FUNC(int, pthreadZujoin, // pthread_join
393         pthread_t pt_joinee, void **thread_return)
394{
395   int      ret;
396   int      res;
397   OrigFn   fn;
398
399   VALGRIND_GET_ORIG_FN(fn);
400   CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
401   if (ret == 0)
402   {
403      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_JOIN,
404                                 pt_joinee, 0, 0, 0, 0);
405   }
406   return ret;
407}
408
409// pthread_detach
410PTH_FUNC(int, pthreadZudetach, pthread_t pt_thread)
411{
412   int ret;
413   OrigFn fn;
414   VALGRIND_GET_ORIG_FN(fn);
415   {
416      CALL_FN_W_W(ret, fn, pt_thread);
417      if (ret == 0)
418      {
419         DRD_(set_joinable)(pt_thread, 0);
420      }
421   }
422   return ret;
423}
424
425// pthread_cancel
426PTH_FUNC(int, pthreadZucancel, pthread_t pt_thread)
427{
428   int res;
429   int ret;
430   OrigFn fn;
431   VALGRIND_GET_ORIG_FN(fn);
432   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_THREAD_CANCEL,
433                              pt_thread, 0, 0, 0, 0);
434   CALL_FN_W_W(ret, fn, pt_thread);
435   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_CANCEL,
436                              pt_thread, ret==0, 0, 0, 0);
437   return ret;
438}
439
440// pthread_mutex_init
441PTH_FUNC(int, pthreadZumutexZuinit,
442         pthread_mutex_t *mutex,
443         const pthread_mutexattr_t* attr)
444{
445   int ret;
446   int res;
447   OrigFn fn;
448   int mt;
449   VALGRIND_GET_ORIG_FN(fn);
450   mt = PTHREAD_MUTEX_DEFAULT;
451   if (attr)
452      pthread_mutexattr_gettype(attr, &mt);
453   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_INIT,
454                              mutex, DRD_(pthread_to_drd_mutex_type)(mt),
455                              0, 0, 0);
456   CALL_FN_W_WW(ret, fn, mutex, attr);
457   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_INIT,
458                              mutex, 0, 0, 0, 0);
459   return ret;
460}
461
462// pthread_mutex_destroy
463PTH_FUNC(int, pthreadZumutexZudestroy,
464         pthread_mutex_t *mutex)
465{
466   int ret;
467   int res;
468   OrigFn fn;
469   VALGRIND_GET_ORIG_FN(fn);
470   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
471                              mutex, 0, 0, 0, 0);
472   CALL_FN_W_W(ret, fn, mutex);
473   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
474                              mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
475   return ret;
476}
477
478// pthread_mutex_lock
479PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
480         pthread_mutex_t *mutex)
481{
482   int   ret;
483   int   res;
484   OrigFn fn;
485   VALGRIND_GET_ORIG_FN(fn);
486   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
487                              mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
488   CALL_FN_W_W(ret, fn, mutex);
489   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__POST_MUTEX_LOCK,
490                              mutex, ret == 0, 0, 0, 0);
491   return ret;
492}
493
494// pthread_mutex_trylock
495PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
496         pthread_mutex_t *mutex)
497{
498   int   ret;
499   int   res;
500   OrigFn fn;
501   VALGRIND_GET_ORIG_FN(fn);
502   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
503                              mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
504   CALL_FN_W_W(ret, fn, mutex);
505   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
506                              mutex, ret == 0, 0, 0, 0);
507   return ret;
508}
509
510// pthread_mutex_timedlock
511PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
512         pthread_mutex_t *mutex,
513         const struct timespec *abs_timeout)
514{
515   int   ret;
516   int   res;
517   OrigFn fn;
518   VALGRIND_GET_ORIG_FN(fn);
519   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
520                              mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
521   CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
522   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
523                              mutex, ret == 0, 0, 0, 0);
524   return ret;
525}
526
527// pthread_mutex_unlock
528PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
529         pthread_mutex_t *mutex)
530{
531   int ret;
532   int   res;
533   OrigFn fn;
534   VALGRIND_GET_ORIG_FN(fn);
535   VALGRIND_DO_CLIENT_REQUEST(res, -1,
536                              VG_USERREQ__PRE_MUTEX_UNLOCK,
537                              mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
538   CALL_FN_W_W(ret, fn, mutex);
539   VALGRIND_DO_CLIENT_REQUEST(res, -1,
540                              VG_USERREQ__POST_MUTEX_UNLOCK,
541                              mutex, 0, 0, 0, 0);
542   return ret;
543}
544
545// pthread_cond_init
546PTH_FUNC(int, pthreadZucondZuinitZa, // pthread_cond_init*
547         pthread_cond_t* cond,
548         const pthread_condattr_t* attr)
549{
550   int ret;
551   int res;
552   OrigFn fn;
553   VALGRIND_GET_ORIG_FN(fn);
554   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_INIT,
555                              cond, 0, 0, 0, 0);
556   CALL_FN_W_WW(ret, fn, cond, attr);
557   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_INIT,
558                              cond, 0, 0, 0, 0);
559   return ret;
560}
561
562// pthread_cond_destroy
563PTH_FUNC(int, pthreadZucondZudestroyZa, // pthread_cond_destroy*
564         pthread_cond_t* cond)
565{
566   int ret;
567   int res;
568   OrigFn fn;
569   VALGRIND_GET_ORIG_FN(fn);
570   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_DESTROY,
571                              cond, 0, 0, 0, 0);
572   CALL_FN_W_W(ret, fn, cond);
573   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_DESTROY,
574                              cond, 0, 0, 0, 0);
575   return ret;
576}
577
578// pthread_cond_wait
579PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
580         pthread_cond_t *cond,
581         pthread_mutex_t *mutex)
582{
583   int   ret;
584   int   res;
585   OrigFn fn;
586   VALGRIND_GET_ORIG_FN(fn);
587   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
588                              cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
589   CALL_FN_W_WW(ret, fn, cond, mutex);
590   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
591                              cond, mutex, 1, 0, 0);
592   return ret;
593}
594
595// pthread_cond_timedwait
596PTH_FUNC(int, pthreadZucondZutimedwaitZa, // pthread_cond_timedwait*
597         pthread_cond_t *cond,
598         pthread_mutex_t *mutex,
599         const struct timespec* abstime)
600{
601   int   ret;
602   int   res;
603   OrigFn fn;
604   VALGRIND_GET_ORIG_FN(fn);
605   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
606                              cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
607   CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
608   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
609                              cond, mutex, 1, 0, 0);
610   return ret;
611}
612
613// pthread_cond_signal
614PTH_FUNC(int, pthreadZucondZusignalZa, // pthread_cond_signal*
615         pthread_cond_t* cond)
616{
617   int   ret;
618   int   res;
619   OrigFn fn;
620   VALGRIND_GET_ORIG_FN(fn);
621   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_SIGNAL,
622                              cond, 0, 0, 0, 0);
623   CALL_FN_W_W(ret, fn, cond);
624   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_SIGNAL,
625                              cond, 0, 0, 0, 0);
626   return ret;
627}
628
629// pthread_cond_broadcast
630PTH_FUNC(int, pthreadZucondZubroadcastZa, // pthread_cond_broadcast*
631         pthread_cond_t* cond)
632{
633   int   ret;
634   int   res;
635   OrigFn fn;
636   VALGRIND_GET_ORIG_FN(fn);
637   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_BROADCAST,
638                              cond, 0, 0, 0, 0);
639   CALL_FN_W_W(ret, fn, cond);
640   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_BROADCAST,
641                              cond, 0, 0, 0, 0);
642   return ret;
643}
644
645
646// pthread_spin_init
647PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
648         pthread_spinlock_t *spinlock,
649         int pshared)
650{
651   int ret;
652   int res;
653   OrigFn fn;
654   VALGRIND_GET_ORIG_FN(fn);
655   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
656                              spinlock, 0, 0, 0, 0);
657   CALL_FN_W_WW(ret, fn, spinlock, pshared);
658   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
659                              spinlock, 0, 0, 0, 0);
660   return ret;
661}
662
663// pthread_spin_destroy
664PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
665         pthread_spinlock_t *spinlock)
666{
667   int ret;
668   int res;
669   OrigFn fn;
670   VALGRIND_GET_ORIG_FN(fn);
671   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
672                              spinlock, 0, 0, 0, 0);
673   CALL_FN_W_W(ret, fn, spinlock);
674   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
675                              spinlock, mutex_type_spinlock, 0, 0, 0);
676   return ret;
677}
678
679// pthread_spin_lock
680PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
681         pthread_spinlock_t *spinlock)
682{
683   int   ret;
684   int   res;
685   OrigFn fn;
686   VALGRIND_GET_ORIG_FN(fn);
687   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
688                              spinlock, mutex_type_spinlock, 0, 0, 0);
689   CALL_FN_W_W(ret, fn, spinlock);
690   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
691                              spinlock, ret == 0, 0, 0, 0);
692   return ret;
693}
694
695// pthread_spin_trylock
696PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
697         pthread_spinlock_t *spinlock)
698{
699   int   ret;
700   int   res;
701   OrigFn fn;
702   VALGRIND_GET_ORIG_FN(fn);
703   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
704                              spinlock, mutex_type_spinlock, 0, 0, 0);
705   CALL_FN_W_W(ret, fn, spinlock);
706   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
707                              spinlock, ret == 0, 0, 0, 0);
708   return ret;
709}
710
711// pthread_spin_unlock
712PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
713         pthread_spinlock_t *spinlock)
714{
715   int   ret;
716   int   res;
717   OrigFn fn;
718   VALGRIND_GET_ORIG_FN(fn);
719   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
720                              spinlock, mutex_type_spinlock, 0, 0, 0);
721   CALL_FN_W_W(ret, fn, spinlock);
722   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
723                              spinlock, 0, 0, 0, 0);
724   return ret;
725}
726
727// pthread_barrier_init
728PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
729         pthread_barrier_t* barrier,
730         const pthread_barrierattr_t* attr,
731         unsigned count)
732{
733   int   ret;
734   int   res;
735   OrigFn fn;
736   VALGRIND_GET_ORIG_FN(fn);
737   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_INIT,
738                              barrier, pthread_barrier, count, 0, 0);
739   CALL_FN_W_WWW(ret, fn, barrier, attr, count);
740   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_INIT,
741                              barrier, pthread_barrier, 0, 0, 0);
742   return ret;
743}
744
745// pthread_barrier_destroy
746PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
747         pthread_barrier_t* barrier)
748{
749   int   ret;
750   int   res;
751   OrigFn fn;
752   VALGRIND_GET_ORIG_FN(fn);
753   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_DESTROY,
754                              barrier, pthread_barrier, 0, 0, 0);
755   CALL_FN_W_W(ret, fn, barrier);
756   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_DESTROY,
757                              barrier, pthread_barrier, 0, 0, 0);
758   return ret;
759}
760
761// pthread_barrier_wait
762PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
763         pthread_barrier_t* barrier)
764{
765   int   ret;
766   int   res;
767   OrigFn fn;
768   VALGRIND_GET_ORIG_FN(fn);
769   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_WAIT,
770                              barrier, pthread_barrier, 0, 0, 0);
771   CALL_FN_W_W(ret, fn, barrier);
772   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_WAIT,
773                              barrier, pthread_barrier,
774                              ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
775                              ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
776   return ret;
777}
778
779
780// sem_init
781PTH_FUNC(int, semZuinitZa, // sem_init*
782         sem_t *sem,
783         int pshared,
784         unsigned int value)
785{
786   int   ret;
787   int   res;
788   OrigFn fn;
789   VALGRIND_GET_ORIG_FN(fn);
790   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_INIT,
791                              sem, pshared, value, 0, 0);
792   CALL_FN_W_WWW(ret, fn, sem, pshared, value);
793   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_INIT,
794                              sem, 0, 0, 0, 0);
795   return ret;
796}
797
798// sem_destroy
799PTH_FUNC(int, semZudestroyZa, // sem_destroy*
800         sem_t *sem)
801{
802   int   ret;
803   int   res;
804   OrigFn fn;
805   VALGRIND_GET_ORIG_FN(fn);
806   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_DESTROY,
807                              sem, 0, 0, 0, 0);
808   CALL_FN_W_W(ret, fn, sem);
809   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_DESTROY,
810                              sem, 0, 0, 0, 0);
811   return ret;
812}
813
814// sem_wait
815PTH_FUNC(int, semZuwaitZa, // sem_wait*
816         sem_t *sem)
817{
818   int   ret;
819   int   res;
820   OrigFn fn;
821   VALGRIND_GET_ORIG_FN(fn);
822   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
823                              sem, 0, 0, 0, 0);
824   CALL_FN_W_W(ret, fn, sem);
825   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
826                              sem, ret == 0, 0, 0, 0);
827   return ret;
828}
829
830// sem_trywait
831PTH_FUNC(int, semZutrywaitZa, // sem_trywait*
832         sem_t *sem)
833{
834   int   ret;
835   int   res;
836   OrigFn fn;
837   VALGRIND_GET_ORIG_FN(fn);
838   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
839                              sem, 0, 0, 0, 0);
840   CALL_FN_W_W(ret, fn, sem);
841   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
842                              sem, ret == 0, 0, 0, 0);
843   return ret;
844}
845
846// sem_timedwait
847PTH_FUNC(int, semZutimedwait, // sem_timedwait
848         sem_t *sem, const struct timespec *abs_timeout)
849{
850   int   ret;
851   int   res;
852   OrigFn fn;
853   VALGRIND_GET_ORIG_FN(fn);
854   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
855                              sem, 0, 0, 0, 0);
856   CALL_FN_W_WW(ret, fn, sem, abs_timeout);
857   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
858                              sem, ret == 0, 0, 0, 0);
859   return ret;
860}
861
862// sem_post
863PTH_FUNC(int, semZupostZa, // sem_post*
864         sem_t *sem)
865{
866   int   ret;
867   int   res;
868   OrigFn fn;
869   VALGRIND_GET_ORIG_FN(fn);
870   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_POST,
871                              sem, 0, 0, 0, 0);
872   CALL_FN_W_W(ret, fn, sem);
873   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_POST,
874                              sem, ret == 0, 0, 0, 0);
875   return ret;
876}
877
878// pthread_rwlock_init
879PTH_FUNC(int,
880         pthreadZurwlockZuinitZa, // pthread_rwlock_init*
881         pthread_rwlock_t* rwlock,
882         const pthread_rwlockattr_t* attr)
883{
884   int   ret;
885   int   res;
886   OrigFn fn;
887   VALGRIND_GET_ORIG_FN(fn);
888   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_INIT,
889                              rwlock, 0, 0, 0, 0);
890   CALL_FN_W_WW(ret, fn, rwlock, attr);
891   return ret;
892}
893
894// pthread_rwlock_destroy
895PTH_FUNC(int,
896         pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
897         pthread_rwlock_t* rwlock)
898{
899   int   ret;
900   int   res;
901   OrigFn fn;
902   VALGRIND_GET_ORIG_FN(fn);
903   CALL_FN_W_W(ret, fn, rwlock);
904   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_DESTROY,
905                              rwlock, 0, 0, 0, 0);
906   return ret;
907}
908
909// pthread_rwlock_rdlock
910PTH_FUNC(int,
911         pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
912         pthread_rwlock_t* rwlock)
913{
914   int   ret;
915   int   res;
916   OrigFn fn;
917   VALGRIND_GET_ORIG_FN(fn);
918   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
919                              rwlock, 0, 0, 0, 0);
920   CALL_FN_W_W(ret, fn, rwlock);
921   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
922                              rwlock, ret == 0, 0, 0, 0);
923   return ret;
924}
925
926// pthread_rwlock_wrlock
927PTH_FUNC(int,
928         pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
929         pthread_rwlock_t* rwlock)
930{
931   int   ret;
932   int   res;
933   OrigFn fn;
934   VALGRIND_GET_ORIG_FN(fn);
935   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
936                              rwlock, 0, 0, 0, 0);
937   CALL_FN_W_W(ret, fn, rwlock);
938   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
939                              rwlock, ret == 0, 0, 0, 0);
940   return ret;
941}
942
943// pthread_rwlock_timedrdlock
944PTH_FUNC(int,
945         pthreadZurwlockZutimedrdlockZa, // pthread_rwlock_timedrdlock*
946         pthread_rwlock_t* rwlock)
947{
948   int   ret;
949   int   res;
950   OrigFn fn;
951   VALGRIND_GET_ORIG_FN(fn);
952   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
953                              rwlock, 0, 0, 0, 0);
954   CALL_FN_W_W(ret, fn, rwlock);
955   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
956                              rwlock, ret == 0, 0, 0, 0);
957   return ret;
958}
959
960// pthread_rwlock_timedwrlock
961PTH_FUNC(int,
962         pthreadZurwlockZutimedwrlockZa, // pthread_rwlock_timedwrlock*
963         pthread_rwlock_t* rwlock)
964{
965   int   ret;
966   int   res;
967   OrigFn fn;
968   VALGRIND_GET_ORIG_FN(fn);
969   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
970                              rwlock, 0, 0, 0, 0);
971   CALL_FN_W_W(ret, fn, rwlock);
972   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
973                              rwlock, ret == 0, 0, 0, 0);
974   return ret;
975}
976
977// pthread_rwlock_tryrdlock
978PTH_FUNC(int,
979         pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
980         pthread_rwlock_t* rwlock)
981{
982   int   ret;
983   int   res;
984   OrigFn fn;
985   VALGRIND_GET_ORIG_FN(fn);
986   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
987                              rwlock, 0, 0, 0, 0);
988   CALL_FN_W_W(ret, fn, rwlock);
989   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
990                              rwlock, ret == 0, 0, 0, 0);
991   return ret;
992}
993
994// pthread_rwlock_trywrlock
995PTH_FUNC(int,
996         pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
997         pthread_rwlock_t* rwlock)
998{
999   int   ret;
1000   int   res;
1001   OrigFn fn;
1002   VALGRIND_GET_ORIG_FN(fn);
1003   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1004                              rwlock, 0, 0, 0, 0);
1005   CALL_FN_W_W(ret, fn, rwlock);
1006   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1007                              rwlock, ret == 0, 0, 0, 0);
1008   return ret;
1009}
1010
1011// pthread_rwlock_unlock
1012PTH_FUNC(int,
1013         pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
1014         pthread_rwlock_t* rwlock)
1015{
1016   int   ret;
1017   int   res;
1018   OrigFn fn;
1019   VALGRIND_GET_ORIG_FN(fn);
1020   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_UNLOCK,
1021                              rwlock, 0, 0, 0, 0);
1022   CALL_FN_W_W(ret, fn, rwlock);
1023   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_UNLOCK,
1024                              rwlock, ret == 0, 0, 0, 0);
1025   return ret;
1026}
1027