drd_pthread_intercepts.c revision 3f4623e4ab3a3ab66c0685610e0f338a56f0426d
1
2/*--------------------------------------------------------------------*/
3/*--- Client-space code for drd.          drd_pthread_intercepts.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7  This file is part of drd, a data race detector.
8
9  Copyright (C) 2006-2008 Bart Van Assche
10  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// Make sure pthread_spinlock_t is available when compiling with older glibc
44// versions (2.3 or before).
45#ifndef _GNU_SOURCE
46#define _GNU_SOURCE
47#endif
48
49#include <assert.h>
50#include <inttypes.h>       // uintptr_t
51#include <pthread.h>
52#include <semaphore.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <unistd.h>         // confstr()
56#include "config.h"
57#include "drd_clientreq.h"
58#include "pub_tool_redir.h"
59
60
61// Defines.
62
63#define PTH_FUNC(ret_ty, f, args...)                            \
64  ret_ty VG_WRAP_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args);        \
65  ret_ty VG_WRAP_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args)
66
67
68/* Local data structures. */
69
70typedef struct
71{
72  void* (*start)(void*);
73  void* arg;
74  int   detachstate;
75#if 0
76  pthread_mutex_t mutex;
77  pthread_cond_t  cond;
78#else
79  int wrapper_started;
80#endif
81} VgPosixThreadArgs;
82
83
84/* Function declarations. */
85
86static void init(void) __attribute__((constructor));
87static void check_threading_library(void);
88static void vg_set_main_thread_state(void);
89
90
91/* Function definitions. */
92
93/** Shared library initialization function: the _init() function is called
94 *  after dlopen() has loaded the shared library. This function must not
95 *  be declared static.
96 */
97static void init(void)
98{
99  check_threading_library();
100  vg_set_main_thread_state();
101  /* glibc up to and including version 2.7 triggers conflicting accesses   */
102  /* on stdout and stderr when sending output to one of these streams from */
103  /* more than one thread. Suppress data race reports on these objects.    */
104  DRD_IGNORE_VAR(*stdout);
105  DRD_IGNORE_VAR(*stderr);
106}
107
108static MutexT pthread_to_drd_mutex_type(const int kind)
109{
110  switch (kind)
111  {
112    /* PTHREAD_MUTEX_RECURSIVE_NP */
113  case PTHREAD_MUTEX_RECURSIVE:
114    return mutex_type_recursive_mutex;
115    /* PTHREAD_MUTEX_ERRORCHECK_NP */
116  case PTHREAD_MUTEX_ERRORCHECK:
117    return mutex_type_errorcheck_mutex;
118    /* PTHREAD_MUTEX_TIMED_NP */
119    /* PTHREAD_MUTEX_NORMAL */
120  case PTHREAD_MUTEX_DEFAULT:
121#if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
122  case PTHREAD_MUTEX_ADAPTIVE_NP:
123#endif
124    return mutex_type_default_mutex;
125  }
126  return mutex_type_invalid_mutex;
127}
128
129static MutexT mutex_type(pthread_mutex_t* mutex)
130{
131#if defined(HAVE_PTHREAD_MUTEX_T__M_KIND)
132  /* LinuxThreads. */
133  const int kind = mutex->__m_kind;
134#elif defined(HAVE_PTHREAD_MUTEX_T__DATA__KIND)
135  /* NPTL. */
136  const int kind = mutex->__data.__kind;
137#else
138  /* Another POSIX threads implementation. Regression tests will fail. */
139  const int kind = PTHREAD_MUTEX_DEFAULT;
140  fprintf(stderr,
141          "Did not recognize your POSIX threads implementation. Giving up.\n");
142  assert(0);
143#endif
144  return pthread_to_drd_mutex_type(kind);
145}
146
147static void vg_start_suppression(const void* const p, size_t const size)
148{
149  int res;
150  VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_START_SUPPRESSION,
151                             p, size, 0, 0, 0);
152}
153
154static void vg_set_joinable(const pthread_t tid, const int joinable)
155{
156  int res;
157  assert(joinable == 0 || joinable == 1);
158  VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__SET_JOINABLE,
159                             tid, joinable, 0, 0, 0);
160}
161
162static void* vg_thread_wrapper(void* arg)
163{
164  int res;
165
166  VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
167                             0, 0, 0, 0, 0);
168
169  {
170    VgPosixThreadArgs* const arg_ptr = (VgPosixThreadArgs*)arg;
171    VgPosixThreadArgs const arg_copy = *arg_ptr;
172    void* result;
173
174#if 0
175    pthread_mutex_lock(arg_ptr->mutex);
176    pthread_cond_signal(arg_ptr->cond);
177    pthread_mutex_unlock(arg_ptr->mutex);
178#else
179    arg_ptr->wrapper_started = 1;
180#endif
181
182    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
183                               pthread_self(), 0, 0, 0, 0);
184    vg_set_joinable(pthread_self(),
185                    arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
186    result = (arg_copy.start)(arg_copy.arg);
187    return result;
188  }
189}
190
191/** Return 1 if LinuxThread has been detected, and 0 otherwise. */
192static int detected_linuxthreads(void)
193{
194#if defined(linux)
195#if defined(_CS_GNU_LIBPTHREAD_VERSION)
196  /* Linux with a recent glibc. */
197  char buffer[256];
198  unsigned len;
199  len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
200  assert(len <= sizeof(buffer));
201  return len > 0 && buffer[0] == 'l';
202#else
203  /* Linux without _CS_GNU_LIBPTHREAD_VERSION: most likely LinuxThreads. */
204  return 1;
205#endif
206#else
207  /* Another OS than Linux, hence no LinuxThreads. */
208  return 0;
209#endif
210}
211
212/** Stop and print an error message in case a non-supported threading
213 *  library (LinuxThreads) has been detected.
214 */
215static void check_threading_library(void)
216{
217  if (detected_linuxthreads())
218  {
219    if (getenv("LD_ASSUME_KERNEL"))
220    {
221      fprintf(stderr,
222              "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
223              "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
224              "after having unset the environment variable LD_ASSUME_KERNEL. Giving up.\n"
225              );
226    }
227    else
228    {
229      fprintf(stderr,
230              "Detected the LinuxThreads threading library. Sorry, but DRD only supports\n"
231              "the newer NPTL (Native POSIX Threads Library). Please try to rerun DRD\n"
232              "after having upgraded to a newer version of your Linux distribution.\n"
233              "Giving up.\n"
234              );
235    }
236    abort();
237  }
238}
239
240static void vg_set_main_thread_state(void)
241{
242  int res;
243
244  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
245                             0, 0, 0, 0, 0);
246
247  // Make sure that DRD knows about the main thread's POSIX thread ID.
248  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
249                             pthread_self(), 0, 0, 0, 0);
250
251}
252
253// pthread_create
254PTH_FUNC(int, pthreadZucreateZa, // pthread_create*
255         pthread_t *thread, const pthread_attr_t *attr,
256         void *(*start) (void *), void *arg)
257{
258  int    res;
259  int    ret;
260  OrigFn fn;
261  VgPosixThreadArgs vgargs;
262
263  VALGRIND_GET_ORIG_FN(fn);
264
265  vg_start_suppression(&vgargs.wrapper_started,
266                       sizeof(vgargs.wrapper_started));
267  vgargs.start = start;
268  vgargs.arg   = arg;
269  vgargs.wrapper_started = 0;
270  vgargs.detachstate = PTHREAD_CREATE_JOINABLE;
271  if (attr)
272  {
273    if (pthread_attr_getdetachstate(attr, &vgargs.detachstate) != 0)
274    {
275      assert(0);
276    }
277  }
278  assert(vgargs.detachstate == PTHREAD_CREATE_JOINABLE
279         || vgargs.detachstate == PTHREAD_CREATE_DETACHED);
280#if 0
281  pthread_mutex_init(&vgargs.mutex, 0);
282  pthread_cond_init(&vgargs.cond, 0);
283  pthread_mutex_lock(&vgargs.mutex);
284#endif
285  /* Suppress NPTL-specific conflicts between creator and created thread. */
286  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_STOP_RECORDING,
287                             0, 0, 0, 0, 0);
288  CALL_FN_W_WWWW(ret, fn, thread, attr, vg_thread_wrapper, &vgargs);
289  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_START_RECORDING,
290                             0, 0, 0, 0, 0);
291#if 0
292  pthread_cond_wait(&vgargs.cond, &vgargs.mutex);
293  pthread_mutex_unlock(&vgargs.mutex);
294  pthread_cond_destroy(&vgargs.cond);
295  pthread_mutex_destroy(&vgargs.mutex);
296#else
297  // Yes, you see it correctly, busy waiting ... The problem is that
298  // POSIX threads functions cannot be called here -- the functions defined
299  // in this file (drd_intercepts.c) would be called instead of those in
300  // libpthread.so. This loop is necessary because vgargs is allocated on the
301  // stack, and the created thread reads it.
302  if (ret == 0)
303  {
304    while (! vgargs.wrapper_started)
305    {
306      sched_yield();
307    }
308  }
309#endif
310  return ret;
311}
312
313// pthread_join
314PTH_FUNC(int, pthreadZujoin, // pthread_join
315         pthread_t pt_joinee, void **thread_return)
316{
317  int      ret;
318  int      res;
319  OrigFn   fn;
320
321  VALGRIND_GET_ORIG_FN(fn);
322  CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
323  if (ret == 0)
324  {
325    VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_JOIN,
326                               pt_joinee, 0, 0, 0, 0);
327  }
328  return ret;
329}
330
331// pthread_detach
332PTH_FUNC(int, pthreadZudetach, pthread_t pt_thread)
333{
334  int ret;
335  OrigFn fn;
336  VALGRIND_GET_ORIG_FN(fn);
337  {
338    CALL_FN_W_W(ret, fn, pt_thread);
339    if (ret == 0)
340    {
341      vg_set_joinable(pt_thread, 0);
342    }
343  }
344  return ret;
345}
346
347// pthread_mutex_init
348PTH_FUNC(int, pthreadZumutexZuinit,
349         pthread_mutex_t *mutex,
350         const pthread_mutexattr_t* attr)
351{
352  int ret;
353  int res;
354  OrigFn fn;
355  int mt;
356  VALGRIND_GET_ORIG_FN(fn);
357  mt = PTHREAD_MUTEX_DEFAULT;
358  if (attr)
359    pthread_mutexattr_gettype(attr, &mt);
360  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_INIT,
361                             mutex, pthread_to_drd_mutex_type(mt), 0, 0, 0);
362  CALL_FN_W_WW(ret, fn, mutex, attr);
363  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_INIT,
364                             mutex, 0, 0, 0, 0);
365  return ret;
366}
367
368// pthread_mutex_destroy
369PTH_FUNC(int, pthreadZumutexZudestroy,
370         pthread_mutex_t *mutex)
371{
372  int ret;
373  int res;
374  OrigFn fn;
375  VALGRIND_GET_ORIG_FN(fn);
376  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
377                             mutex, 0, 0, 0, 0);
378  CALL_FN_W_W(ret, fn, mutex);
379  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
380                             mutex, mutex_type(mutex), 0, 0, 0);
381  return ret;
382}
383
384// pthread_mutex_lock
385PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
386         pthread_mutex_t *mutex)
387{
388  int   ret;
389  int   res;
390  OrigFn fn;
391  VALGRIND_GET_ORIG_FN(fn);
392  VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
393                             mutex, mutex_type(mutex), 0, 0, 0);
394  CALL_FN_W_W(ret, fn, mutex);
395  VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__POST_MUTEX_LOCK,
396                             mutex, ret == 0, 0, 0, 0);
397  return ret;
398}
399
400// pthread_mutex_trylock
401PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
402         pthread_mutex_t *mutex)
403{
404  int   ret;
405  int   res;
406  OrigFn fn;
407  VALGRIND_GET_ORIG_FN(fn);
408  VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
409                             mutex, mutex_type(mutex), 1, 0, 0);
410  CALL_FN_W_W(ret, fn, mutex);
411  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
412                             mutex, ret == 0, 0, 0, 0);
413  return ret;
414}
415
416// pthread_mutex_timedlock
417PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
418         pthread_mutex_t *mutex,
419         const struct timespec *abs_timeout)
420{
421  int   ret;
422  int   res;
423  OrigFn fn;
424  VALGRIND_GET_ORIG_FN(fn);
425  VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
426                             mutex, mutex_type(mutex), 0, 0, 0);
427  CALL_FN_W_WW(ret, fn, mutex, abs_timeout);
428  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
429                             mutex, ret == 0, 0, 0, 0);
430  return ret;
431}
432
433// pthread_mutex_unlock
434PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
435         pthread_mutex_t *mutex)
436{
437  int ret;
438  int   res;
439  OrigFn fn;
440  VALGRIND_GET_ORIG_FN(fn);
441  VALGRIND_DO_CLIENT_REQUEST(res, -1,
442                             VG_USERREQ__PRE_MUTEX_UNLOCK,
443                             mutex, mutex_type(mutex), 0, 0, 0);
444  CALL_FN_W_W(ret, fn, mutex);
445  VALGRIND_DO_CLIENT_REQUEST(res, -1,
446                             VG_USERREQ__POST_MUTEX_UNLOCK,
447                             mutex, 0, 0, 0, 0);
448  return ret;
449}
450
451// pthread_cond_init
452PTH_FUNC(int, pthreadZucondZuinitZa, // pthread_cond_init*
453         pthread_cond_t* cond,
454         const pthread_condattr_t* attr)
455{
456  int ret;
457  int res;
458  OrigFn fn;
459  VALGRIND_GET_ORIG_FN(fn);
460  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_INIT,
461                             cond, 0, 0, 0, 0);
462  CALL_FN_W_WW(ret, fn, cond, attr);
463  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_INIT,
464                             cond, 0, 0, 0, 0);
465  return ret;
466}
467
468// pthread_cond_destroy
469PTH_FUNC(int, pthreadZucondZudestroyZa, // pthread_cond_destroy*
470         pthread_cond_t* cond)
471{
472  int ret;
473  int res;
474  OrigFn fn;
475  VALGRIND_GET_ORIG_FN(fn);
476  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_DESTROY,
477                             cond, 0, 0, 0, 0);
478  CALL_FN_W_W(ret, fn, cond);
479  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_DESTROY,
480                             cond, 0, 0, 0, 0);
481  return ret;
482}
483
484// pthread_cond_wait
485PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait*
486         pthread_cond_t *cond,
487         pthread_mutex_t *mutex)
488{
489  int   ret;
490  int   res;
491  OrigFn fn;
492  VALGRIND_GET_ORIG_FN(fn);
493  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
494                             cond, mutex, mutex_type(mutex), 0, 0);
495  CALL_FN_W_WW(ret, fn, cond, mutex);
496  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
497                             cond, mutex, 1, 0, 0);
498  return ret;
499}
500
501// pthread_cond_timedwait
502PTH_FUNC(int, pthreadZucondZutimedwaitZa, // pthread_cond_timedwait*
503         pthread_cond_t *cond,
504         pthread_mutex_t *mutex,
505         const struct timespec* abstime)
506{
507  int   ret;
508  int   res;
509  OrigFn fn;
510  VALGRIND_GET_ORIG_FN(fn);
511  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_WAIT,
512                             cond, mutex, mutex_type(mutex), 0, 0);
513  CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
514  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_WAIT,
515                             cond, mutex, 1, 0, 0);
516  return ret;
517}
518
519// pthread_cond_signal
520PTH_FUNC(int, pthreadZucondZusignalZa, // pthread_cond_signal*
521         pthread_cond_t* cond)
522{
523  int   ret;
524  int   res;
525  OrigFn fn;
526  VALGRIND_GET_ORIG_FN(fn);
527  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_SIGNAL,
528                             cond, 0, 0, 0, 0);
529  CALL_FN_W_W(ret, fn, cond);
530  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_SIGNAL,
531                             cond, 0, 0, 0, 0);
532  return ret;
533}
534
535// pthread_cond_broadcast
536PTH_FUNC(int, pthreadZucondZubroadcastZa, // pthread_cond_broadcast*
537         pthread_cond_t* cond)
538{
539  int   ret;
540  int   res;
541  OrigFn fn;
542  VALGRIND_GET_ORIG_FN(fn);
543  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_COND_BROADCAST,
544                             cond, 0, 0, 0, 0);
545  CALL_FN_W_W(ret, fn, cond);
546  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_COND_BROADCAST,
547                             cond, 0, 0, 0, 0);
548  return ret;
549}
550
551
552// pthread_spin_init
553PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
554         pthread_spinlock_t *spinlock,
555         int pshared)
556{
557  int ret;
558  int res;
559  OrigFn fn;
560  VALGRIND_GET_ORIG_FN(fn);
561  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
562                             spinlock, 0, 0, 0, 0);
563  CALL_FN_W_WW(ret, fn, spinlock, pshared);
564  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
565                             spinlock, 0, 0, 0, 0);
566  return ret;
567}
568
569// pthread_spin_destroy
570PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
571         pthread_spinlock_t *spinlock)
572{
573  int ret;
574  int res;
575  OrigFn fn;
576  VALGRIND_GET_ORIG_FN(fn);
577  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_DESTROY,
578                             spinlock, 0, 0, 0, 0);
579  CALL_FN_W_W(ret, fn, spinlock);
580  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
581                             spinlock, mutex_type_spinlock, 0, 0, 0);
582  return ret;
583}
584
585// pthread_spin_lock
586PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
587         pthread_spinlock_t *spinlock)
588{
589  int   ret;
590  int   res;
591  OrigFn fn;
592  VALGRIND_GET_ORIG_FN(fn);
593  VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
594                             spinlock, mutex_type_spinlock, 0, 0, 0);
595  CALL_FN_W_W(ret, fn, spinlock);
596  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
597                             spinlock, ret == 0, 0, 0, 0);
598  return ret;
599}
600
601// pthread_spin_trylock
602PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
603         pthread_spinlock_t *spinlock)
604{
605  int   ret;
606  int   res;
607  OrigFn fn;
608  VALGRIND_GET_ORIG_FN(fn);
609  VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_MUTEX_LOCK,
610                             spinlock, mutex_type_spinlock, 0, 0, 0);
611  CALL_FN_W_W(ret, fn, spinlock);
612  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_LOCK,
613                             spinlock, ret == 0, 0, 0, 0);
614  return ret;
615}
616
617// pthread_spin_unlock
618PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
619         pthread_spinlock_t *spinlock)
620{
621  int   ret;
622  int   res;
623  OrigFn fn;
624  VALGRIND_GET_ORIG_FN(fn);
625  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK,
626                             spinlock, mutex_type_spinlock, 0, 0, 0);
627  CALL_FN_W_W(ret, fn, spinlock);
628  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK,
629                             spinlock, 0, 0, 0, 0);
630  return ret;
631}
632
633// pthread_barrier_init
634PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
635         pthread_barrier_t* barrier,
636         const pthread_barrierattr_t* attr,
637         unsigned count)
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_BARRIER_INIT,
644                             barrier, pthread_barrier, count, 0, 0);
645  CALL_FN_W_WWW(ret, fn, barrier, attr, count);
646  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_INIT,
647                             barrier, pthread_barrier, 0, 0, 0);
648  return ret;
649}
650
651// pthread_barrier_destroy
652PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
653         pthread_barrier_t* barrier)
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_BARRIER_DESTROY,
660                             barrier, pthread_barrier, 0, 0, 0);
661  CALL_FN_W_W(ret, fn, barrier);
662  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_DESTROY,
663                             barrier, pthread_barrier, 0, 0, 0);
664  return ret;
665}
666
667// pthread_barrier_wait
668PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
669         pthread_barrier_t* barrier)
670{
671  int   ret;
672  int   res;
673  OrigFn fn;
674  VALGRIND_GET_ORIG_FN(fn);
675  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_BARRIER_WAIT,
676                             barrier, pthread_barrier, 0, 0, 0);
677  CALL_FN_W_W(ret, fn, barrier);
678  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_BARRIER_WAIT,
679                             barrier, pthread_barrier,
680                             ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD,
681                             0, 0);
682  return ret;
683}
684
685
686// sem_init
687PTH_FUNC(int, semZuinitZa, // sem_init*
688         sem_t *sem,
689         int pshared,
690         unsigned int value)
691{
692  int   ret;
693  int   res;
694  OrigFn fn;
695  VALGRIND_GET_ORIG_FN(fn);
696  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_INIT,
697                             sem, pshared, value, 0, 0);
698  CALL_FN_W_WWW(ret, fn, sem, pshared, value);
699  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_INIT,
700                             sem, 0, 0, 0, 0);
701  return ret;
702}
703
704// sem_destroy
705PTH_FUNC(int, semZudestroyZa, // sem_destroy*
706         sem_t *sem)
707{
708  int   ret;
709  int   res;
710  OrigFn fn;
711  VALGRIND_GET_ORIG_FN(fn);
712  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_DESTROY,
713                             sem, 0, 0, 0, 0);
714  CALL_FN_W_W(ret, fn, sem);
715  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_DESTROY,
716                             sem, 0, 0, 0, 0);
717  return ret;
718}
719
720// sem_wait
721PTH_FUNC(int, semZuwaitZa, // sem_wait*
722         sem_t *sem)
723{
724  int   ret;
725  int   res;
726  OrigFn fn;
727  VALGRIND_GET_ORIG_FN(fn);
728  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
729                             sem, 0, 0, 0, 0);
730  CALL_FN_W_W(ret, fn, sem);
731  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
732                             sem, ret == 0, 0, 0, 0);
733  return ret;
734}
735
736// sem_trywait
737PTH_FUNC(int, semZutrywaitZa, // sem_trywait*
738         sem_t *sem)
739{
740  int   ret;
741  int   res;
742  OrigFn fn;
743  VALGRIND_GET_ORIG_FN(fn);
744  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
745                             sem, 0, 0, 0, 0);
746  CALL_FN_W_W(ret, fn, sem);
747  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
748                             sem, ret == 0, 0, 0, 0);
749  return ret;
750}
751
752// sem_timedwait
753PTH_FUNC(int, semZutimedwait, // sem_timedwait
754         sem_t *sem, const struct timespec *abs_timeout)
755{
756  int   ret;
757  int   res;
758  OrigFn fn;
759  VALGRIND_GET_ORIG_FN(fn);
760  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_WAIT,
761                             sem, 0, 0, 0, 0);
762  CALL_FN_W_WW(ret, fn, sem, abs_timeout);
763  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_WAIT,
764                             sem, ret == 0, 0, 0, 0);
765  return ret;
766}
767
768// sem_post
769PTH_FUNC(int, semZupostZa, // sem_post*
770         sem_t *sem)
771{
772  int   ret;
773  int   res;
774  OrigFn fn;
775  VALGRIND_GET_ORIG_FN(fn);
776  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_SEM_POST,
777                             sem, 0, 0, 0, 0);
778  CALL_FN_W_W(ret, fn, sem);
779  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_SEM_POST,
780                             sem, ret == 0, 0, 0, 0);
781  return ret;
782}
783
784// pthread_rwlock_init
785PTH_FUNC(int,
786         pthreadZurwlockZuinitZa, // pthread_rwlock_init*
787         pthread_rwlock_t* rwlock,
788         const pthread_rwlockattr_t* attr)
789{
790  int   ret;
791  int   res;
792  OrigFn fn;
793  VALGRIND_GET_ORIG_FN(fn);
794  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_INIT,
795                             rwlock, 0, 0, 0, 0);
796  CALL_FN_W_WW(ret, fn, rwlock, attr);
797  return ret;
798}
799
800// pthread_rwlock_destroy
801PTH_FUNC(int,
802         pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy*
803         pthread_rwlock_t* rwlock)
804{
805  int   ret;
806  int   res;
807  OrigFn fn;
808  VALGRIND_GET_ORIG_FN(fn);
809  CALL_FN_W_W(ret, fn, rwlock);
810  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_DESTROY,
811                             rwlock, 0, 0, 0, 0);
812  return ret;
813}
814
815// pthread_rwlock_rdlock
816PTH_FUNC(int,
817         pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock*
818         pthread_rwlock_t* rwlock)
819{
820  int   ret;
821  int   res;
822  OrigFn fn;
823  VALGRIND_GET_ORIG_FN(fn);
824  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
825                             rwlock, 0, 0, 0, 0);
826  CALL_FN_W_W(ret, fn, rwlock);
827  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
828                             rwlock, ret == 0, 0, 0, 0);
829  return ret;
830}
831
832// pthread_rwlock_wrlock
833PTH_FUNC(int,
834         pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock*
835         pthread_rwlock_t* rwlock)
836{
837  int   ret;
838  int   res;
839  OrigFn fn;
840  VALGRIND_GET_ORIG_FN(fn);
841  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
842                             rwlock, 0, 0, 0, 0);
843  CALL_FN_W_W(ret, fn, rwlock);
844  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
845                             rwlock, ret == 0, 0, 0, 0);
846  return ret;
847}
848
849// pthread_rwlock_timedrdlock
850PTH_FUNC(int,
851         pthreadZurwlockZutimedrdlockZa, // pthread_rwlock_timedrdlock*
852         pthread_rwlock_t* rwlock)
853{
854  int   ret;
855  int   res;
856  OrigFn fn;
857  VALGRIND_GET_ORIG_FN(fn);
858  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
859                             rwlock, 0, 0, 0, 0);
860  CALL_FN_W_W(ret, fn, rwlock);
861  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
862                             rwlock, ret == 0, 0, 0, 0);
863  return ret;
864}
865
866// pthread_rwlock_timedwrlock
867PTH_FUNC(int,
868         pthreadZurwlockZutimedwrlockZa, // pthread_rwlock_timedwrlock*
869         pthread_rwlock_t* rwlock)
870{
871  int   ret;
872  int   res;
873  OrigFn fn;
874  VALGRIND_GET_ORIG_FN(fn);
875  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
876                             rwlock, 0, 0, 0, 0);
877  CALL_FN_W_W(ret, fn, rwlock);
878  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
879                             rwlock, ret == 0, 0, 0, 0);
880  return ret;
881}
882
883// pthread_rwlock_tryrdlock
884PTH_FUNC(int,
885         pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock*
886         pthread_rwlock_t* rwlock)
887{
888  int   ret;
889  int   res;
890  OrigFn fn;
891  VALGRIND_GET_ORIG_FN(fn);
892  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_RDLOCK,
893                             rwlock, 0, 0, 0, 0);
894  CALL_FN_W_W(ret, fn, rwlock);
895  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_RDLOCK,
896                             rwlock, ret == 0, 0, 0, 0);
897  return ret;
898}
899
900// pthread_rwlock_trywrlock
901PTH_FUNC(int,
902         pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock*
903         pthread_rwlock_t* rwlock)
904{
905  int   ret;
906  int   res;
907  OrigFn fn;
908  VALGRIND_GET_ORIG_FN(fn);
909  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_WRLOCK,
910                             rwlock, 0, 0, 0, 0);
911  CALL_FN_W_W(ret, fn, rwlock);
912  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_WRLOCK,
913                             rwlock, ret == 0, 0, 0, 0);
914  return ret;
915}
916
917// pthread_rwlock_unlock
918PTH_FUNC(int,
919         pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock*
920         pthread_rwlock_t* rwlock)
921{
922  int   ret;
923  int   res;
924  OrigFn fn;
925  VALGRIND_GET_ORIG_FN(fn);
926  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_RWLOCK_UNLOCK,
927                             rwlock, 0, 0, 0, 0);
928  CALL_FN_W_W(ret, fn, rwlock);
929  VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_RWLOCK_UNLOCK,
930                             rwlock, ret == 0, 0, 0, 0);
931  return ret;
932}
933