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