drd_pthread_intercepts.c revision d2d744c4b4ec47822a9d88833d2fa0500efb342a
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   return DRD_(pthread_to_drd_mutex_type)(kind);
170#elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
171   /* glibc + NPTL. */
172   const int kind = mutex->__data.__kind & 3;
173   return DRD_(pthread_to_drd_mutex_type)(kind);
174#else
175   /*
176    * Another POSIX threads implementation. The mutex type won't be printed
177    * when enabling --trace-mutex=yes.
178    */
179   return mutex_type_unknown;
180#endif
181}
182
183/**
184 * Tell DRD whether 'tid' is a joinable thread or a detached thread.
185 */
186static void DRD_(set_joinable)(const pthread_t tid, const int joinable)
187{
188   int res;
189   assert(joinable == 0 || joinable == 1);
190   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__SET_JOINABLE,
191                              tid, joinable, 0, 0, 0);
192}
193
194/**
195 * The function called from the thread created by pthread_create().
196 */
197static void* DRD_(thread_wrapper)(void* arg)
198{
199   int res;
200   DrdPosixThreadArgs* arg_ptr;
201   DrdPosixThreadArgs arg_copy;
202
203   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
204                              0, 0, 0, 0, 0);
205
206   arg_ptr = (DrdPosixThreadArgs*)arg;
207   arg_copy = *arg_ptr;
208#if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
209   arg_ptr->wrapper_started = 1;
210#else
211#if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
212#error Defining ALLOCATE_THREAD_ARGS_ON_THE_STACK but not \
213       WAIT_UNTIL_CREATED_THREAD_STARTED is not supported.
214#else
215   free(arg_ptr);
216#endif
217#endif
218
219   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
220                              pthread_self(), 0, 0, 0, 0);
221
222   DRD_(set_joinable)(pthread_self(),
223                      arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
224
225   return (arg_copy.start)(arg_copy.arg);
226}
227
228/**
229 * Return 1 if the LinuxThreads implementation of POSIX Threads has been
230 * detected, and 0 otherwise.
231 *
232 * @see For more information about the confstr() function, see also
233 * http://www.opengroup.org/onlinepubs/009695399/functions/confstr.html
234 */
235static int DRD_(detected_linuxthreads)(void)
236{
237#if defined(linux)
238#if defined(_CS_GNU_LIBPTHREAD_VERSION)
239   /* Linux with a recent glibc. */
240   char buffer[256];
241   unsigned len;
242   len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
243   assert(len <= sizeof(buffer));
244   return len > 0 && buffer[0] == 'l';
245#else
246   /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
247   return 1;
248#endif
249#else
250   /* Another OS than Linux, hence no LinuxThreads. */
251   return 0;
252#endif
253}
254
255/**
256 * Stop and print an error message in case a non-supported threading
257 * library implementation (LinuxThreads) has been detected.
258 */
259static void DRD_(check_threading_library)(void)
260{
261   if (DRD_(detected_linuxthreads)())
262   {
263      if (getenv("LD_ASSUME_KERNEL"))
264      {
265         fprintf(stderr,
266"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
267"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
268"after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
269);
270      }
271      else
272      {
273         fprintf(stderr,
274"Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
275"the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
276"after having upgraded to a newer version of your Linux distribution.\n"
277"Giving up.\n"
278);
279      }
280      abort();
281   }
282}
283
284/**
285 * The main thread is the only thread not created by pthread_create().
286 * Update DRD's state information about the main thread.
287 */
288static void DRD_(set_main_thread_state)(void)
289{
290   int res;
291
292   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
293                              0, 0, 0, 0, 0);
294
295   // Make sure that DRD knows about the main thread's POSIX thread ID.
296   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
297                              pthread_self(), 0, 0, 0, 0);
298
299}
300
301
302/*
303 * Note: as of today there exist three different versions of pthread_create:
304 * - pthread_create@GLIBC_2.0
305 * - pthread_create@@GLIBC_2.1
306 * - pthread_create@@GLIBC_2.2.5
307 * As an example, in libpthread-2.3.4 both pthread_create@GLIBC_2.0 and
308 * pthread_create@@GLIBC_2.1 are defined, while in libpthread-2.9 all three
309 * versions have been implemented. In any glibc version where more than one
310 * pthread_create function has been implemented, older versions call the
311 * newer versions. Or: the pthread_create* wrapper defined below can be
312 * called recursively. Any code in this wrapper should take this in account.
313 * As an example, it is not safe to invoke the DRD_STOP_RECORDING
314 * / DRD_START_RECORDING client requests from the pthread_create wrapper.
315 * See also the implementation of pthread_create@GLIBC_2.0 in
316 * glibc-2.9/nptl/pthread_create.c.
317 */
318
319// pthread_create
320PTH_FUNC(int, pthreadZucreateZa, // pthread_create*
321         pthread_t *thread, const pthread_attr_t *attr,
322         void *(*start) (void *), void *arg)
323{
324   int    res;
325   int    ret;
326   OrigFn fn;
327#if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
328   DrdPosixThreadArgs thread_args;
329#endif
330   DrdPosixThreadArgs* thread_args_p;
331
332   VALGRIND_GET_ORIG_FN(fn);
333
334#if defined(ALLOCATE_THREAD_ARGS_ON_THE_STACK)
335   thread_args_p = &thread_args;
336#else
337   thread_args_p = malloc(sizeof(*thread_args_p));
338#endif
339   assert(thread_args_p);
340
341   thread_args_p->start           = start;
342   thread_args_p->arg             = arg;
343#if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
344   DRD_IGNORE_VAR(thread_args_p->wrapper_started);
345   thread_args_p->wrapper_started = 0;
346#endif
347   /*
348    * Find out whether the thread will be started as a joinable thread
349    * or as a detached thread. If no thread attributes have been specified,
350    * this means that the new thread will be started as a joinable thread.
351    */
352   thread_args_p->detachstate = PTHREAD_CREATE_JOINABLE;
353   if (attr)
354   {
355      if (pthread_attr_getdetachstate(attr, &thread_args_p->detachstate) != 0)
356      {
357         assert(0);
358      }
359   }
360   assert(thread_args_p->detachstate == PTHREAD_CREATE_JOINABLE
361          || thread_args_p->detachstate == PTHREAD_CREATE_DETACHED);
362
363   CALL_FN_W_WWWW(ret, fn, thread, attr, DRD_(thread_wrapper), thread_args_p);
364
365#if defined(WAIT_UNTIL_CREATED_THREAD_STARTED)
366   if (ret == 0)
367   {
368      /*
369       * Wait until the thread wrapper started.
370       * @todo Find out why some regression tests fail if thread arguments are
371       *   passed via dynamically allocated memory and if the loop below is
372       *   removed.
373       */
374      while (! thread_args_p->wrapper_started)
375      {
376         sched_yield();
377      }
378   }
379
380#if defined(ALLOCATE_THREAD_ARGS_DYNAMICALLY)
381   free(thread_args_p);
382#endif
383
384#endif
385
386   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_START_NEW_SEGMENT,
387                              pthread_self(), 0, 0, 0, 0);
388
389   return ret;
390}
391
392// pthread_join
393PTH_FUNC(int, pthreadZujoinZa, // pthread_join*
394         pthread_t pt_joinee, void **thread_return)
395{
396   int      ret;
397   int      res;
398   OrigFn   fn;
399
400   VALGRIND_GET_ORIG_FN(fn);
401   CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
402   if (ret == 0)
403   {
404      VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_JOIN,
405                                 pt_joinee, 0, 0, 0, 0);
406   }
407   return ret;
408}
409
410// pthread_detach
411PTH_FUNC(int, pthreadZudetach, pthread_t pt_thread)
412{
413   int ret;
414   OrigFn fn;
415   VALGRIND_GET_ORIG_FN(fn);
416   {
417      CALL_FN_W_W(ret, fn, pt_thread);
418      if (ret == 0)
419      {
420         DRD_(set_joinable)(pt_thread, 0);
421      }
422   }
423   return ret;
424}
425
426// pthread_cancel*
427PTH_FUNC(int, pthreadZucancelZa, pthread_t pt_thread)
428{
429   int res;
430   int ret;
431   OrigFn fn;
432   VALGRIND_GET_ORIG_FN(fn);
433   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_THREAD_CANCEL,
434                              pt_thread, 0, 0, 0, 0);
435   CALL_FN_W_W(ret, fn, pt_thread);
436   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_CANCEL,
437                              pt_thread, ret==0, 0, 0, 0);
438   return ret;
439}
440
441// pthread_mutex_init
442PTH_FUNC(int, pthreadZumutexZuinit,
443         pthread_mutex_t *mutex,
444         const pthread_mutexattr_t* attr)
445{
446   int ret;
447   int res;
448   OrigFn fn;
449   int mt;
450   VALGRIND_GET_ORIG_FN(fn);
451   mt = PTHREAD_MUTEX_DEFAULT;
452   if (attr)
453      pthread_mutexattr_gettype(attr, &mt);
454   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_INIT,
455                              mutex, DRD_(pthread_to_drd_mutex_type)(mt),
456                              0, 0, 0);
457   CALL_FN_W_WW(ret, fn, mutex, attr);
458   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_INIT,
459                              mutex, 0, 0, 0, 0);
460   return ret;
461}
462
463// pthread_mutex_destroy
464PTH_FUNC(int, pthreadZumutexZudestroy,
465         pthread_mutex_t *mutex)
466{
467   int ret;
468   int res;
469   OrigFn fn;
470   VALGRIND_GET_ORIG_FN(fn);
471   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
472                              mutex, 0, 0, 0, 0);
473   CALL_FN_W_W(ret, fn, mutex);
474   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
475                              mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
476   return ret;
477}
478
479// pthread_mutex_lock
480PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
481         pthread_mutex_t *mutex)
482{
483   int   ret;
484   int   res;
485   OrigFn fn;
486   VALGRIND_GET_ORIG_FN(fn);
487   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
488                              mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
489   CALL_FN_W_W(ret, fn, mutex);
490   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__POST_MUTEX_LOCK,
491                              mutex, ret == 0, 0, 0, 0);
492   return ret;
493}
494
495// pthread_mutex_trylock
496PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
497         pthread_mutex_t *mutex)
498{
499   int   ret;
500   int   res;
501   OrigFn fn;
502   VALGRIND_GET_ORIG_FN(fn);
503   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
504                              mutex, DRD_(mutex_type)(mutex), 1, 0, 0);
505   CALL_FN_W_W(ret, fn, mutex);
506   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
507                              mutex, ret == 0, 0, 0, 0);
508   return ret;
509}
510
511// pthread_mutex_timedlock
512PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
513         pthread_mutex_t *mutex,
514         const struct timespec *abs_timeout)
515{
516   int   ret;
517   int   res;
518   OrigFn fn;
519   VALGRIND_GET_ORIG_FN(fn);
520   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
521                              mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
522   CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
523   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
524                              mutex, ret == 0, 0, 0, 0);
525   return ret;
526}
527
528// pthread_mutex_unlock
529PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
530         pthread_mutex_t *mutex)
531{
532   int ret;
533   int   res;
534   OrigFn fn;
535   VALGRIND_GET_ORIG_FN(fn);
536   VALGRIND_DO_CLIENT_REQUEST(res, -1,
537                              VG_USERREQ__PRE_MUTEX_UNLOCK,
538                              mutex, DRD_(mutex_type)(mutex), 0, 0, 0);
539   CALL_FN_W_W(ret, fn, mutex);
540   VALGRIND_DO_CLIENT_REQUEST(res, -1,
541                              VG_USERREQ__POST_MUTEX_UNLOCK,
542                              mutex, 0, 0, 0, 0);
543   return ret;
544}
545
546// pthread_cond_init
547PTH_FUNC(int, pthreadZucondZuinitZa, // pthread_cond_init*
548         pthread_cond_t* cond,
549         const pthread_condattr_t* attr)
550{
551   int ret;
552   int res;
553   OrigFn fn;
554   VALGRIND_GET_ORIG_FN(fn);
555   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_INIT,
556                              cond, 0, 0, 0, 0);
557   CALL_FN_W_WW(ret, fn, cond, attr);
558   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_INIT,
559                              cond, 0, 0, 0, 0);
560   return ret;
561}
562
563// pthread_cond_destroy
564PTH_FUNC(int, pthreadZucondZudestroyZa, // pthread_cond_destroy*
565         pthread_cond_t* cond)
566{
567   int ret;
568   int res;
569   OrigFn fn;
570   VALGRIND_GET_ORIG_FN(fn);
571   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_DESTROY,
572                              cond, 0, 0, 0, 0);
573   CALL_FN_W_W(ret, fn, cond);
574   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_DESTROY,
575                              cond, 0, 0, 0, 0);
576   return ret;
577}
578
579// pthread_cond_wait
580PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
581         pthread_cond_t *cond,
582         pthread_mutex_t *mutex)
583{
584   int   ret;
585   int   res;
586   OrigFn fn;
587   VALGRIND_GET_ORIG_FN(fn);
588   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
589                              cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
590   CALL_FN_W_WW(ret, fn, cond, mutex);
591   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
592                              cond, mutex, 1, 0, 0);
593   return ret;
594}
595
596// pthread_cond_timedwait
597PTH_FUNC(int, pthreadZucondZutimedwaitZa, // pthread_cond_timedwait*
598         pthread_cond_t *cond,
599         pthread_mutex_t *mutex,
600         const struct timespec* abstime)
601{
602   int   ret;
603   int   res;
604   OrigFn fn;
605   VALGRIND_GET_ORIG_FN(fn);
606   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
607                              cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
608   CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
609   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
610                              cond, mutex, 1, 0, 0);
611   return ret;
612}
613
614// NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
615// pthread_cond_signal_thread_np(). The former accepts one argument; the latter
616// two. Intercepting all pthread_cond_signal* functions will cause only one
617// argument to be passed to pthread_cond_signal_np() and hence will cause this
618// last function to crash.
619
620// pthread_cond_signal
621PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal
622         pthread_cond_t* cond)
623{
624   int   ret;
625   int   res;
626   OrigFn fn;
627   VALGRIND_GET_ORIG_FN(fn);
628   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_SIGNAL,
629                              cond, 0, 0, 0, 0);
630   CALL_FN_W_W(ret, fn, cond);
631   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_SIGNAL,
632                              cond, 0, 0, 0, 0);
633   return ret;
634}
635
636PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
637         pthread_cond_t* cond)
638{
639   int   ret;
640   int   res;
641   OrigFn fn;
642   VALGRIND_GET_ORIG_FN(fn);
643   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_SIGNAL,
644                              cond, 0, 0, 0, 0);
645   CALL_FN_W_W(ret, fn, cond);
646   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_SIGNAL,
647                              cond, 0, 0, 0, 0);
648   return ret;
649}
650
651// pthread_cond_broadcast
652PTH_FUNC(int, pthreadZucondZubroadcastZa, // pthread_cond_broadcast*
653         pthread_cond_t* cond)
654{
655   int   ret;
656   int   res;
657   OrigFn fn;
658   VALGRIND_GET_ORIG_FN(fn);
659   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_BROADCAST,
660                              cond, 0, 0, 0, 0);
661   CALL_FN_W_W(ret, fn, cond);
662   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_BROADCAST,
663                              cond, 0, 0, 0, 0);
664   return ret;
665}
666
667
668#if defined(HAVE_PTHREAD_SPIN_LOCK)
669// pthread_spin_init
670PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
671         pthread_spinlock_t *spinlock,
672         int pshared)
673{
674   int ret;
675   int res;
676   OrigFn fn;
677   VALGRIND_GET_ORIG_FN(fn);
678   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
679                              spinlock, 0, 0, 0, 0);
680   CALL_FN_W_WW(ret, fn, spinlock, pshared);
681   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
682                              spinlock, 0, 0, 0, 0);
683   return ret;
684}
685
686// pthread_spin_destroy
687PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
688         pthread_spinlock_t *spinlock)
689{
690   int ret;
691   int res;
692   OrigFn fn;
693   VALGRIND_GET_ORIG_FN(fn);
694   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
695                              spinlock, 0, 0, 0, 0);
696   CALL_FN_W_W(ret, fn, spinlock);
697   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
698                              spinlock, mutex_type_spinlock, 0, 0, 0);
699   return ret;
700}
701
702// pthread_spin_lock
703PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
704         pthread_spinlock_t *spinlock)
705{
706   int   ret;
707   int   res;
708   OrigFn fn;
709   VALGRIND_GET_ORIG_FN(fn);
710   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
711                              spinlock, mutex_type_spinlock, 0, 0, 0);
712   CALL_FN_W_W(ret, fn, spinlock);
713   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
714                              spinlock, ret == 0, 0, 0, 0);
715   return ret;
716}
717
718// pthread_spin_trylock
719PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
720         pthread_spinlock_t *spinlock)
721{
722   int   ret;
723   int   res;
724   OrigFn fn;
725   VALGRIND_GET_ORIG_FN(fn);
726   VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
727                              spinlock, mutex_type_spinlock, 0, 0, 0);
728   CALL_FN_W_W(ret, fn, spinlock);
729   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
730                              spinlock, ret == 0, 0, 0, 0);
731   return ret;
732}
733
734// pthread_spin_unlock
735PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
736         pthread_spinlock_t *spinlock)
737{
738   int   ret;
739   int   res;
740   OrigFn fn;
741   VALGRIND_GET_ORIG_FN(fn);
742   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
743                              spinlock, mutex_type_spinlock, 0, 0, 0);
744   CALL_FN_W_W(ret, fn, spinlock);
745   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
746                              spinlock, 0, 0, 0, 0);
747   return ret;
748}
749#endif   // HAVE_PTHREAD_SPIN_LOCK
750
751
752#if defined(HAVE_PTHREAD_BARRIER_INIT)
753// pthread_barrier_init
754PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
755         pthread_barrier_t* barrier,
756         const pthread_barrierattr_t* attr,
757         unsigned count)
758{
759   int   ret;
760   int   res;
761   OrigFn fn;
762   VALGRIND_GET_ORIG_FN(fn);
763   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_INIT,
764                              barrier, pthread_barrier, count, 0, 0);
765   CALL_FN_W_WWW(ret, fn, barrier, attr, count);
766   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_INIT,
767                              barrier, pthread_barrier, 0, 0, 0);
768   return ret;
769}
770
771// pthread_barrier_destroy
772PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
773         pthread_barrier_t* barrier)
774{
775   int   ret;
776   int   res;
777   OrigFn fn;
778   VALGRIND_GET_ORIG_FN(fn);
779   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_DESTROY,
780                              barrier, pthread_barrier, 0, 0, 0);
781   CALL_FN_W_W(ret, fn, barrier);
782   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_DESTROY,
783                              barrier, pthread_barrier, 0, 0, 0);
784   return ret;
785}
786
787// pthread_barrier_wait
788PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
789         pthread_barrier_t* barrier)
790{
791   int   ret;
792   int   res;
793   OrigFn fn;
794   VALGRIND_GET_ORIG_FN(fn);
795   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_WAIT,
796                              barrier, pthread_barrier, 0, 0, 0);
797   CALL_FN_W_W(ret, fn, barrier);
798   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_WAIT,
799                              barrier, pthread_barrier,
800                              ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
801                              ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
802   return ret;
803}
804#endif   // HAVE_PTHREAD_BARRIER_INIT
805
806
807// sem_init
808PTH_FUNC(int, semZuinitZa, // sem_init*
809         sem_t *sem,
810         int pshared,
811         unsigned int value)
812{
813   int   ret;
814   int   res;
815   OrigFn fn;
816   VALGRIND_GET_ORIG_FN(fn);
817   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_INIT,
818                              sem, pshared, value, 0, 0);
819   CALL_FN_W_WWW(ret, fn, sem, pshared, value);
820   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_INIT,
821                              sem, 0, 0, 0, 0);
822   return ret;
823}
824
825// sem_destroy
826PTH_FUNC(int, semZudestroyZa, // sem_destroy*
827         sem_t *sem)
828{
829   int   ret;
830   int   res;
831   OrigFn fn;
832   VALGRIND_GET_ORIG_FN(fn);
833   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_DESTROY,
834                              sem, 0, 0, 0, 0);
835   CALL_FN_W_W(ret, fn, sem);
836   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_DESTROY,
837                              sem, 0, 0, 0, 0);
838   return ret;
839}
840
841// sem_wait
842PTH_FUNC(int, semZuwaitZa, // sem_wait*
843         sem_t *sem)
844{
845   int   ret;
846   int   res;
847   OrigFn fn;
848   VALGRIND_GET_ORIG_FN(fn);
849   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
850                              sem, 0, 0, 0, 0);
851   CALL_FN_W_W(ret, fn, sem);
852   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
853                              sem, ret == 0, 0, 0, 0);
854   return ret;
855}
856
857// sem_trywait
858PTH_FUNC(int, semZutrywaitZa, // sem_trywait*
859         sem_t *sem)
860{
861   int   ret;
862   int   res;
863   OrigFn fn;
864   VALGRIND_GET_ORIG_FN(fn);
865   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
866                              sem, 0, 0, 0, 0);
867   CALL_FN_W_W(ret, fn, sem);
868   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
869                              sem, ret == 0, 0, 0, 0);
870   return ret;
871}
872
873// sem_timedwait
874PTH_FUNC(int, semZutimedwait, // sem_timedwait
875         sem_t *sem, const struct timespec *abs_timeout)
876{
877   int   ret;
878   int   res;
879   OrigFn fn;
880   VALGRIND_GET_ORIG_FN(fn);
881   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
882                              sem, 0, 0, 0, 0);
883   CALL_FN_W_WW(ret, fn, sem, abs_timeout);
884   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
885                              sem, ret == 0, 0, 0, 0);
886   return ret;
887}
888
889// sem_post
890PTH_FUNC(int, semZupostZa, // sem_post*
891         sem_t *sem)
892{
893   int   ret;
894   int   res;
895   OrigFn fn;
896   VALGRIND_GET_ORIG_FN(fn);
897   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_POST,
898                              sem, 0, 0, 0, 0);
899   CALL_FN_W_W(ret, fn, sem);
900   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_POST,
901                              sem, ret == 0, 0, 0, 0);
902   return ret;
903}
904
905// pthread_rwlock_init
906PTH_FUNC(int,
907         pthreadZurwlockZuinitZa, // pthread_rwlock_init*
908         pthread_rwlock_t* rwlock,
909         const pthread_rwlockattr_t* attr)
910{
911   int   ret;
912   int   res;
913   OrigFn fn;
914   VALGRIND_GET_ORIG_FN(fn);
915   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_INIT,
916                              rwlock, 0, 0, 0, 0);
917   CALL_FN_W_WW(ret, fn, rwlock, attr);
918   return ret;
919}
920
921// pthread_rwlock_destroy
922PTH_FUNC(int,
923         pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
924         pthread_rwlock_t* rwlock)
925{
926   int   ret;
927   int   res;
928   OrigFn fn;
929   VALGRIND_GET_ORIG_FN(fn);
930   CALL_FN_W_W(ret, fn, rwlock);
931   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_DESTROY,
932                              rwlock, 0, 0, 0, 0);
933   return ret;
934}
935
936// pthread_rwlock_rdlock
937PTH_FUNC(int,
938         pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
939         pthread_rwlock_t* rwlock)
940{
941   int   ret;
942   int   res;
943   OrigFn fn;
944   VALGRIND_GET_ORIG_FN(fn);
945   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
946                              rwlock, 0, 0, 0, 0);
947   CALL_FN_W_W(ret, fn, rwlock);
948   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
949                              rwlock, ret == 0, 0, 0, 0);
950   return ret;
951}
952
953// pthread_rwlock_wrlock
954PTH_FUNC(int,
955         pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
956         pthread_rwlock_t* rwlock)
957{
958   int   ret;
959   int   res;
960   OrigFn fn;
961   VALGRIND_GET_ORIG_FN(fn);
962   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
963                              rwlock, 0, 0, 0, 0);
964   CALL_FN_W_W(ret, fn, rwlock);
965   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
966                              rwlock, ret == 0, 0, 0, 0);
967   return ret;
968}
969
970// pthread_rwlock_timedrdlock
971PTH_FUNC(int,
972         pthreadZurwlockZutimedrdlockZa, // pthread_rwlock_timedrdlock*
973         pthread_rwlock_t* rwlock)
974{
975   int   ret;
976   int   res;
977   OrigFn fn;
978   VALGRIND_GET_ORIG_FN(fn);
979   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
980                              rwlock, 0, 0, 0, 0);
981   CALL_FN_W_W(ret, fn, rwlock);
982   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
983                              rwlock, ret == 0, 0, 0, 0);
984   return ret;
985}
986
987// pthread_rwlock_timedwrlock
988PTH_FUNC(int,
989         pthreadZurwlockZutimedwrlockZa, // pthread_rwlock_timedwrlock*
990         pthread_rwlock_t* rwlock)
991{
992   int   ret;
993   int   res;
994   OrigFn fn;
995   VALGRIND_GET_ORIG_FN(fn);
996   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
997                              rwlock, 0, 0, 0, 0);
998   CALL_FN_W_W(ret, fn, rwlock);
999   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1000                              rwlock, ret == 0, 0, 0, 0);
1001   return ret;
1002}
1003
1004// pthread_rwlock_tryrdlock
1005PTH_FUNC(int,
1006         pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
1007         pthread_rwlock_t* rwlock)
1008{
1009   int   ret;
1010   int   res;
1011   OrigFn fn;
1012   VALGRIND_GET_ORIG_FN(fn);
1013   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
1014                              rwlock, 0, 0, 0, 0);
1015   CALL_FN_W_W(ret, fn, rwlock);
1016   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
1017                              rwlock, ret == 0, 0, 0, 0);
1018   return ret;
1019}
1020
1021// pthread_rwlock_trywrlock
1022PTH_FUNC(int,
1023         pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
1024         pthread_rwlock_t* rwlock)
1025{
1026   int   ret;
1027   int   res;
1028   OrigFn fn;
1029   VALGRIND_GET_ORIG_FN(fn);
1030   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
1031                              rwlock, 0, 0, 0, 0);
1032   CALL_FN_W_W(ret, fn, rwlock);
1033   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
1034                              rwlock, ret == 0, 0, 0, 0);
1035   return ret;
1036}
1037
1038// pthread_rwlock_unlock
1039PTH_FUNC(int,
1040         pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
1041         pthread_rwlock_t* rwlock)
1042{
1043   int   ret;
1044   int   res;
1045   OrigFn fn;
1046   VALGRIND_GET_ORIG_FN(fn);
1047   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_UNLOCK,
1048                              rwlock, 0, 0, 0, 0);
1049   CALL_FN_W_W(ret, fn, rwlock);
1050   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_UNLOCK,
1051                              rwlock, ret == 0, 0, 0, 0);
1052   return ret;
1053}
1054