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