blob: 49388bc5c33e8250e4bb6680867e46359b1bb68d [file] [log] [blame]
sewardje663cb92002-04-12 10:26:32 +00001
sewardj439d45e2002-05-03 20:43:10 +00002/*--------------------------------------------------------------------*/
3/*--- A replacement for the standard libpthread.so. ---*/
4/*--- vg_libpthread.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardj439d45e2002-05-03 20:43:10 +000010
nethercotebb1c9912004-01-04 16:43:23 +000011 Copyright (C) 2000-2004 Julian Seward
sewardj439d45e2002-05-03 20:43:10 +000012 jseward@acm.org
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardj439d45e2002-05-03 20:43:10 +000030*/
31
32/* ALL THIS CODE RUNS ON THE SIMULATED CPU.
33
34 This is a replacement for the standard libpthread.so. It is loaded
sewardje663cb92002-04-12 10:26:32 +000035 as part of the client's image (if required) and directs pthread
36 calls through to Valgrind's request mechanism.
37
38 A couple of caveats.
39
40 1. Since it's a binary-compatible replacement for an existing library,
41 we must take care to used exactly the same data layouts, etc, as
42 the standard pthread.so does.
43
44 2. Since this runs as part of the client, there are no specific
45 restrictions on what headers etc we can include, so long as
46 this libpthread.so does not end up having dependencies on .so's
47 which the real one doesn't.
48
49 Later ... it appears we cannot call file-related stuff in libc here,
50 perhaps fair enough. Be careful what you call from here. Even exit()
51 doesn't work (gives infinite recursion and then stack overflow); hence
52 myexit(). Also fprintf doesn't seem safe.
53*/
54
55#include "valgrind.h" /* For the request-passing mechanism */
nethercotef1e5e152004-09-01 23:58:16 +000056#include "core.h" /* For the VG_USERREQ__* constants */
sewardje663cb92002-04-12 10:26:32 +000057
sewardja1ac5cb2002-05-27 13:00:05 +000058#define __USE_UNIX98
59#include <sys/types.h>
60#include <pthread.h>
61#undef __USE_UNIX98
62
fitzhardinge47735af2004-01-21 01:27:27 +000063#define __USE_GNU
64#include <dlfcn.h>
65#undef __USE_GNU
66
sewardje663cb92002-04-12 10:26:32 +000067#include <unistd.h>
68#include <string.h>
sewardj2a1dcce2002-04-22 12:45:25 +000069#include <sys/time.h>
sewardjf912dfc2002-11-13 21:51:10 +000070#include <sys/stat.h>
71#include <sys/poll.h>
sewardj2d94c112002-06-03 01:25:54 +000072#include <stdio.h>
daywalker005e7c12003-10-16 16:14:13 +000073#include <errno.h>
fitzhardingef7866182004-03-16 22:09:12 +000074#include <signal.h>
sewardj2d94c112002-06-03 01:25:54 +000075
fitzhardinge98abfc72003-12-16 02:05:15 +000076#include <stdlib.h>
sewardj705d3cb2002-05-23 13:13:12 +000077
jsgf855d93d2003-10-13 22:26:55 +000078# define strong_alias(name, aliasname) \
79 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
80
81# define weak_alias(name, aliasname) \
82 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
83
84
sewardj705d3cb2002-05-23 13:13:12 +000085/* ---------------------------------------------------------------------
nethercote1f0173b2004-02-28 15:40:36 +000086 Our own definition of types that vary between LinuxThreads and NPTL.
87 ------------------------------------------------------------------ */
88
89/* Moving from LinuxThreads to NPTL, several crucial types (eg.
90 pthread_mutex_t, pthread_mutexattr_t, etc) in pthreadtypes.h were changed
91 in binary-compatible, but source-incompatible, ways. We can similarly
92 use any layout we want, so long as it's binary-compatible. However, we
93 can no longer use the LinuxThreads types, because they won't work on NPTL
94 systems. Thus, we have to introduce a layer of indirection, and define
95 our own versions of these types (vg_pthread_mutex_t, etc). NPTL does
96 pretty much the same thing, and it keeps many of its internal types
97 secret.
98
99 We can layout our types however we want, as long as we put the small
100 number of fields in the right place for binary compatibility (eg.
101 mutex->kind). To make life easy, our versions have the exact same layout
102 as the LinuxThreads ones; only the type names and field names are
103 different (they differ only by include "vg" at the start).
104
105 In our implementation of the pthread operations (pthread_mutex_lock(),
106 pthread_mutexattr_settype(), etc) we always cast the standard pthread
107 types to our own types, (eg. pthread_mutex_t --> vg_pthread_mutex_t),
108 before working with them.
109
110 Note that we have various mutexes (and condvars) in this file that have the
111 type pthread_mutex_t (and pthread_cond_t). That is fine, because they
112 are always only handled by calling the standard pthread functions (eg.
113 pthread_mutex_lock()) on them. Phew.
114
115 WARNING: as a result of all this, we should *never* access these standard
116 pthread types as is; they *must* be converted to the vg_pthread_foo_t
117 equivalent. It would be nice if this was enforced... (but compilation
118 on NPTL-only systems should fail if this rule isn't followed...?)
119*/
120
121#include <sched.h> // for 'struct __sched_param'
122
123typedef struct __vg_pthread_attr_s
124{
125 int __vg_detachstate;
126 int __vg_schedpolicy;
127 struct __sched_param __vg_schedparam;
128 int __vg_inheritsched;
129 int __vg_scope;
130 size_t __vg_guardsize;
131 int __vg_stackaddr_set;
132 void *__vg_stackaddr;
133 size_t __vg_stacksize;
134} vg_pthread_attr_t;
135
136typedef struct
137{
138 int __vg_mutexkind;
139} vg_pthread_mutexattr_t;
140
thughes5d975072004-10-29 18:22:38 +0000141typedef struct
142{
143 int __vg_pshared;
144} vg_pthread_condattr_t;
145
nethercote1f0173b2004-02-28 15:40:36 +0000146typedef struct _vg_pthread_rwlock_t
147{
148 struct _vg_pthread_fastlock __vg_rw_lock; /* Lock to guarantee mutual exclusion */
149 int __vg_rw_readers; /* Number of readers */
150 /*_pthread_descr*/ void* __vg_rw_writer; /* Identity of writer, or NULL if none */
151 /*_pthread_descr*/ void* __vg_rw_read_waiting; /* Threads waiting for reading */
152 /*_pthread_descr*/ void* __vg_rw_write_waiting; /* Threads waiting for writing */
153 int __vg_rw_kind; /* Reader/Writer preference selection */
154 int __vg_rw_pshared; /* Shared between processes or not */
155} vg_pthread_rwlock_t;
156
157typedef struct
158{
159 int __vg_lockkind;
160 int __vg_pshared;
161} vg_pthread_rwlockattr_t;
162
163/* Converting pthread types to vg_pthread types. We always check that the
164 passed-in type is as big as ours, for safety. We also zero the pointer
165 to the original struct, to ensure we don't accidentally use it again. */
166
167#define CONVERT(foo, x, vg_x) \
168 my_assert(sizeof(*x) >= sizeof(vg_pthread_##foo##_t)); \
169 vg_x = (vg_pthread_##foo##_t*)x; \
170 x = 0; // ensure we don't accidentally use x again!
171
thughesebed9982004-06-12 17:25:25 +0000172
173/* ---------------------------------------------------------------------
174 Our own definition of types that only exist in NPTL.
175 ------------------------------------------------------------------ */
176
177#ifndef HAVE___PTHREAD_UNWIND_BUF_T
178
179typedef struct
180{
181 struct
182 {
183 jmp_buf __cancel_jmp_buf;
184 int __mask_was_saved;
185 } __cancel_jmp_buf[1];
186 void *__pad[4];
187} __pthread_unwind_buf_t __attribute__ ((__aligned__));
188
189#endif
190
nethercote1f0173b2004-02-28 15:40:36 +0000191/* ---------------------------------------------------------------------
sewardj705d3cb2002-05-23 13:13:12 +0000192 Forwardses.
193 ------------------------------------------------------------------ */
194
sewardj11f0bb42003-04-26 20:11:15 +0000195#define WEAK __attribute__((weak))
196
sewardjfd7747b2002-12-01 10:25:53 +0000197static
198__inline__
199int is_kerror ( int res )
200{
201 if (res >= -4095 && res <= -1)
202 return 1;
203 else
204 return 0;
205}
206
sewardj08c7f012002-10-07 23:56:55 +0000207
208#ifdef GLIBC_2_3
209 /* kludge by JRS (not from glibc) ... */
210 typedef void* __locale_t;
211
212 /* Copied from locale/locale.h in glibc-2.2.93 sources */
213 /* This value can be passed to `uselocale' and may be returned by
214 it. Passing this value to any other function has undefined
215 behavior. */
216# define LC_GLOBAL_LOCALE ((__locale_t) -1L)
217 extern __locale_t __uselocale ( __locale_t );
218#endif
219
thughes5298da92004-03-07 19:36:14 +0000220static void
221init_global_thread_specific_state ( void );
fitzhardinge47735af2004-01-21 01:27:27 +0000222
thughes5298da92004-03-07 19:36:14 +0000223static void
224init_thread_specific_state ( void );
sewardj705d3cb2002-05-23 13:13:12 +0000225
thughes11975ff2004-06-12 12:58:22 +0000226static void
227set_ret_val ( void* );
228static void *
229get_ret_val ( void );
230
sewardje663cb92002-04-12 10:26:32 +0000231/* ---------------------------------------------------------------------
232 Helpers. We have to be pretty self-sufficient.
233 ------------------------------------------------------------------ */
234
sewardj436e0582002-04-26 14:31:40 +0000235/* Number of times any given error message is printed. */
236#define N_MOANS 3
237
sewardj45b4b372002-04-16 22:50:32 +0000238/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
239 Returns 0 (none) if not running on Valgrind. */
240static
241int get_pt_trace_level ( void )
242{
243 int res;
244 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
245 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
246 0, 0, 0, 0);
247 return res;
248}
249
fitzhardinge98abfc72003-12-16 02:05:15 +0000250/* Don't do anything if we're not under Valgrind */
sewardj604ec3c2002-04-18 22:38:41 +0000251static __inline__
sewardje663cb92002-04-12 10:26:32 +0000252void ensure_valgrind ( char* caller )
253{
fitzhardinge98abfc72003-12-16 02:05:15 +0000254 if (!RUNNING_ON_VALGRIND) {
255 const char msg[] = "Warning: this libpthread.so should only be run with Valgrind\n";
256 VG_(do_syscall)(__NR_write, 2, msg, sizeof(msg)-1);
257 VG_(do_syscall)(__NR_exit, 1);
258 }
sewardje663cb92002-04-12 10:26:32 +0000259}
260
sewardjbea1caa2002-05-10 23:20:58 +0000261/* While we're at it ... hook our own startup function into this
262 game. */
sewardje663cb92002-04-12 10:26:32 +0000263
264static
sewardj3b5d8862002-04-20 13:53:23 +0000265__attribute__((noreturn))
daywalker3222e0a2003-09-18 01:39:50 +0000266void barf ( const char* str )
sewardje663cb92002-04-12 10:26:32 +0000267{
sewardj69a72a52002-11-03 13:41:41 +0000268 char buf[1000];
daywalker3222e0a2003-09-18 01:39:50 +0000269 strcpy(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000270 strcat(buf, str);
nethercote421281e2003-11-20 16:20:55 +0000271 strcat(buf, "\nPlease report this bug at: ");
272 strcat(buf, VG_BUGS_TO);
sewardje663cb92002-04-12 10:26:32 +0000273 strcat(buf, "\n\n");
fitzhardinge98abfc72003-12-16 02:05:15 +0000274 VALGRIND_INTERNAL_PRINTF(buf);
275 _exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000276 /* We have to persuade gcc into believing this doesn't return. */
277 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000278}
279
280
nethercoteaad8c192003-11-20 14:23:09 +0000281static void cat_n_send ( char* s1, char* s2, char* s3 )
sewardj2a3d28c2002-04-14 13:27:00 +0000282{
sewardj69a72a52002-11-03 13:41:41 +0000283 char buf[1000];
sewardj436e0582002-04-26 14:31:40 +0000284 if (get_pt_trace_level() >= 0) {
nethercoteaad8c192003-11-20 14:23:09 +0000285 snprintf(buf, sizeof(buf), "%s%s%s", s1, s2, s3);
sewardj69a72a52002-11-03 13:41:41 +0000286 buf[sizeof(buf)-1] = '\0';
fitzhardinge98abfc72003-12-16 02:05:15 +0000287 VALGRIND_INTERNAL_PRINTF(buf);
sewardj45b4b372002-04-16 22:50:32 +0000288 }
sewardj2a3d28c2002-04-14 13:27:00 +0000289}
290
nethercoteaad8c192003-11-20 14:23:09 +0000291static void oh_dear ( char* fn, char* aux, char* s )
sewardj69a72a52002-11-03 13:41:41 +0000292{
nethercoteaad8c192003-11-20 14:23:09 +0000293 cat_n_send ( "warning: Valgrind's ", fn, s );
294 if (NULL != aux)
295 cat_n_send ( " ", aux, "" );
296 cat_n_send ( " your program may misbehave as a result", "", "" );
sewardj69a72a52002-11-03 13:41:41 +0000297}
298
nethercoteaad8c192003-11-20 14:23:09 +0000299static void ignored ( char* fn, char* aux )
sewardj30671ff2002-04-21 00:13:57 +0000300{
nethercoteaad8c192003-11-20 14:23:09 +0000301 oh_dear ( fn, aux, " does nothing" );
302}
303
304static void kludged ( char* fn, char* aux )
305{
306 oh_dear ( fn, aux, " is incomplete" );
sewardj439d45e2002-05-03 20:43:10 +0000307}
308
sewardj69a72a52002-11-03 13:41:41 +0000309
sewardjccef2e62002-05-29 19:26:32 +0000310__attribute__((noreturn))
nethercoteaad8c192003-11-20 14:23:09 +0000311void vgPlain_unimp ( char* fn )
sewardj3b13f0e2002-04-25 20:17:29 +0000312{
nethercoteaad8c192003-11-20 14:23:09 +0000313 cat_n_send ( "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ", fn, "" );
nethercote421281e2003-11-20 16:20:55 +0000314 barf("unimplemented function");
sewardj3b13f0e2002-04-25 20:17:29 +0000315}
316
sewardje663cb92002-04-12 10:26:32 +0000317
nethercote9b3c7652004-10-19 13:18:00 +0000318void VG_(user_assert_fail) ( const Char* expr, const Char* file, Int line, const Char* fn )
sewardj2d94c112002-06-03 01:25:54 +0000319{
sewardj69a72a52002-11-03 13:41:41 +0000320 char buf[1000];
sewardj2d94c112002-06-03 01:25:54 +0000321 static Bool entered = False;
322 if (entered)
fitzhardinge98abfc72003-12-16 02:05:15 +0000323 _exit(2);
sewardj2d94c112002-06-03 01:25:54 +0000324 entered = True;
sewardj69a72a52002-11-03 13:41:41 +0000325 sprintf(buf, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
326 "valgrind", file, line, fn, expr );
nethercoteaad8c192003-11-20 14:23:09 +0000327 cat_n_send ( "", buf, "" );
nethercote421281e2003-11-20 16:20:55 +0000328 sprintf(buf, "Please report this bug at: %s\n\n", VG_BUGS_TO);
fitzhardinge98abfc72003-12-16 02:05:15 +0000329 cat_n_send ( "", buf, "" );
330 _exit(1);
sewardj2d94c112002-06-03 01:25:54 +0000331}
332
sewardj00a66b12002-10-12 16:42:35 +0000333static
334void my_free ( void* ptr )
335{
fitzhardinge98abfc72003-12-16 02:05:15 +0000336#if 0
sewardj00a66b12002-10-12 16:42:35 +0000337 int res;
338 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
339 VG_USERREQ__FREE, ptr, 0, 0, 0);
340 my_assert(res == 0);
fitzhardinge98abfc72003-12-16 02:05:15 +0000341#else
342 free(ptr);
343#endif
sewardj00a66b12002-10-12 16:42:35 +0000344}
345
346
347static
348void* my_malloc ( int nbytes )
349{
350 void* res;
fitzhardinge98abfc72003-12-16 02:05:15 +0000351#if 0
sewardj00a66b12002-10-12 16:42:35 +0000352 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
353 VG_USERREQ__MALLOC, nbytes, 0, 0, 0);
fitzhardinge98abfc72003-12-16 02:05:15 +0000354#else
355 res = malloc(nbytes);
356#endif
sewardj00a66b12002-10-12 16:42:35 +0000357 my_assert(res != (void*)0);
358 return res;
359}
360
361
sewardj2d94c112002-06-03 01:25:54 +0000362
sewardje663cb92002-04-12 10:26:32 +0000363/* ---------------------------------------------------------------------
364 Pass pthread_ calls to Valgrind's request mechanism.
365 ------------------------------------------------------------------ */
366
sewardja1ac5cb2002-05-27 13:00:05 +0000367
sewardjf8f819e2002-04-17 23:21:37 +0000368/* ---------------------------------------------------
sewardj4dced352002-06-04 22:54:20 +0000369 Ummm ..
370 ------------------------------------------------ */
371
372static
373void pthread_error ( const char* msg )
374{
375 int res;
376 VALGRIND_MAGIC_SEQUENCE(res, 0,
377 VG_USERREQ__PTHREAD_ERROR,
378 msg, 0, 0, 0);
379}
380
381
382/* ---------------------------------------------------
sewardj00a66b12002-10-12 16:42:35 +0000383 Here so it can be inlined without complaint.
384 ------------------------------------------------ */
385
386__inline__
387pthread_t pthread_self(void)
388{
389 int tid;
390 ensure_valgrind("pthread_self");
391 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
392 VG_USERREQ__PTHREAD_GET_THREADID,
393 0, 0, 0, 0);
394 if (tid < 1 || tid >= VG_N_THREADS)
395 barf("pthread_self: invalid ThreadId");
396 return tid;
397}
398
399
400/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000401 THREAD ATTRIBUTES
402 ------------------------------------------------ */
403
sewardj6af4b5d2002-04-16 04:40:49 +0000404int pthread_attr_init(pthread_attr_t *attr)
405{
nethercote1f0173b2004-02-28 15:40:36 +0000406 vg_pthread_attr_t* vg_attr;
407 CONVERT(attr, attr, vg_attr);
408
sewardj7989d0c2002-05-28 11:00:01 +0000409 /* Just initialise the fields which we might look at. */
nethercote1f0173b2004-02-28 15:40:36 +0000410 vg_attr->__vg_detachstate = PTHREAD_CREATE_JOINABLE;
sewardj111b14c2002-10-20 16:22:57 +0000411 /* Linuxthreads sets this field to the value __getpagesize(), so I
412 guess the following is OK. */
nethercote73b526f2004-10-31 18:48:21 +0000413 vg_attr->__vg_guardsize = VKI_PAGE_SIZE;
thughesdaa34562004-06-27 12:48:53 +0000414 /* No special stack yet. */
415 vg_attr->__vg_stackaddr = 0;
416 vg_attr->__vg_stacksize = VG_PTHREAD_STACK_SIZE;
nethercote1f0173b2004-02-28 15:40:36 +0000417 return 0;
sewardj6af4b5d2002-04-16 04:40:49 +0000418}
419
420int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
421{
nethercote1f0173b2004-02-28 15:40:36 +0000422 vg_pthread_attr_t* vg_attr;
423 CONVERT(attr, attr, vg_attr);
424
sewardj7989d0c2002-05-28 11:00:01 +0000425 if (detachstate != PTHREAD_CREATE_JOINABLE
sewardj4dced352002-06-04 22:54:20 +0000426 && detachstate != PTHREAD_CREATE_DETACHED) {
427 pthread_error("pthread_attr_setdetachstate: "
428 "detachstate is invalid");
sewardj7989d0c2002-05-28 11:00:01 +0000429 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000430 }
nethercote1f0173b2004-02-28 15:40:36 +0000431 vg_attr->__vg_detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000432 return 0;
433}
434
njn25e49d8e72002-09-23 09:36:25 +0000435int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
436{
nethercote1f0173b2004-02-28 15:40:36 +0000437 vg_pthread_attr_t* vg_attr;
438 CONVERT(attr, attr, vg_attr);
nethercote1f0173b2004-02-28 15:40:36 +0000439 *detachstate = vg_attr->__vg_detachstate;
njn25e49d8e72002-09-23 09:36:25 +0000440 return 0;
441}
442
thughes47501812004-10-16 14:24:43 +0000443int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
444{
445 static int moans = N_MOANS;
446 if (moans-- > 0)
447 kludged("pthread_attr_getinheritsched", NULL);
448 *inherit = PTHREAD_EXPLICIT_SCHED;
449 return 0;
450}
451
sewardj30671ff2002-04-21 00:13:57 +0000452int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
453{
sewardj436e0582002-04-26 14:31:40 +0000454 static int moans = N_MOANS;
455 if (moans-- > 0)
nethercoteaad8c192003-11-20 14:23:09 +0000456 ignored("pthread_attr_setinheritsched", NULL);
sewardj30671ff2002-04-21 00:13:57 +0000457 return 0;
458}
sewardj6af4b5d2002-04-16 04:40:49 +0000459
sewardj11f0bb42003-04-26 20:11:15 +0000460WEAK
thughesdaa34562004-06-27 12:48:53 +0000461int pthread_attr_setstacksize (pthread_attr_t *attr,
462 size_t stacksize)
sewardj0286dd52002-05-16 20:51:15 +0000463{
thughesdaa34562004-06-27 12:48:53 +0000464 vg_pthread_attr_t* vg_attr;
465 CONVERT(attr, attr, vg_attr);
466 vg_attr->__vg_stacksize = stacksize;
467 return 0;
sewardj0286dd52002-05-16 20:51:15 +0000468}
469
470
sewardj30671ff2002-04-21 00:13:57 +0000471/* This is completely bogus. */
472int pthread_attr_getschedparam(const pthread_attr_t *attr,
473 struct sched_param *param)
474{
sewardj436e0582002-04-26 14:31:40 +0000475 static int moans = N_MOANS;
476 if (moans-- > 0)
nethercoteaad8c192003-11-20 14:23:09 +0000477 kludged("pthread_attr_getschedparam", NULL);
sewardj3e909ce2002-06-03 13:27:15 +0000478# ifdef HAVE_SCHED_PRIORITY
sewardj72d58482002-04-24 02:20:20 +0000479 if (param) param->sched_priority = 0; /* who knows */
480# else
sewardj30671ff2002-04-21 00:13:57 +0000481 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000482# endif
sewardj30671ff2002-04-21 00:13:57 +0000483 return 0;
484}
485
486int pthread_attr_setschedparam(pthread_attr_t *attr,
487 const struct sched_param *param)
488{
sewardj436e0582002-04-26 14:31:40 +0000489 static int moans = N_MOANS;
490 if (moans-- > 0)
nethercoteaad8c192003-11-20 14:23:09 +0000491 ignored("pthread_attr_setschedparam", "(scheduling not changeable)");
sewardj30671ff2002-04-21 00:13:57 +0000492 return 0;
493}
494
495int pthread_attr_destroy(pthread_attr_t *attr)
496{
sewardj436e0582002-04-26 14:31:40 +0000497 static int moans = N_MOANS;
498 if (moans-- > 0)
nethercoteaad8c192003-11-20 14:23:09 +0000499 ignored("pthread_attr_destroy", NULL);
sewardj30671ff2002-04-21 00:13:57 +0000500 return 0;
501}
sewardjf8f819e2002-04-17 23:21:37 +0000502
sewardj0d844232002-06-02 09:29:31 +0000503/* These are no-ops, as with LinuxThreads. */
504int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
505{
506 ensure_valgrind("pthread_attr_setscope");
507 if (scope == PTHREAD_SCOPE_SYSTEM)
508 return 0;
sewardj4dced352002-06-04 22:54:20 +0000509 pthread_error("pthread_attr_setscope: "
510 "invalid or unsupported scope");
sewardj0d844232002-06-02 09:29:31 +0000511 if (scope == PTHREAD_SCOPE_PROCESS)
512 return ENOTSUP;
513 return EINVAL;
514}
515
516int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
517{
518 ensure_valgrind("pthread_attr_setscope");
519 if (scope)
520 *scope = PTHREAD_SCOPE_SYSTEM;
521 return 0;
522}
523
sewardj64039bb2002-06-03 00:58:18 +0000524
525/* Pretty bogus. Avoid if possible. */
526int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
527{
thughesdaa34562004-06-27 12:48:53 +0000528 StackInfo si;
529 int res;
sewardj64039bb2002-06-03 00:58:18 +0000530 int detached;
nethercote1f0173b2004-02-28 15:40:36 +0000531 vg_pthread_attr_t* vg_attr;
532 CONVERT(attr, attr, vg_attr);
533
sewardj64039bb2002-06-03 00:58:18 +0000534 ensure_valgrind("pthread_getattr_np");
nethercoteaad8c192003-11-20 14:23:09 +0000535 kludged("pthread_getattr_np", NULL);
nethercote1f0173b2004-02-28 15:40:36 +0000536 vg_attr->__vg_detachstate = PTHREAD_CREATE_JOINABLE;
537 vg_attr->__vg_schedpolicy = SCHED_OTHER;
538 vg_attr->__vg_schedparam.sched_priority = 0;
539 vg_attr->__vg_inheritsched = PTHREAD_EXPLICIT_SCHED;
540 vg_attr->__vg_scope = PTHREAD_SCOPE_SYSTEM;
thughesdaa34562004-06-27 12:48:53 +0000541 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
542 VG_USERREQ__GET_STACK_INFO,
543 thread, &si, 0, 0 );
544 vg_attr->__vg_guardsize = si.guardsize;
545 vg_attr->__vg_stackaddr = (void *)si.base;
nethercote1f0173b2004-02-28 15:40:36 +0000546 vg_attr->__vg_stackaddr_set = 0;
thughesdaa34562004-06-27 12:48:53 +0000547 vg_attr->__vg_stacksize = si.size;
sewardj64039bb2002-06-03 00:58:18 +0000548 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
549 VG_USERREQ__SET_OR_GET_DETACH,
550 2 /* get */, thread, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000551 my_assert(detached == 0 || detached == 1);
sewardj64039bb2002-06-03 00:58:18 +0000552 if (detached)
nethercote1f0173b2004-02-28 15:40:36 +0000553 vg_attr->__vg_detachstate = PTHREAD_CREATE_DETACHED;
sewardj64039bb2002-06-03 00:58:18 +0000554 return 0;
555}
556
557
thughesdaa34562004-06-27 12:48:53 +0000558WEAK
559int pthread_attr_getstack ( const pthread_attr_t * attr,
560 void ** stackaddr,
561 size_t *stacksize )
562{
563 vg_pthread_attr_t* vg_attr;
564 CONVERT(attr, attr, vg_attr);
565 ensure_valgrind("pthread_attr_getstack");
566 if (stackaddr)
567 *stackaddr = vg_attr->__vg_stackaddr;
568 if (stacksize)
569 *stacksize = vg_attr->__vg_stacksize;
570 return 0;
571}
572
sewardj11f0bb42003-04-26 20:11:15 +0000573WEAK
sewardj64039bb2002-06-03 00:58:18 +0000574int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
575 void ** stackaddr )
576{
thughesdaa34562004-06-27 12:48:53 +0000577 vg_pthread_attr_t* vg_attr;
578 CONVERT(attr, attr, vg_attr);
sewardj64039bb2002-06-03 00:58:18 +0000579 ensure_valgrind("pthread_attr_getstackaddr");
sewardj64039bb2002-06-03 00:58:18 +0000580 if (stackaddr)
thughesdaa34562004-06-27 12:48:53 +0000581 *stackaddr = vg_attr->__vg_stackaddr;
sewardj64039bb2002-06-03 00:58:18 +0000582 return 0;
583}
584
sewardj11f0bb42003-04-26 20:11:15 +0000585WEAK
thughesdaa34562004-06-27 12:48:53 +0000586int pthread_attr_getstacksize ( const pthread_attr_t * attr,
587 size_t * stacksize )
sewardj64039bb2002-06-03 00:58:18 +0000588{
thughesdaa34562004-06-27 12:48:53 +0000589 vg_pthread_attr_t* vg_attr;
590 CONVERT(attr, attr, vg_attr);
sewardj64039bb2002-06-03 00:58:18 +0000591 ensure_valgrind("pthread_attr_getstacksize");
thughesdaa34562004-06-27 12:48:53 +0000592 if (stacksize)
593 *stacksize = vg_attr->__vg_stacksize;
sewardj64039bb2002-06-03 00:58:18 +0000594 return 0;
595}
596
sewardja3be12f2002-06-17 12:19:44 +0000597int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
598{
nethercote1f0173b2004-02-28 15:40:36 +0000599 vg_pthread_attr_t* vg_attr;
600 CONVERT(attr, attr, vg_attr);
601 if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
602 return EINVAL;
603 vg_attr->__vg_schedpolicy = policy;
604 return 0;
sewardja3be12f2002-06-17 12:19:44 +0000605}
606
607int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
608{
nethercote1f0173b2004-02-28 15:40:36 +0000609 vg_pthread_attr_t* vg_attr;
610 CONVERT(attr, attr, vg_attr);
611 *policy = vg_attr->__vg_schedpolicy;
612 return 0;
sewardja3be12f2002-06-17 12:19:44 +0000613}
614
615
sewardj11f0bb42003-04-26 20:11:15 +0000616WEAK
sewardj111b14c2002-10-20 16:22:57 +0000617int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
618{
thughesdaa34562004-06-27 12:48:53 +0000619 vg_pthread_attr_t* vg_attr;
620 CONVERT(attr, attr, vg_attr);
621 vg_attr->__vg_guardsize = guardsize;
sewardj111b14c2002-10-20 16:22:57 +0000622 return 0;
623}
624
sewardj11f0bb42003-04-26 20:11:15 +0000625WEAK
sewardj111b14c2002-10-20 16:22:57 +0000626int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
627{
nethercote1f0173b2004-02-28 15:40:36 +0000628 vg_pthread_attr_t* vg_attr;
629 CONVERT(attr, attr, vg_attr);
630 *guardsize = vg_attr->__vg_guardsize;
sewardj111b14c2002-10-20 16:22:57 +0000631 return 0;
632}
633
sewardjab2e1232002-12-26 12:16:11 +0000634/* Again, like LinuxThreads. */
635
636static int concurrency_current_level = 0;
637
sewardj11f0bb42003-04-26 20:11:15 +0000638WEAK
sewardjb34e4db2002-12-08 23:51:32 +0000639int pthread_setconcurrency(int new_level)
640{
641 if (new_level < 0)
642 return EINVAL;
sewardjab2e1232002-12-26 12:16:11 +0000643 else {
644 concurrency_current_level = new_level;
sewardjb34e4db2002-12-08 23:51:32 +0000645 return 0;
sewardjab2e1232002-12-26 12:16:11 +0000646 }
sewardjb34e4db2002-12-08 23:51:32 +0000647}
648
sewardj11f0bb42003-04-26 20:11:15 +0000649WEAK
sewardjab2e1232002-12-26 12:16:11 +0000650int pthread_getconcurrency(void)
651{
652 return concurrency_current_level;
653}
654
655
sewardj20917d82002-05-28 01:36:45 +0000656/* All exiting threads eventually pass through here, bearing the
657 return value, or PTHREAD_CANCELED, in ret_val. */
658static
659__attribute__((noreturn))
660void thread_exit_wrapper ( void* ret_val )
661{
sewardj870497a2002-05-29 01:06:47 +0000662 int detached, res;
663 CleanupEntry cu;
664 pthread_key_t key;
sewardj00a66b12002-10-12 16:42:35 +0000665 void** specifics_ptr;
sewardj870497a2002-05-29 01:06:47 +0000666
sewardj870497a2002-05-29 01:06:47 +0000667 /* Run this thread's key finalizers. Really this should be run
668 PTHREAD_DESTRUCTOR_ITERATIONS times. */
669 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
670 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
671 VG_USERREQ__GET_KEY_D_AND_S,
672 key, &cu, 0, 0 );
673 if (res == 0) {
674 /* valid key */
thughes11975ff2004-06-12 12:58:22 +0000675 my_assert(cu.type == VgCt_Function);
676 if (cu.data.function.fn && cu.data.function.arg)
677 cu.data.function.fn /* destructor for key */
678 ( cu.data.function.arg /* specific for key for this thread */ );
sewardj870497a2002-05-29 01:06:47 +0000679 continue;
680 }
sewardj2d94c112002-06-03 01:25:54 +0000681 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000682 }
sewardj20917d82002-05-28 01:36:45 +0000683
sewardj00a66b12002-10-12 16:42:35 +0000684 /* Free up my specifics space, if any. */
685 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
686 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
687 pthread_self(), 0, 0, 0);
688 my_assert(specifics_ptr != (void**)3);
689 my_assert(specifics_ptr != (void**)1); /* 1 means invalid thread */
690 if (specifics_ptr != NULL)
691 my_free(specifics_ptr);
fitzhardinge47735af2004-01-21 01:27:27 +0000692
nethercote9b3c7652004-10-19 13:18:00 +0000693 VGA_(thread_exit)();
fitzhardinge47735af2004-01-21 01:27:27 +0000694
sewardj20917d82002-05-28 01:36:45 +0000695 /* Decide on my final disposition. */
696 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
697 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000698 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000699 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000700
701 if (detached) {
702 /* Detached; I just quit right now. */
703 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
704 VG_USERREQ__QUIT, 0, 0, 0, 0);
705 } else {
706 /* Not detached; so I wait for a joiner. */
707 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
708 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
709 }
710 /* NOTREACHED */
711 barf("thread_exit_wrapper: still alive?!");
712}
713
714
715/* This function is a wrapper function for running a thread. It runs
716 the root function specified in pthread_create, and then, should the
717 root function return a value, it arranges to run the thread's
718 cleanup handlers and exit correctly. */
719
sewardj728a5272002-06-20 10:25:37 +0000720/* Struct used to convey info from pthread_create to thread_wrapper.
721 Must be careful not to pass to the child thread any pointers to
722 objects which might be on the parent's stack. */
sewardj20917d82002-05-28 01:36:45 +0000723typedef
724 struct {
fitzhardinge47735af2004-01-21 01:27:27 +0000725 int attr__detachstate;
fitzhardinge47735af2004-01-21 01:27:27 +0000726 void* (*root_fn) ( void* );
727 void* arg;
fitzhardingef7866182004-03-16 22:09:12 +0000728 sigset_t sigmask;
nethercote9b3c7652004-10-19 13:18:00 +0000729 arch_thread_aux_t aux;
sewardj20917d82002-05-28 01:36:45 +0000730 }
731 NewThreadInfo;
732
fitzhardinge47735af2004-01-21 01:27:27 +0000733/* Struct used to describe a TDB header, copied from glibc. */
734typedef
735 struct {
736 void *tcb;
737 void *dtv;
738 void *self;
739 int multiple_threads;
740 unsigned long sysinfo;
741 }
742 tcbhead_t;
sewardj20917d82002-05-28 01:36:45 +0000743
744/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
745 not return. Note that this runs in the new thread, not the
746 parent. */
747static
748__attribute__((noreturn))
749void thread_wrapper ( NewThreadInfo* info )
750{
thughesebed9982004-06-12 17:25:25 +0000751 int attr__detachstate;
thughesebed9982004-06-12 17:25:25 +0000752 void* (*root_fn) ( void* );
753 void* arg;
754 void* ret_val;
755 __pthread_unwind_buf_t ub;
sewardj20917d82002-05-28 01:36:45 +0000756
sewardj728a5272002-06-20 10:25:37 +0000757 attr__detachstate = info->attr__detachstate;
758 root_fn = info->root_fn;
759 arg = info->arg;
sewardj20917d82002-05-28 01:36:45 +0000760
nethercote9b3c7652004-10-19 13:18:00 +0000761 VGA_(thread_wrapper)(&info->aux);
fitzhardinge47735af2004-01-21 01:27:27 +0000762
sewardj7989d0c2002-05-28 11:00:01 +0000763 /* Minimally observe the attributes supplied. */
sewardj728a5272002-06-20 10:25:37 +0000764 if (attr__detachstate != PTHREAD_CREATE_DETACHED
765 && attr__detachstate != PTHREAD_CREATE_JOINABLE)
766 pthread_error("thread_wrapper: invalid attr->__detachstate");
767 if (attr__detachstate == PTHREAD_CREATE_DETACHED)
768 pthread_detach(pthread_self());
sewardj7989d0c2002-05-28 11:00:01 +0000769
fitzhardinge47735af2004-01-21 01:27:27 +0000770 /* Initialise thread specific state */
771 init_thread_specific_state();
772
fitzhardingef7866182004-03-16 22:09:12 +0000773 /* Now that everything is set up, restore our signal mask (we're
774 ready to accept signals) */
775 sigprocmask(SIG_SETMASK, &info->sigmask, NULL);
776
777 /* Free up the arg block that pthread_create malloced. */
778 my_free(info);
779
thughes11975ff2004-06-12 12:58:22 +0000780
thughesebed9982004-06-12 17:25:25 +0000781 if (setjmp(ub.__cancel_jmp_buf[0].__cancel_jmp_buf) == 0) {
thughes11975ff2004-06-12 12:58:22 +0000782 CleanupEntry cu;
783 int res;
784
785 cu.type = VgCt_Longjmp;
786 cu.data.longjmp.ub = &ub;
787 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
788 VG_USERREQ__CLEANUP_PUSH,
789 &cu, 0, 0, 0);
790
791 /* The root function might not return. But if it does we simply
792 move along to thread_exit_wrapper. All other ways out for the
793 thread (cancellation, or calling pthread_exit) lead there
794 too. */
795 ret_val = root_fn(arg);
796 }
797 else {
798 ret_val = get_ret_val();
799 }
800
sewardj20917d82002-05-28 01:36:45 +0000801 thread_exit_wrapper(ret_val);
802 /* NOTREACHED */
803}
804
805
sewardjf8f819e2002-04-17 23:21:37 +0000806/* ---------------------------------------------------
thughes11975ff2004-06-12 12:58:22 +0000807 CLEANUP STACKS
808 ------------------------------------------------ */
809
810void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
811 void (*__routine) (void *),
812 void *__arg)
813{
814 int res;
815 CleanupEntry cu;
816 ensure_valgrind("_pthread_cleanup_push");
817 cu.type = VgCt_Function;
818 cu.data.function.fn = __routine;
819 cu.data.function.arg = __arg;
820 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
821 VG_USERREQ__CLEANUP_PUSH,
822 &cu, 0, 0, 0);
823 my_assert(res == 0);
824}
825
826
827void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
828 void (*__routine) (void *),
829 void *__arg)
830{
831 /* As _pthread_cleanup_push, but first save the thread's original
832 cancellation type in __buffer and set it to Deferred. */
833 int orig_ctype;
834 ensure_valgrind("_pthread_cleanup_push_defer");
835 /* Set to Deferred, and put the old cancellation type in res. */
836 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
837 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
838 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
839 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
840 VG_USERREQ__SET_CANCELTYPE,
841 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
842 my_assert(orig_ctype != -1);
843 *((int*)(__buffer)) = orig_ctype;
844 /* Now push the cleanup. */
845 _pthread_cleanup_push(NULL, __routine, __arg);
846}
847
848
849void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
850 int __execute)
851{
852 int res;
853 CleanupEntry cu;
854 ensure_valgrind("_pthread_cleanup_push");
855 cu.type = VgCt_None; /* paranoia */
856 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
857 VG_USERREQ__CLEANUP_POP,
858 &cu, 0, 0, 0);
859 my_assert(cu.type == VgCt_Function);
860 if (res == 0) {
861 /* pop succeeded */
862 if (__execute) {
863 cu.data.function.fn ( cu.data.function.arg );
864 }
865 return;
866 }
867 if (res == -1) {
868 /* stack underflow */
869 return;
870 }
871 barf("_pthread_cleanup_pop");
872}
873
874
875void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
876 int __execute)
877{
878 int orig_ctype, fake_ctype;
879 /* As _pthread_cleanup_pop, but after popping/running the handler,
880 restore the thread's original cancellation type from the first
881 word of __buffer. */
882 _pthread_cleanup_pop(NULL, __execute);
883 orig_ctype = *((int*)(__buffer));
884 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
885 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
886 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
887 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
888 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
889 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
890 VG_USERREQ__SET_CANCELTYPE,
891 orig_ctype, 0, 0, 0);
892 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
893}
894
895
nethercoteeec46302004-08-23 15:06:23 +0000896REGPARM(1)
thughesebed9982004-06-12 17:25:25 +0000897void __pthread_register_cancel (__pthread_unwind_buf_t *__buf)
thughes11975ff2004-06-12 12:58:22 +0000898{
899 int res;
900 CleanupEntry cu;
901 ensure_valgrind("__pthread_register_cancel");
902 cu.type = VgCt_Longjmp;
thughesebed9982004-06-12 17:25:25 +0000903 cu.data.longjmp.ub = __buf;
thughes11975ff2004-06-12 12:58:22 +0000904 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
905 VG_USERREQ__CLEANUP_PUSH,
906 &cu, 0, 0, 0);
907 my_assert(res == 0);
908}
909
910
nethercoteeec46302004-08-23 15:06:23 +0000911REGPARM(1)
thughesebed9982004-06-12 17:25:25 +0000912void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf)
thughes11975ff2004-06-12 12:58:22 +0000913{
914 /* As __pthread_register cancel, but save the thread's original
915 cancellation type and set it to Deferred. */
916 int res;
917 CleanupEntry cu;
918 ensure_valgrind("__pthread_register_cancel_defer");
919 cu.type = VgCt_Longjmp;
thughesebed9982004-06-12 17:25:25 +0000920 cu.data.longjmp.ub = __buf;
thughes11975ff2004-06-12 12:58:22 +0000921 /* Set to Deferred, and save the old cancellation type. */
922 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
923 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
924 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
925 VALGRIND_MAGIC_SEQUENCE(cu.data.longjmp.ctype, (-1) /* default */,
926 VG_USERREQ__SET_CANCELTYPE,
927 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
928 my_assert(cu.data.longjmp.ctype != -1);
929 /* Now push the cleanup. */
930 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
931 VG_USERREQ__CLEANUP_PUSH,
932 &cu, 0, 0, 0);
933 my_assert(res == 0);
934}
935
936
nethercoteeec46302004-08-23 15:06:23 +0000937REGPARM(1)
thughesebed9982004-06-12 17:25:25 +0000938void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf)
thughes11975ff2004-06-12 12:58:22 +0000939{
940 int res;
941 CleanupEntry cu;
942 ensure_valgrind("__pthread_unregister_cancel");
943 cu.type = VgCt_None; /* paranoia */
944 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
945 VG_USERREQ__CLEANUP_POP,
946 &cu, 0, 0, 0);
947 my_assert(cu.type == VgCt_Longjmp);
thughesebed9982004-06-12 17:25:25 +0000948 my_assert(cu.data.longjmp.ub == __buf);
thughes11975ff2004-06-12 12:58:22 +0000949 return;
950}
951
952
nethercoteeec46302004-08-23 15:06:23 +0000953REGPARM(1)
thughesebed9982004-06-12 17:25:25 +0000954void __pthread_unregister_restore (__pthread_unwind_buf_t *__buf)
thughes11975ff2004-06-12 12:58:22 +0000955{
956 int res;
957 CleanupEntry cu;
958 int fake_ctype;
959 /* As __pthread_unregister_cancel, but after popping/running the
960 handler, restore the thread's original cancellation type. */
961 ensure_valgrind("__pthread_unregister_cancel_restore");
962 cu.type = VgCt_None; /* paranoia */
963 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
964 VG_USERREQ__CLEANUP_POP,
965 &cu, 0, 0, 0);
966 my_assert(cu.type == VgCt_Longjmp);
thughesebed9982004-06-12 17:25:25 +0000967 my_assert(cu.data.longjmp.ub == __buf);
thughes11975ff2004-06-12 12:58:22 +0000968 /* Restore the original cancellation type. */
969 my_assert(cu.data.longjmp.ctype == PTHREAD_CANCEL_DEFERRED
970 || cu.data.longjmp.ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
971 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
972 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
973 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
974 VG_USERREQ__SET_CANCELTYPE,
975 cu.data.longjmp.ctype, 0, 0, 0);
976 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
977 return;
978}
979
nethercoteeec46302004-08-23 15:06:23 +0000980REGPARM(1)
thughes11975ff2004-06-12 12:58:22 +0000981__attribute ((__noreturn__))
thughesebed9982004-06-12 17:25:25 +0000982void __pthread_unwind (__pthread_unwind_buf_t *__buf)
thughes11975ff2004-06-12 12:58:22 +0000983{
984 int res;
985 CleanupEntry cu;
986 while (1) {
987 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
988 VG_USERREQ__CLEANUP_POP,
989 &cu, 0, 0, 0);
990 my_assert(res == 0);
991 if (cu.type == VgCt_Longjmp) break;
992 if (0) printf("running cleanup handler");
993 my_assert(cu.type == VgCt_Function);
994 cu.data.function.fn ( cu.data.function.arg );
995 }
996 my_assert(cu.type == VgCt_Longjmp);
thughesebed9982004-06-12 17:25:25 +0000997 my_assert(__buf == NULL || __buf == cu.data.longjmp.ub);
998 __buf = cu.data.longjmp.ub;
999 longjmp(__buf->__cancel_jmp_buf[0].__cancel_jmp_buf, 1);
thughes11975ff2004-06-12 12:58:22 +00001000 /* NOTREACHED */
1001}
1002
1003
nethercoteeec46302004-08-23 15:06:23 +00001004REGPARM(1)
thughes11975ff2004-06-12 12:58:22 +00001005__attribute ((__noreturn__))
thughesebed9982004-06-12 17:25:25 +00001006void __pthread_unwind_next (__pthread_unwind_buf_t *__buf)
thughes11975ff2004-06-12 12:58:22 +00001007{
1008 __pthread_unwind(NULL);
1009 /* NOTREACHED */
1010}
1011
1012
1013/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001014 THREADs
1015 ------------------------------------------------ */
1016
sewardjc91a4ff2003-07-11 00:12:58 +00001017static void __valgrind_pthread_yield ( void )
sewardjff42d1d2002-05-22 13:17:31 +00001018{
1019 int res;
1020 ensure_valgrind("pthread_yield");
1021 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1022 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
sewardjc91a4ff2003-07-11 00:12:58 +00001023}
1024
1025WEAK
1026int pthread_yield ( void )
1027{
1028 __valgrind_pthread_yield();
sewardjff42d1d2002-05-22 13:17:31 +00001029 return 0;
1030}
1031
1032
sewardj6072c362002-04-19 14:40:57 +00001033int pthread_equal(pthread_t thread1, pthread_t thread2)
1034{
1035 return thread1 == thread2 ? 1 : 0;
1036}
1037
1038
sewardj20917d82002-05-28 01:36:45 +00001039/* Bundle up the args into a malloc'd block and create a new thread
1040 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +00001041int
sewardj1462c8b2002-07-24 09:41:52 +00001042pthread_create (pthread_t *__restrict __thredd,
sewardje663cb92002-04-12 10:26:32 +00001043 __const pthread_attr_t *__restrict __attr,
1044 void *(*__start_routine) (void *),
1045 void *__restrict __arg)
1046{
sewardj20917d82002-05-28 01:36:45 +00001047 int tid_child;
1048 NewThreadInfo* info;
thughesdaa34562004-06-27 12:48:53 +00001049 StackInfo si;
nethercote1f0173b2004-02-28 15:40:36 +00001050 vg_pthread_attr_t* __vg_attr;
1051 CONVERT(attr, __attr, __vg_attr);
sewardje663cb92002-04-12 10:26:32 +00001052
sewardj20917d82002-05-28 01:36:45 +00001053 ensure_valgrind("pthread_create");
1054
thughes5298da92004-03-07 19:36:14 +00001055 /* make sure the tsd keys, and hence locale info, for the root
1056 thread are initialised before we get into complications making
1057 new threads. */
1058 init_global_thread_specific_state();
sewardj00a66b12002-10-12 16:42:35 +00001059
sewardj20917d82002-05-28 01:36:45 +00001060 /* Allocate space for the arg block. thread_wrapper will free
1061 it. */
sewardj00a66b12002-10-12 16:42:35 +00001062 info = my_malloc(sizeof(NewThreadInfo));
sewardj2d94c112002-06-03 01:25:54 +00001063 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +00001064
nethercote1f0173b2004-02-28 15:40:36 +00001065 if (__vg_attr)
1066 info->attr__detachstate = __vg_attr->__vg_detachstate;
sewardj728a5272002-06-20 10:25:37 +00001067 else
1068 info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
1069
nethercote9b3c7652004-10-19 13:18:00 +00001070 VGA_(thread_create)(&info->aux);
fitzhardinge47735af2004-01-21 01:27:27 +00001071
sewardj20917d82002-05-28 01:36:45 +00001072 info->root_fn = __start_routine;
1073 info->arg = __arg;
fitzhardingef7866182004-03-16 22:09:12 +00001074 sigprocmask(SIG_SETMASK, NULL, &info->sigmask);
1075
thughes5d975072004-10-29 18:22:38 +00001076 if (__attr) {
thughesdaa34562004-06-27 12:48:53 +00001077 si.base = (Addr)__vg_attr->__vg_stackaddr;
1078 si.size = __vg_attr->__vg_stacksize;
1079 si.guardsize = __vg_attr->__vg_guardsize;
1080 } else {
1081 si.base = (Addr)NULL;
1082 si.size = VG_PTHREAD_STACK_SIZE;
nethercote73b526f2004-10-31 18:48:21 +00001083 si.guardsize = VKI_PAGE_SIZE;
thughesdaa34562004-06-27 12:48:53 +00001084 }
1085
sewardj20917d82002-05-28 01:36:45 +00001086 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
1087 VG_USERREQ__APPLY_IN_NEW_THREAD,
thughesdaa34562004-06-27 12:48:53 +00001088 &thread_wrapper, info, &si, 0);
sewardj2d94c112002-06-03 01:25:54 +00001089 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +00001090
sewardj1462c8b2002-07-24 09:41:52 +00001091 if (__thredd)
1092 *__thredd = tid_child;
fitzhardingef7866182004-03-16 22:09:12 +00001093
sewardj20917d82002-05-28 01:36:45 +00001094 return 0; /* success */
1095}
sewardje663cb92002-04-12 10:26:32 +00001096
1097
1098int
1099pthread_join (pthread_t __th, void **__thread_return)
1100{
1101 int res;
1102 ensure_valgrind("pthread_join");
1103 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1104 VG_USERREQ__PTHREAD_JOIN,
1105 __th, __thread_return, 0, 0);
1106 return res;
1107}
1108
1109
sewardj3b5d8862002-04-20 13:53:23 +00001110void pthread_exit(void *retval)
1111{
sewardj3b5d8862002-04-20 13:53:23 +00001112 ensure_valgrind("pthread_exit");
thughes11975ff2004-06-12 12:58:22 +00001113 set_ret_val(retval);
1114 __pthread_unwind(NULL);
sewardj3b5d8862002-04-20 13:53:23 +00001115}
1116
sewardje663cb92002-04-12 10:26:32 +00001117
sewardj853f55d2002-04-26 00:27:53 +00001118int pthread_detach(pthread_t th)
1119{
sewardj20917d82002-05-28 01:36:45 +00001120 int res;
1121 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +00001122 /* First we enquire as to the current detach state. */
1123 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +00001124 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +00001125 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +00001126 if (res == -1) {
1127 /* not found */
1128 pthread_error("pthread_detach: "
1129 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +00001130 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +00001131 }
1132 if (res == 1) {
1133 /* already detached */
1134 pthread_error("pthread_detach: "
1135 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +00001136 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001137 }
sewardj7989d0c2002-05-28 11:00:01 +00001138 if (res == 0) {
1139 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
1140 VG_USERREQ__SET_OR_GET_DETACH,
1141 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001142 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +00001143 return 0;
1144 }
1145 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +00001146}
1147
1148
sewardjf8f819e2002-04-17 23:21:37 +00001149/* ---------------------------------------------------
1150 MUTEX ATTRIBUTES
1151 ------------------------------------------------ */
1152
sewardj5905fae2002-04-26 13:25:00 +00001153int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +00001154{
nethercote1f0173b2004-02-28 15:40:36 +00001155 vg_pthread_mutexattr_t* vg_attr;
1156 CONVERT(mutexattr, attr, vg_attr);
1157 vg_attr->__vg_mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +00001158 return 0;
sewardje663cb92002-04-12 10:26:32 +00001159}
1160
sewardj5905fae2002-04-26 13:25:00 +00001161int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +00001162{
nethercote1f0173b2004-02-28 15:40:36 +00001163 vg_pthread_mutexattr_t* vg_attr;
1164 CONVERT(mutexattr, attr, vg_attr);
1165
sewardjf8f819e2002-04-17 23:21:37 +00001166 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +00001167# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +00001168 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +00001169 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +00001170# endif
sewardja1679dd2002-05-10 22:31:40 +00001171# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +00001172 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +00001173# endif
sewardjf8f819e2002-04-17 23:21:37 +00001174 case PTHREAD_MUTEX_RECURSIVE_NP:
1175 case PTHREAD_MUTEX_ERRORCHECK_NP:
nethercote1f0173b2004-02-28 15:40:36 +00001176 vg_attr->__vg_mutexkind = type;
sewardjf8f819e2002-04-17 23:21:37 +00001177 return 0;
1178 default:
sewardj4dced352002-06-04 22:54:20 +00001179 pthread_error("pthread_mutexattr_settype: "
1180 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +00001181 return EINVAL;
1182 }
1183}
1184
thughescca97252004-10-13 18:29:54 +00001185int __pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
1186{
1187 vg_pthread_mutexattr_t* vg_attr;
1188 CONVERT(mutexattr, attr, vg_attr);
1189
1190 *type = vg_attr->__vg_mutexkind;
1191
1192 return 0;
1193}
1194
sewardj5905fae2002-04-26 13:25:00 +00001195int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +00001196{
1197 return 0;
1198}
1199
sewardjf0995512003-07-06 01:29:49 +00001200int __pthread_mutexattr_setpshared ( pthread_mutexattr_t* attr, int pshared)
sewardj7685cae2003-07-06 01:23:11 +00001201{
1202 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
1203 return EINVAL;
1204
1205 /* For now it is not possible to shared a conditional variable. */
1206 if (pshared != PTHREAD_PROCESS_PRIVATE)
1207 return ENOSYS;
1208
1209 return 0;
1210}
1211
sewardjf8f819e2002-04-17 23:21:37 +00001212
1213/* ---------------------------------------------------
1214 MUTEXes
1215 ------------------------------------------------ */
1216
sewardj5905fae2002-04-26 13:25:00 +00001217int __pthread_mutex_init(pthread_mutex_t *mutex,
1218 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +00001219{
nethercote1f0173b2004-02-28 15:40:36 +00001220 vg_pthread_mutex_t* vg_mutex;
1221 vg_pthread_mutexattr_t* vg_mutexattr;
1222 CONVERT(mutex, mutex, vg_mutex);
1223 CONVERT(mutexattr, mutexattr, vg_mutexattr);
1224
1225 vg_mutex->__vg_m_count = 0;
1226 vg_mutex->__vg_m_owner = (/*_pthread_descr*/void*)VG_INVALID_THREADID;
1227 vg_mutex->__vg_m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
1228 if (vg_mutexattr)
1229 vg_mutex->__vg_m_kind = vg_mutexattr->__vg_mutexkind;
sewardj604ec3c2002-04-18 22:38:41 +00001230 return 0;
sewardje663cb92002-04-12 10:26:32 +00001231}
1232
sewardj439d45e2002-05-03 20:43:10 +00001233
sewardj5905fae2002-04-26 13:25:00 +00001234int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +00001235{
1236 int res;
nethercote1f0173b2004-02-28 15:40:36 +00001237 vg_pthread_mutex_t* vg_mutex;
1238 CONVERT(mutex, mutex, vg_mutex);
1239
nethercote6618e632004-04-10 00:54:42 +00001240 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1241 VG_USERREQ__PTHREAD_MUTEX_LOCK,
1242 vg_mutex, 0, 0, 0);
1243 return res;
sewardje663cb92002-04-12 10:26:32 +00001244}
1245
sewardj439d45e2002-05-03 20:43:10 +00001246
thughese321d492004-10-17 15:00:20 +00001247int __pthread_mutex_timedlock(pthread_mutex_t *mutex,
1248 const struct timespec *abstime )
1249{
1250 int res;
1251 unsigned int ms_now, ms_end;
1252 struct timeval timeval_now;
1253 unsigned long long int ull_ms_now_after_1970;
1254 unsigned long long int ull_ms_end_after_1970;
thughese761bef2004-10-17 15:18:22 +00001255 unsigned long long int ull_ms_now;
1256 unsigned long long int ull_ms_end;
thughese321d492004-10-17 15:00:20 +00001257 vg_pthread_mutex_t* vg_mutex;
1258 CONVERT(mutex, mutex, vg_mutex);
1259
1260 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1261 VG_USERREQ__READ_MILLISECOND_TIMER,
1262 0, 0, 0, 0);
1263 my_assert(ms_now != 0xFFFFFFFF);
1264 res = gettimeofday(&timeval_now, NULL);
1265 my_assert(res == 0);
1266
1267 ull_ms_now_after_1970
1268 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
1269 + ((unsigned long long int)(timeval_now.tv_usec / 1000));
1270 ull_ms_end_after_1970
1271 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
1272 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
1273 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
1274 ull_ms_end_after_1970 = ull_ms_now_after_1970;
thughes39569e12004-10-18 12:11:23 +00001275 ull_ms_now = ((unsigned long long int)(ms_now));
1276 ull_ms_end = ull_ms_now + (ull_ms_end_after_1970 - ull_ms_now_after_1970);
thughese761bef2004-10-17 15:18:22 +00001277 if (ull_ms_end >= (unsigned long long int)(0xFFFFFFFFUL)) {
1278 /* use 0xFFFFFFFEUL because 0xFFFFFFFFUL is reserved for no timeout
1279 (the fine difference between a long wait and a possible abort
1280 due to a detected deadlock).
1281 */
1282 ms_end = 0xFFFFFFFEUL;
1283 } else {
1284 ms_end = (unsigned int)(ull_ms_end);
1285 }
thughese321d492004-10-17 15:00:20 +00001286 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1287 VG_USERREQ__PTHREAD_MUTEX_TIMEDLOCK,
1288 vg_mutex, ms_end, 0, 0);
1289 return res;
1290}
1291
1292
sewardj5905fae2002-04-26 13:25:00 +00001293int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +00001294{
1295 int res;
nethercote1f0173b2004-02-28 15:40:36 +00001296 vg_pthread_mutex_t* vg_mutex;
1297 CONVERT(mutex, mutex, vg_mutex);
1298
nethercote6618e632004-04-10 00:54:42 +00001299 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1300 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
1301 vg_mutex, 0, 0, 0);
1302 return res;
sewardj30671ff2002-04-21 00:13:57 +00001303}
1304
sewardj439d45e2002-05-03 20:43:10 +00001305
sewardj5905fae2002-04-26 13:25:00 +00001306int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +00001307{
1308 int res;
nethercote1f0173b2004-02-28 15:40:36 +00001309 vg_pthread_mutex_t* vg_mutex;
1310 CONVERT(mutex, mutex, vg_mutex);
1311
nethercote6618e632004-04-10 00:54:42 +00001312 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1313 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
1314 vg_mutex, 0, 0, 0);
1315 return res;
sewardje663cb92002-04-12 10:26:32 +00001316}
1317
sewardj439d45e2002-05-03 20:43:10 +00001318
sewardj5905fae2002-04-26 13:25:00 +00001319int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +00001320{
nethercote1f0173b2004-02-28 15:40:36 +00001321 vg_pthread_mutex_t* vg_mutex;
1322 CONVERT(mutex, mutex, vg_mutex);
1323
sewardj604ec3c2002-04-18 22:38:41 +00001324 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
1325 need to involve it. */
nethercote1f0173b2004-02-28 15:40:36 +00001326 if (vg_mutex->__vg_m_count > 0) {
sewardjd8acdf22002-11-13 21:57:52 +00001327 /* Oh, the horror. glibc's internal use of pthreads "knows"
1328 that destroying a lock does an implicit unlock. Make it
1329 explicit. */
nethercote1f0173b2004-02-28 15:40:36 +00001330 __pthread_mutex_unlock( (pthread_mutex_t*)vg_mutex );
1331 pthread_error("pthread_mutex_destroy: mutex is still in use");
sewardjd8acdf22002-11-13 21:57:52 +00001332 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +00001333 }
nethercote1f0173b2004-02-28 15:40:36 +00001334 vg_mutex->__vg_m_count = 0;
1335 vg_mutex->__vg_m_owner = (/*_pthread_descr*/void*)VG_INVALID_THREADID;
1336 vg_mutex->__vg_m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj4dced352002-06-04 22:54:20 +00001337 return 0;
sewardje663cb92002-04-12 10:26:32 +00001338}
1339
1340
sewardjf8f819e2002-04-17 23:21:37 +00001341/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +00001342 CONDITION VARIABLES
1343 ------------------------------------------------ */
1344
1345/* LinuxThreads supports no attributes for conditions. Hence ... */
1346
1347int pthread_condattr_init(pthread_condattr_t *attr)
1348{
thughes5d975072004-10-29 18:22:38 +00001349 vg_pthread_condattr_t* vg_attr;
1350 CONVERT(condattr, attr, vg_attr);
1351
1352 vg_attr->__vg_pshared = 0;
sewardj6072c362002-04-19 14:40:57 +00001353 return 0;
1354}
1355
sewardj0738a592002-04-20 13:59:33 +00001356int pthread_condattr_destroy(pthread_condattr_t *attr)
1357{
1358 return 0;
1359}
thughes5d975072004-10-29 18:22:38 +00001360
1361int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
1362{
1363 static int moans = N_MOANS;
1364 vg_pthread_condattr_t* vg_attr;
1365 CONVERT(condattr, attr, vg_attr);
1366
1367 if (pshared != PTHREAD_PROCESS_PRIVATE &&
1368 pshared != PTHREAD_PROCESS_SHARED)
1369 return EINVAL;
1370
1371 if (pshared == PTHREAD_PROCESS_SHARED && moans-- > 0)
1372 kludged("pthread_setschedparam", "(process shared condition variables not supported)");
1373
1374 vg_attr->__vg_pshared = pshared;
1375 return 0;
1376}
1377
1378int pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared)
1379{
1380 vg_pthread_condattr_t* vg_attr;
1381 CONVERT(condattr, attr, vg_attr);
1382
1383 *pshared = vg_attr->__vg_pshared;
1384 return 0;
1385}
sewardj6072c362002-04-19 14:40:57 +00001386
1387int pthread_cond_init( pthread_cond_t *cond,
fitzhardinge98abfc72003-12-16 02:05:15 +00001388 const pthread_condattr_t *cond_attr)
sewardj6072c362002-04-19 14:40:57 +00001389{
nethercote1f0173b2004-02-28 15:40:36 +00001390 vg_pthread_cond_t* vg_cond;
1391 CONVERT(cond, cond, vg_cond);
1392 vg_cond->__vg_c_waiting = (/*_pthread_descr*/void*)VG_INVALID_THREADID;
sewardj6072c362002-04-19 14:40:57 +00001393 return 0;
1394}
1395
sewardjf854f472002-04-21 12:19:41 +00001396int pthread_cond_destroy(pthread_cond_t *cond)
1397{
1398 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +00001399 static int moans = N_MOANS;
1400 if (moans-- > 0)
nethercoteaad8c192003-11-20 14:23:09 +00001401 kludged("pthread_cond_destroy",
1402 "(it doesn't check if the cond is waited on)" );
sewardjf854f472002-04-21 12:19:41 +00001403 return 0;
1404}
sewardj6072c362002-04-19 14:40:57 +00001405
1406/* ---------------------------------------------------
1407 SCHEDULING
1408 ------------------------------------------------ */
1409
1410/* This is completely bogus. */
1411int pthread_getschedparam(pthread_t target_thread,
1412 int *policy,
1413 struct sched_param *param)
1414{
sewardj436e0582002-04-26 14:31:40 +00001415 static int moans = N_MOANS;
1416 if (moans-- > 0)
nethercoteaad8c192003-11-20 14:23:09 +00001417 kludged("pthread_getschedparam", NULL);
sewardj6072c362002-04-19 14:40:57 +00001418 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +00001419# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +00001420 if (param) param->sched_priority = 0; /* who knows */
1421# else
sewardj6072c362002-04-19 14:40:57 +00001422 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +00001423# endif
sewardj6072c362002-04-19 14:40:57 +00001424 return 0;
1425}
1426
1427int pthread_setschedparam(pthread_t target_thread,
1428 int policy,
1429 const struct sched_param *param)
1430{
sewardj436e0582002-04-26 14:31:40 +00001431 static int moans = N_MOANS;
1432 if (moans-- > 0)
nethercoteaad8c192003-11-20 14:23:09 +00001433 ignored("pthread_setschedparam", "(scheduling not changeable)");
sewardj6072c362002-04-19 14:40:57 +00001434 return 0;
1435}
1436
sewardj3b5d8862002-04-20 13:53:23 +00001437int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
1438{
1439 int res;
nethercote1f0173b2004-02-28 15:40:36 +00001440 vg_pthread_mutex_t* vg_mutex;
1441 CONVERT(mutex, mutex, vg_mutex);
1442
sewardj3b5d8862002-04-20 13:53:23 +00001443 ensure_valgrind("pthread_cond_wait");
1444 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1445 VG_USERREQ__PTHREAD_COND_WAIT,
nethercote1f0173b2004-02-28 15:40:36 +00001446 cond, vg_mutex, 0, 0);
sewardj3b5d8862002-04-20 13:53:23 +00001447 return res;
1448}
1449
sewardj5f07b662002-04-23 16:52:51 +00001450int pthread_cond_timedwait ( pthread_cond_t *cond,
1451 pthread_mutex_t *mutex,
1452 const struct timespec *abstime )
1453{
1454 int res;
1455 unsigned int ms_now, ms_end;
1456 struct timeval timeval_now;
1457 unsigned long long int ull_ms_now_after_1970;
1458 unsigned long long int ull_ms_end_after_1970;
thughese761bef2004-10-17 15:18:22 +00001459 unsigned long long int ull_ms_now;
1460 unsigned long long int ull_ms_end;
nethercote1f0173b2004-02-28 15:40:36 +00001461 vg_pthread_mutex_t* vg_mutex;
1462 CONVERT(mutex, mutex, vg_mutex);
sewardj5f07b662002-04-23 16:52:51 +00001463
1464 ensure_valgrind("pthread_cond_timedwait");
1465 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1466 VG_USERREQ__READ_MILLISECOND_TIMER,
1467 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001468 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001469 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +00001470 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001471
1472 ull_ms_now_after_1970
1473 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
thughesb1a111b2004-09-27 18:55:55 +00001474 + ((unsigned long long int)(timeval_now.tv_usec / 1000));
sewardj5f07b662002-04-23 16:52:51 +00001475 ull_ms_end_after_1970
1476 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
1477 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +00001478 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
1479 ull_ms_end_after_1970 = ull_ms_now_after_1970;
thughese761bef2004-10-17 15:18:22 +00001480 ull_ms_now = ((unsigned long long int)(ms_now));
1481 ull_ms_end = ull_ms_now + (ull_ms_end_after_1970 - ull_ms_now_after_1970);
1482 if (ull_ms_end >= (unsigned long long int)(0xFFFFFFFFUL)) {
1483 /* use 0xFFFFFFFEUL because 0xFFFFFFFFUL is reserved for no timeout
1484 (the fine difference between a long wait and a possible abort
1485 due to a detected deadlock).
1486 */
1487 ms_end = 0xFFFFFFFEUL;
1488 } else {
1489 ms_end = (unsigned int)(ull_ms_end);
1490 }
sewardj5f07b662002-04-23 16:52:51 +00001491 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1492 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
nethercote1f0173b2004-02-28 15:40:36 +00001493 cond, vg_mutex, ms_end, 0);
sewardj5f07b662002-04-23 16:52:51 +00001494 return res;
1495}
1496
1497
sewardj3b5d8862002-04-20 13:53:23 +00001498int pthread_cond_signal(pthread_cond_t *cond)
1499{
1500 int res;
1501 ensure_valgrind("pthread_cond_signal");
1502 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1503 VG_USERREQ__PTHREAD_COND_SIGNAL,
1504 cond, 0, 0, 0);
1505 return res;
1506}
1507
1508int pthread_cond_broadcast(pthread_cond_t *cond)
1509{
1510 int res;
1511 ensure_valgrind("pthread_cond_broadcast");
1512 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1513 VG_USERREQ__PTHREAD_COND_BROADCAST,
1514 cond, 0, 0, 0);
1515 return res;
1516}
1517
sewardj6072c362002-04-19 14:40:57 +00001518
1519/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001520 CANCELLATION
1521 ------------------------------------------------ */
1522
sewardj853f55d2002-04-26 00:27:53 +00001523int pthread_setcancelstate(int state, int *oldstate)
1524{
sewardj20917d82002-05-28 01:36:45 +00001525 int res;
1526 ensure_valgrind("pthread_setcancelstate");
1527 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +00001528 && state != PTHREAD_CANCEL_DISABLE) {
1529 pthread_error("pthread_setcancelstate: "
1530 "invalid state");
sewardj20917d82002-05-28 01:36:45 +00001531 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001532 }
sewardj2d94c112002-06-03 01:25:54 +00001533 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1534 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001535 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1536 VG_USERREQ__SET_CANCELSTATE,
1537 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001538 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001539 if (oldstate)
1540 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001541 return 0;
1542}
1543
sewardje663cb92002-04-12 10:26:32 +00001544int pthread_setcanceltype(int type, int *oldtype)
1545{
sewardj20917d82002-05-28 01:36:45 +00001546 int res;
1547 ensure_valgrind("pthread_setcanceltype");
1548 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001549 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1550 pthread_error("pthread_setcanceltype: "
1551 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001552 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001553 }
sewardj2d94c112002-06-03 01:25:54 +00001554 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1555 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001556 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1557 VG_USERREQ__SET_CANCELTYPE,
1558 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001559 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001560 if (oldtype)
1561 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001562 return 0;
1563}
1564
sewardje663cb92002-04-12 10:26:32 +00001565int pthread_cancel(pthread_t thread)
1566{
1567 int res;
1568 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001569 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1570 VG_USERREQ__SET_CANCELPEND,
thughes11975ff2004-06-12 12:58:22 +00001571 thread, &pthread_exit, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001572 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001573 return res;
1574}
1575
jsgf855d93d2003-10-13 22:26:55 +00001576static
sewardjd140e442002-05-29 01:21:19 +00001577void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001578{
sewardj20917d82002-05-28 01:36:45 +00001579 int res;
njn25e49d8e72002-09-23 09:36:25 +00001580 ensure_valgrind("__my_pthread_testcancel");
sewardj20917d82002-05-28 01:36:45 +00001581 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1582 VG_USERREQ__TESTCANCEL,
1583 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001584 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001585}
1586
sewardjd140e442002-05-29 01:21:19 +00001587void pthread_testcancel ( void )
1588{
1589 __my_pthread_testcancel();
1590}
1591
sewardj20917d82002-05-28 01:36:45 +00001592
sewardjef037c72002-05-30 00:40:03 +00001593/* Not really sure what this is for. I suspect for doing the POSIX
1594 requirements for fork() and exec(). We do this internally anyway
1595 whenever those syscalls are observed, so this could be superfluous,
1596 but hey ...
1597*/
sewardj853f55d2002-04-26 00:27:53 +00001598void __pthread_kill_other_threads_np ( void )
1599{
sewardjef037c72002-05-30 00:40:03 +00001600 int res;
1601 ensure_valgrind("__pthread_kill_other_threads_np");
1602 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1603 VG_USERREQ__NUKE_OTHER_THREADS,
1604 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001605 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001606}
1607
sewardje663cb92002-04-12 10:26:32 +00001608
sewardjf8f819e2002-04-17 23:21:37 +00001609/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001610 SIGNALS
1611 ------------------------------------------------ */
1612
1613#include <signal.h>
1614
1615int pthread_sigmask(int how, const sigset_t *newmask,
1616 sigset_t *oldmask)
1617{
1618 int res;
1619
1620 /* A bit subtle, because the scheduler expects newmask and oldmask
1621 to be vki_sigset_t* rather than sigset_t*, and the two are
1622 different. Fortunately the first 64 bits of a sigset_t are
1623 exactly a vki_sigset_t, so we just pass the pointers through
1624 unmodified. Haaaack!
1625
1626 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001627 constants to VKI_ constants, so that the former do not have to
1628 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001629
1630 ensure_valgrind("pthread_sigmask");
1631
1632 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001633 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1634 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1635 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001636 default: pthread_error("pthread_sigmask: invalid how");
1637 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001638 }
1639
sewardjb48e5002002-05-13 00:16:03 +00001640 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1641 VG_USERREQ__PTHREAD_SIGMASK,
1642 how, newmask, oldmask, 0);
1643
1644 /* The scheduler tells us of any memory violations. */
1645 return res == 0 ? 0 : EFAULT;
1646}
1647
sewardjb48e5002002-05-13 00:16:03 +00001648int sigwait ( const sigset_t* set, int* sig )
1649{
1650 int res;
fitzhardinge98abfc72003-12-16 02:05:15 +00001651 siginfo_t si;
jsgf855d93d2003-10-13 22:26:55 +00001652
1653 __my_pthread_testcancel();
1654
jsgf855d93d2003-10-13 22:26:55 +00001655 si.si_signo = 0;
fitzhardinge98abfc72003-12-16 02:05:15 +00001656 res = sigtimedwait(set, &si, NULL);
jsgf855d93d2003-10-13 22:26:55 +00001657 *sig = si.si_signo;
1658
1659 return 0; /* always returns 0 */
sewardjb48e5002002-05-13 00:16:03 +00001660}
1661
1662
sewardj018f7622002-05-15 21:13:39 +00001663int pthread_kill(pthread_t thread, int signo)
1664{
1665 int res;
1666 ensure_valgrind("pthread_kill");
1667 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1668 VG_USERREQ__PTHREAD_KILL,
1669 thread, signo, 0, 0);
1670 return res;
1671}
1672
1673
sewardj3665ded2002-05-16 16:57:25 +00001674/* Copied verbatim from Linuxthreads */
1675/* Redefine raise() to send signal to calling thread only,
1676 as per POSIX 1003.1c */
1677int raise (int sig)
1678{
1679 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001680 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001681 return 0;
sewardj4dced352002-06-04 22:54:20 +00001682 } else {
sewardj25418ae2003-05-09 23:40:34 +00001683 *(__errno_location()) = retcode;
sewardj3665ded2002-05-16 16:57:25 +00001684 return -1;
1685 }
1686}
1687
1688
sewardj9a2224b2002-06-19 10:17:40 +00001689
sewardjb48e5002002-05-13 00:16:03 +00001690/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001691 THREAD-SPECIFICs
1692 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001693
sewardj00a66b12002-10-12 16:42:35 +00001694static
1695int key_is_valid (pthread_key_t key)
1696{
1697 int res;
1698 VALGRIND_MAGIC_SEQUENCE(res, 2 /* default */,
1699 VG_USERREQ__PTHREAD_KEY_VALIDATE,
1700 key, 0, 0, 0);
1701 my_assert(res != 2);
1702 return res;
1703}
1704
1705
1706/* Returns NULL if thread is invalid. Otherwise, if the thread
1707 already has a specifics area, return that. Otherwise allocate it
1708 one. */
1709static
1710void** get_or_allocate_specifics_ptr ( pthread_t thread )
1711{
1712 int res, i;
1713 void** specifics_ptr;
1714 ensure_valgrind("get_or_allocate_specifics_ptr");
1715
1716 /* Returns zero if the thread has no specific_ptr. One if thread
1717 is invalid. Otherwise, the specific_ptr value. This is
1718 allocated with my_malloc and so is aligned and cannot be
1719 confused with 1 or 3. */
1720 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
1721 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
1722 thread, 0, 0, 0);
1723 my_assert(specifics_ptr != (void**)3);
1724
1725 if (specifics_ptr == (void**)1)
1726 return NULL; /* invalid thread */
1727
1728 if (specifics_ptr != NULL)
1729 return specifics_ptr; /* already has a specifics ptr. */
1730
1731 /* None yet ... allocate a new one. Should never fail. */
1732 specifics_ptr = my_malloc( VG_N_THREAD_KEYS * sizeof(void*) );
1733 my_assert(specifics_ptr != NULL);
1734
1735 VALGRIND_MAGIC_SEQUENCE(res, -1 /* default */,
1736 VG_USERREQ__PTHREAD_SETSPECIFIC_PTR,
1737 specifics_ptr, 0, 0, 0);
1738 my_assert(res == 0);
1739
1740 /* POSIX sez: "Upon thread creation, the value NULL shall be
1741 associated with all defined keys in the new thread." This
1742 allocation is in effect a delayed allocation of the specific
1743 data for a thread, at its first-use. Hence we initialise it
1744 here. */
1745 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
1746 specifics_ptr[i] = NULL;
1747 }
1748
1749 return specifics_ptr;
1750}
1751
1752
sewardj5905fae2002-04-26 13:25:00 +00001753int __pthread_key_create(pthread_key_t *key,
1754 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001755{
sewardj00a66b12002-10-12 16:42:35 +00001756 void** specifics_ptr;
1757 int res, i;
sewardj5f07b662002-04-23 16:52:51 +00001758 ensure_valgrind("pthread_key_create");
sewardj00a66b12002-10-12 16:42:35 +00001759
1760 /* This writes *key if successful. It should never fail. */
1761 VALGRIND_MAGIC_SEQUENCE(res, 1 /* default */,
sewardj5f07b662002-04-23 16:52:51 +00001762 VG_USERREQ__PTHREAD_KEY_CREATE,
1763 key, destr_function, 0, 0);
jsgf855d93d2003-10-13 22:26:55 +00001764
1765 if (res == 0) {
1766 /* POSIX sez: "Upon key creation, the value NULL shall be
1767 associated with the new key in all active threads." */
1768 for (i = 0; i < VG_N_THREADS; i++) {
1769 specifics_ptr = get_or_allocate_specifics_ptr(i);
1770 /* we get NULL if i is an invalid thread. */
1771 if (specifics_ptr != NULL)
1772 specifics_ptr[*key] = NULL;
1773 }
sewardj00a66b12002-10-12 16:42:35 +00001774 }
1775
sewardj5f07b662002-04-23 16:52:51 +00001776 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001777}
1778
1779int pthread_key_delete(pthread_key_t key)
1780{
sewardj00a66b12002-10-12 16:42:35 +00001781 int res;
njndfc9b8c2003-09-29 12:58:37 +00001782 ensure_valgrind("pthread_key_delete");
sewardj00a66b12002-10-12 16:42:35 +00001783 if (!key_is_valid(key))
1784 return EINVAL;
1785 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1786 VG_USERREQ__PTHREAD_KEY_DELETE,
1787 key, 0, 0, 0);
1788 my_assert(res == 0);
sewardj5e5fa512002-04-14 13:13:05 +00001789 return 0;
1790}
1791
sewardj5905fae2002-04-26 13:25:00 +00001792int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001793{
sewardj00a66b12002-10-12 16:42:35 +00001794 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001795 ensure_valgrind("pthread_setspecific");
sewardj00a66b12002-10-12 16:42:35 +00001796
1797 if (!key_is_valid(key))
1798 return EINVAL;
1799
1800 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1801 specifics_ptr[key] = (void*)pointer;
1802 return 0;
sewardj5e5fa512002-04-14 13:13:05 +00001803}
1804
sewardj5905fae2002-04-26 13:25:00 +00001805void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001806{
sewardj00a66b12002-10-12 16:42:35 +00001807 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001808 ensure_valgrind("pthread_getspecific");
sewardj00a66b12002-10-12 16:42:35 +00001809
1810 if (!key_is_valid(key))
1811 return NULL;
1812
1813 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1814 return specifics_ptr[key];
1815}
1816
1817
sewardjf8f819e2002-04-17 23:21:37 +00001818/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001819 ONCEry
1820 ------------------------------------------------ */
1821
sewardjc91a4ff2003-07-11 00:12:58 +00001822/* This protects reads and writes of the once_control variable
1823 supplied. It is never held whilst any particular initialiser is
1824 running. */
sewardj89d3d852002-04-24 19:21:39 +00001825static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1826
sewardjc91a4ff2003-07-11 00:12:58 +00001827/* Initialiser needs to be run. */
1828#define P_ONCE_NOT_DONE ((PTHREAD_ONCE_INIT) + 0)
1829
1830/* Initialiser currently running. */
1831#define P_ONCE_RUNNING ((PTHREAD_ONCE_INIT) + 1)
1832
1833/* Initialiser has completed. */
1834#define P_ONCE_COMPLETED ((PTHREAD_ONCE_INIT) + 2)
sewardj89d3d852002-04-24 19:21:39 +00001835
sewardj5905fae2002-04-26 13:25:00 +00001836int __pthread_once ( pthread_once_t *once_control,
1837 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001838{
1839 int res;
sewardjc91a4ff2003-07-11 00:12:58 +00001840 int done;
sewardj89d3d852002-04-24 19:21:39 +00001841
sewardjc91a4ff2003-07-11 00:12:58 +00001842# define TAKE_LOCK \
1843 res = __pthread_mutex_lock(&once_masterlock); \
1844 my_assert(res == 0);
sewardj89d3d852002-04-24 19:21:39 +00001845
sewardjc91a4ff2003-07-11 00:12:58 +00001846# define RELEASE_LOCK \
1847 res = __pthread_mutex_unlock(&once_masterlock); \
1848 my_assert(res == 0);
sewardj89d3d852002-04-24 19:21:39 +00001849
jsgf855d93d2003-10-13 22:26:55 +00001850 void cleanup(void *v) {
1851 TAKE_LOCK;
1852 *once_control = P_ONCE_NOT_DONE;
1853 RELEASE_LOCK;
1854 }
1855
1856 ensure_valgrind("pthread_once");
1857
sewardjc91a4ff2003-07-11 00:12:58 +00001858 /* Grab the lock transiently, so we can safely see what state this
1859 once_control is in. */
1860
1861 TAKE_LOCK;
1862
1863 switch (*once_control) {
1864
1865 case P_ONCE_NOT_DONE:
1866 /* Not started. Change state to indicate running, drop the
1867 lock and run. */
1868 *once_control = P_ONCE_RUNNING;
jsgf855d93d2003-10-13 22:26:55 +00001869 _pthread_cleanup_push(NULL, cleanup, NULL);
sewardjc91a4ff2003-07-11 00:12:58 +00001870 RELEASE_LOCK;
1871 init_routine();
1872 /* re-take the lock, and set state to indicate done. */
1873 TAKE_LOCK;
jsgf855d93d2003-10-13 22:26:55 +00001874 _pthread_cleanup_pop(NULL, False);
sewardjc91a4ff2003-07-11 00:12:58 +00001875 *once_control = P_ONCE_COMPLETED;
1876 RELEASE_LOCK;
1877 break;
1878
1879 case P_ONCE_RUNNING:
1880 /* This is the tricky case. The initialiser is running in
1881 some other thread, but we have to delay this thread till
1882 the other one completes. So we sort-of busy wait. In
1883 fact it makes sense to yield now, because what we want to
1884 happen is for the thread running the initialiser to
1885 complete ASAP. */
1886 RELEASE_LOCK;
1887 done = 0;
1888 while (1) {
1889 /* Let others run for a while. */
1890 __valgrind_pthread_yield();
1891 /* Grab the lock and see if we're done waiting. */
1892 TAKE_LOCK;
1893 if (*once_control == P_ONCE_COMPLETED)
1894 done = 1;
1895 RELEASE_LOCK;
1896 if (done)
1897 break;
1898 }
1899 break;
1900
1901 case P_ONCE_COMPLETED:
1902 default:
1903 /* Easy. It's already done. Just drop the lock. */
1904 RELEASE_LOCK;
1905 break;
sewardj89d3d852002-04-24 19:21:39 +00001906 }
1907
sewardj89d3d852002-04-24 19:21:39 +00001908 return 0;
sewardjc91a4ff2003-07-11 00:12:58 +00001909
1910# undef TAKE_LOCK
1911# undef RELEASE_LOCK
sewardj89d3d852002-04-24 19:21:39 +00001912}
1913
sewardjc91a4ff2003-07-11 00:12:58 +00001914#undef P_ONCE_NOT_DONE
1915#undef P_ONCE_RUNNING
1916#undef P_ONCE_COMPLETED
1917
sewardj89d3d852002-04-24 19:21:39 +00001918
1919/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001920 MISC
1921 ------------------------------------------------ */
1922
sewardj2cb00342002-06-28 01:46:26 +00001923static pthread_mutex_t pthread_atfork_lock
1924 = PTHREAD_MUTEX_INITIALIZER;
1925
sewardj5905fae2002-04-26 13:25:00 +00001926int __pthread_atfork ( void (*prepare)(void),
1927 void (*parent)(void),
1928 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001929{
sewardj2cb00342002-06-28 01:46:26 +00001930 int n, res;
1931 ForkHandlerEntry entry;
1932
1933 ensure_valgrind("pthread_atfork");
1934 __pthread_mutex_lock(&pthread_atfork_lock);
1935
1936 /* Fetch old counter */
1937 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1938 VG_USERREQ__GET_FHSTACK_USED,
1939 0, 0, 0, 0);
1940 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1941 if (n == VG_N_FORKHANDLERSTACK-1)
1942 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1943 "increase and recompile");
1944
1945 /* Add entry */
1946 entry.prepare = *prepare;
1947 entry.parent = *parent;
1948 entry.child = *child;
1949 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1950 VG_USERREQ__SET_FHSTACK_ENTRY,
1951 n, &entry, 0, 0);
1952 my_assert(res == 0);
1953
1954 /* Bump counter */
1955 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1956 VG_USERREQ__SET_FHSTACK_USED,
1957 n+1, 0, 0, 0);
1958 my_assert(res == 0);
1959
1960 __pthread_mutex_unlock(&pthread_atfork_lock);
1961 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001962}
1963
1964
sewardj9df78832003-05-04 12:35:54 +00001965#ifdef GLIBC_2_3
1966/* This seems to be a hook which appeared in glibc-2.3.2. */
1967int __register_atfork ( void (*prepare)(void),
1968 void (*parent)(void),
1969 void (*child)(void) )
1970{
1971 return __pthread_atfork(prepare,parent,child);
1972}
1973#endif
1974
sewardj11f0bb42003-04-26 20:11:15 +00001975WEAK
sewardjbb990782002-05-08 02:01:14 +00001976void __pthread_initialize ( void )
1977{
sewardjbea1caa2002-05-10 23:20:58 +00001978 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001979}
1980
1981
sewardj853f55d2002-04-26 00:27:53 +00001982/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001983 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001984 ------------------------------------------------ */
1985
sewardj3b13f0e2002-04-25 20:17:29 +00001986#include <resolv.h>
sewardjf8f819e2002-04-17 23:21:37 +00001987
thughes5298da92004-03-07 19:36:14 +00001988/* The allowable libc TSD keys (indices) from glibc source. */
1989enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1990 _LIBC_TSD_KEY_DL_ERROR,
1991 _LIBC_TSD_KEY_RPC_VARS,
1992 _LIBC_TSD_KEY_LOCALE,
1993 _LIBC_TSD_KEY_CTYPE_B,
1994 _LIBC_TSD_KEY_CTYPE_TOLOWER,
1995 _LIBC_TSD_KEY_CTYPE_TOUPPER,
1996 _LIBC_TSD_KEY_N };
1997
fitzhardinge47735af2004-01-21 01:27:27 +00001998typedef
1999 struct {
thughes11975ff2004-06-12 12:58:22 +00002000 void *ret_val;
fitzhardinge47735af2004-01-21 01:27:27 +00002001 int *errno_ptr;
2002 int *h_errno_ptr;
2003 struct __res_state *res_state_ptr;
2004 int errno_data;
2005 int h_errno_data;
2006 struct __res_state res_state_data;
thughes5298da92004-03-07 19:36:14 +00002007 void *libc_specifics[_LIBC_TSD_KEY_N];
fitzhardinge47735af2004-01-21 01:27:27 +00002008 }
2009 ThreadSpecificState;
2010
2011static ThreadSpecificState thread_specific_state[VG_N_THREADS];
2012
thughes5298da92004-03-07 19:36:14 +00002013/* Auto-initialising subsystem. global_init_done is set
2014 after initialisation. global_init_done_mx guards it. */
2015static int global_init_done = 0;
2016static pthread_mutex_t global_init_done_mx = PTHREAD_MUTEX_INITIALIZER;
2017
thughes11975ff2004-06-12 12:58:22 +00002018static
2019void cleanup_root(void *arg)
2020{
2021 thread_exit_wrapper(get_ret_val());
2022 /* NOTREACHED */
2023}
2024
thughes2224f5c2004-08-14 15:37:59 +00002025static void __attribute__((constructor))
thughes5298da92004-03-07 19:36:14 +00002026init_global_thread_specific_state ( void )
fitzhardinge47735af2004-01-21 01:27:27 +00002027{
thughes5298da92004-03-07 19:36:14 +00002028 int res;
2029
2030 /* Don't fall into deadlock if we get called again whilst we still
2031 hold the lock, via the __uselocale() call herein. */
2032 if (global_init_done != 0)
2033 return;
2034
2035 /* Take the lock. */
2036 res = __pthread_mutex_lock(&global_init_done_mx);
2037 if (res != 0) barf("init_global_thread_specific_state: lock");
2038
2039 /* Now test again, to be sure there is no mistake. */
2040 if (global_init_done != 0) {
2041 res = __pthread_mutex_unlock(&global_init_done_mx);
2042 if (res != 0) barf("init_global_thread_specific_state: unlock(1)");
2043 return;
2044 }
2045
2046 /* assert that we are the root thread. */
2047 my_assert(pthread_self() == 1);
2048
thughesd02298a2004-07-17 11:08:03 +00002049 /* Signify init done - we shouldn't really do this until after
2050 the call to init_thread_specific_state() but that routine makes
2051 a call to __uselocale() that may bring us back here as that
2052 routine will call __libc_tsd_set() which will call us.
2053
2054 We can get away with marking the init as done now because
2055 the important bits of init_thread_specific_state() are done
2056 before the call to __uselocale() is made. */
2057 global_init_done = 1;
2058
thughes5298da92004-03-07 19:36:14 +00002059 /* Initialise thread specific data for the root thread. */
2060 init_thread_specific_state();
2061
thughes11975ff2004-06-12 12:58:22 +00002062 /* Install a cleanup routine to handle the root thread exiting */
2063 _pthread_cleanup_push(NULL, cleanup_root, NULL);
2064
thughes5298da92004-03-07 19:36:14 +00002065 /* Unlock and return. */
2066 res = __pthread_mutex_unlock(&global_init_done_mx);
2067 if (res != 0) barf("init_global_thread_specific_state: unlock");
2068}
2069
2070static void
2071init_thread_specific_state ( void )
2072{
2073 int tid = pthread_self();
2074 int i;
2075
thughes11975ff2004-06-12 12:58:22 +00002076 /* No return value yet */
2077 thread_specific_state[tid].ret_val = NULL;
2078
thughes5298da92004-03-07 19:36:14 +00002079 /* Initialise the errno and resolver state pointers. */
fitzhardinge47735af2004-01-21 01:27:27 +00002080 thread_specific_state[tid].errno_ptr = NULL;
2081 thread_specific_state[tid].h_errno_ptr = NULL;
2082 thread_specific_state[tid].res_state_ptr = NULL;
thughes5298da92004-03-07 19:36:14 +00002083
2084 /* Initialise the per-thread libc data. */
2085 for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
2086 thread_specific_state[tid].libc_specifics[i] = NULL;
2087 }
2088
2089# ifdef GLIBC_2_3
2090 /* Set this thread's locale to the global (default) locale. A hack
2091 in support of glibc-2.3.
2092 */
2093 __uselocale(LC_GLOBAL_LOCALE);
2094# endif
fitzhardinge47735af2004-01-21 01:27:27 +00002095}
2096
thughes11975ff2004-06-12 12:58:22 +00002097static void
2098set_ret_val ( void* ret_val )
2099{
2100 int tid;
2101 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
2102 VG_USERREQ__PTHREAD_GET_THREADID,
2103 0, 0, 0, 0);
2104 thread_specific_state[tid].ret_val = ret_val;
2105}
2106
2107static void *
2108get_ret_val ( void )
2109{
2110 int tid;
2111 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
2112 VG_USERREQ__PTHREAD_GET_THREADID,
2113 0, 0, 0, 0);
2114 return thread_specific_state[tid].ret_val;
2115}
2116
sewardj3b13f0e2002-04-25 20:17:29 +00002117int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00002118{
2119 int tid;
fitzhardinge98abfc72003-12-16 02:05:15 +00002120
2121 ensure_valgrind("__errno_location");
sewardj3b13f0e2002-04-25 20:17:29 +00002122 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00002123 VG_USERREQ__PTHREAD_GET_THREADID,
2124 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00002125 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00002126 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00002127 barf("__errno_location: invalid ThreadId");
fitzhardinge47735af2004-01-21 01:27:27 +00002128 if (thread_specific_state[tid].errno_ptr == NULL) {
nethercote9b3c7652004-10-19 13:18:00 +00002129 if (VGA_(has_tls)())
fitzhardinge47735af2004-01-21 01:27:27 +00002130 thread_specific_state[tid].errno_ptr = dlsym(RTLD_DEFAULT, "errno");
2131 else if (tid == 1)
2132 thread_specific_state[tid].errno_ptr = dlvsym(RTLD_DEFAULT, "errno", "GLIBC_2.0");
2133 else
2134 thread_specific_state[tid].errno_ptr = &thread_specific_state[tid].errno_data;
2135 }
2136 return thread_specific_state[tid].errno_ptr;
sewardj3b13f0e2002-04-25 20:17:29 +00002137}
2138
2139int* __h_errno_location ( void )
2140{
2141 int tid;
2142 /* ensure_valgrind("__h_errno_location"); */
2143 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
2144 VG_USERREQ__PTHREAD_GET_THREADID,
2145 0, 0, 0, 0);
2146 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00002147 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00002148 barf("__h_errno_location: invalid ThreadId");
fitzhardinge47735af2004-01-21 01:27:27 +00002149 if (thread_specific_state[tid].h_errno_ptr == NULL) {
nethercote9b3c7652004-10-19 13:18:00 +00002150 if (VGA_(has_tls)())
fitzhardinge47735af2004-01-21 01:27:27 +00002151 thread_specific_state[tid].h_errno_ptr = dlsym(RTLD_DEFAULT, "h_errno");
2152 else if (tid == 1)
2153 thread_specific_state[tid].h_errno_ptr = dlvsym(RTLD_DEFAULT, "h_errno", "GLIBC_2.0");
2154 else
2155 thread_specific_state[tid].h_errno_ptr = &thread_specific_state[tid].h_errno_data;
2156 }
2157 return thread_specific_state[tid].h_errno_ptr;
sewardj3b13f0e2002-04-25 20:17:29 +00002158}
2159
2160struct __res_state* __res_state ( void )
2161{
2162 int tid;
2163 /* ensure_valgrind("__res_state"); */
2164 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
2165 VG_USERREQ__PTHREAD_GET_THREADID,
2166 0, 0, 0, 0);
2167 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00002168 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00002169 barf("__res_state: invalid ThreadId");
fitzhardinge47735af2004-01-21 01:27:27 +00002170 if (thread_specific_state[tid].res_state_ptr == NULL) {
nethercote9b3c7652004-10-19 13:18:00 +00002171 if (VGA_(has_tls)()) {
fitzhardinge47735af2004-01-21 01:27:27 +00002172 struct __res_state **resp = dlsym(RTLD_DEFAULT, "__resp");
2173
2174 thread_specific_state[tid].res_state_ptr = *resp;
2175 } else if (tid == 1) {
2176 thread_specific_state[tid].res_state_ptr = dlvsym(RTLD_DEFAULT, "_res", "GLIBC_2.0");
2177 } else {
2178 thread_specific_state[tid].res_state_ptr = &thread_specific_state[tid].res_state_data;
2179 }
2180 }
2181 return thread_specific_state[tid].res_state_ptr;
sewardjf8f819e2002-04-17 23:21:37 +00002182}
2183
2184
sewardj5716dbb2002-04-26 03:28:18 +00002185/* ---------------------------------------------------
2186 LIBC-PRIVATE SPECIFIC DATA
2187 ------------------------------------------------ */
2188
sewardj5716dbb2002-04-26 03:28:18 +00002189static int
2190libc_internal_tsd_set ( enum __libc_tsd_key_t key,
2191 const void * pointer )
2192{
thughes5298da92004-03-07 19:36:14 +00002193 int tid = pthread_self();
sewardj5716dbb2002-04-26 03:28:18 +00002194 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardjcb7f08a2002-10-02 09:41:49 +00002195 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00002196 barf("libc_internal_tsd_set: invalid key");
thughes5298da92004-03-07 19:36:14 +00002197 init_global_thread_specific_state();
2198 thread_specific_state[tid].libc_specifics[key] = (void *)pointer;
sewardj5716dbb2002-04-26 03:28:18 +00002199 return 0;
2200}
2201
2202static void *
2203libc_internal_tsd_get ( enum __libc_tsd_key_t key )
2204{
thughes5298da92004-03-07 19:36:14 +00002205 int tid = pthread_self();
sewardj5716dbb2002-04-26 03:28:18 +00002206 /* printf("GET GET GET key %d\n", key); */
sewardjcb7f08a2002-10-02 09:41:49 +00002207 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00002208 barf("libc_internal_tsd_get: invalid key");
thughes5298da92004-03-07 19:36:14 +00002209 init_global_thread_specific_state();
2210 return thread_specific_state[tid].libc_specifics[key];
sewardj5716dbb2002-04-26 03:28:18 +00002211}
2212
2213
sewardj70adeb22002-04-27 01:35:38 +00002214int (*__libc_internal_tsd_set)
2215 (enum __libc_tsd_key_t key, const void * pointer)
2216 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00002217
sewardj70adeb22002-04-27 01:35:38 +00002218void* (*__libc_internal_tsd_get)
2219 (enum __libc_tsd_key_t key)
2220 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00002221
2222
sewardj00a66b12002-10-12 16:42:35 +00002223#ifdef GLIBC_2_3
2224/* This one was first spotted be me in the glibc-2.2.93 sources. */
2225static void**
2226libc_internal_tsd_address ( enum __libc_tsd_key_t key )
2227{
thughes5298da92004-03-07 19:36:14 +00002228 int tid = pthread_self();
sewardj00a66b12002-10-12 16:42:35 +00002229 /* printf("ADDR ADDR ADDR key %d\n", key); */
2230 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
2231 barf("libc_internal_tsd_address: invalid key");
thughes5298da92004-03-07 19:36:14 +00002232 init_global_thread_specific_state();
2233 return &thread_specific_state[tid].libc_specifics[key];
sewardj00a66b12002-10-12 16:42:35 +00002234}
2235
2236void ** (*__libc_internal_tsd_address)
2237 (enum __libc_tsd_key_t key)
2238 = libc_internal_tsd_address;
2239#endif
2240
2241
sewardje663cb92002-04-12 10:26:32 +00002242/* ---------------------------------------------------------------------
2243 These are here (I think) because they are deemed cancellation
2244 points by POSIX. For the moment we'll simply pass the call along
2245 to the corresponding thread-unaware (?) libc routine.
2246 ------------------------------------------------------------------ */
2247
thughes737cf762004-10-16 10:50:11 +00002248static void *libpthread_handle;
2249
thughesb2717cb2004-08-22 22:56:25 +00002250#define FORWARD(name, altname, args...) \
thughesa555ea72004-06-03 18:00:58 +00002251 ({ \
2252 static name##_t name##_ptr = NULL; \
thughes737cf762004-10-16 10:50:11 +00002253 if (libpthread_handle == NULL) { \
2254 libpthread_handle = dlopen("libpthread.so.0", RTLD_LAZY); \
2255 my_assert(libpthread_handle != NULL); \
2256 } \
thughesa555ea72004-06-03 18:00:58 +00002257 if (name##_ptr == NULL) { \
thughesb2717cb2004-08-22 22:56:25 +00002258 if ((name##_ptr = (name##_t)dlsym(RTLD_NEXT, #name)) == NULL) \
2259 name##_ptr = (name##_t)dlsym(RTLD_DEFAULT, #altname); \
thughes737cf762004-10-16 10:50:11 +00002260 my_assert(name##_ptr != NULL && name##_ptr != dlsym(libpthread_handle, #name)); \
thughesa555ea72004-06-03 18:00:58 +00002261 } \
2262 name##_ptr(args); \
2263 })
2264
2265typedef
2266int (*sigaction_t)
sewardjd529a442002-05-04 19:49:21 +00002267 (int signum,
2268 const struct sigaction *act,
2269 struct sigaction *oldact);
sewardje663cb92002-04-12 10:26:32 +00002270int sigaction(int signum,
2271 const struct sigaction *act,
2272 struct sigaction *oldact)
2273{
sewardjd140e442002-05-29 01:21:19 +00002274 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002275#ifdef GLIBC_2_1
2276 return FORWARD(sigaction, __sigaction, signum, act, oldact);
2277#else
2278 return FORWARD(sigaction, __libc_sigaction, signum, act, oldact);
2279#endif
sewardje663cb92002-04-12 10:26:32 +00002280}
2281
thughesa555ea72004-06-03 18:00:58 +00002282typedef
thughesa06b9112004-06-04 21:42:18 +00002283int (*accept_t)(int fd, struct sockaddr *addr, socklen_t *len);
jsgf855d93d2003-10-13 22:26:55 +00002284
thughesa06b9112004-06-04 21:42:18 +00002285WEAK
2286int accept(int fd, struct sockaddr *addr, socklen_t *len)
jsgf855d93d2003-10-13 22:26:55 +00002287{
2288 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002289 return FORWARD(accept, __libc_accept, fd, addr, len);
jsgf855d93d2003-10-13 22:26:55 +00002290}
sewardje663cb92002-04-12 10:26:32 +00002291
thughesa555ea72004-06-03 18:00:58 +00002292typedef
2293int (*connect_t)(int sockfd,
2294 const struct sockaddr *serv_addr,
2295 socklen_t addrlen);
sewardj11f0bb42003-04-26 20:11:15 +00002296WEAK
thughesa555ea72004-06-03 18:00:58 +00002297int connect(int sockfd,
2298 const struct sockaddr *serv_addr,
2299 socklen_t addrlen)
sewardje663cb92002-04-12 10:26:32 +00002300{
sewardjd140e442002-05-29 01:21:19 +00002301 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002302 return FORWARD(connect, __libc_connect, sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00002303}
2304
2305
thughesa555ea72004-06-03 18:00:58 +00002306typedef
2307int (*fcntl_t)(int fd, int cmd, long arg);
sewardj11f0bb42003-04-26 20:11:15 +00002308WEAK
sewardje663cb92002-04-12 10:26:32 +00002309int fcntl(int fd, int cmd, long arg)
2310{
sewardjd140e442002-05-29 01:21:19 +00002311 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002312 return FORWARD(fcntl, __libc_fcntl, fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00002313}
2314
2315
thughesa555ea72004-06-03 18:00:58 +00002316typedef
2317ssize_t (*write_t)(int fd, const void *buf, size_t count);
sewardj11f0bb42003-04-26 20:11:15 +00002318WEAK
sewardje663cb92002-04-12 10:26:32 +00002319ssize_t write(int fd, const void *buf, size_t count)
2320{
sewardjd140e442002-05-29 01:21:19 +00002321 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002322 return FORWARD(write, __libc_write, fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00002323}
2324
2325
thughesa555ea72004-06-03 18:00:58 +00002326typedef
2327ssize_t (*read_t)(int fd, void *buf, size_t count);
sewardj11f0bb42003-04-26 20:11:15 +00002328WEAK
sewardje663cb92002-04-12 10:26:32 +00002329ssize_t read(int fd, void *buf, size_t count)
2330{
sewardjd140e442002-05-29 01:21:19 +00002331 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002332 return FORWARD(read, __libc_read, fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00002333}
2334
thughesa555ea72004-06-03 18:00:58 +00002335typedef
2336int (*open64_t)(const char *pathname, int flags, mode_t mode);
sewardj11f0bb42003-04-26 20:11:15 +00002337/* WEAK */
sewardjf912dfc2002-11-13 21:51:10 +00002338int open64(const char *pathname, int flags, mode_t mode)
2339{
thughesb2717cb2004-08-22 22:56:25 +00002340 return FORWARD(open64, __libc_open64, pathname, flags, mode);
sewardjf912dfc2002-11-13 21:51:10 +00002341}
sewardje663cb92002-04-12 10:26:32 +00002342
thughesa555ea72004-06-03 18:00:58 +00002343typedef
2344int (*open_t)(const char *pathname, int flags, mode_t mode);
sewardj11f0bb42003-04-26 20:11:15 +00002345/* WEAK */
sewardj853f55d2002-04-26 00:27:53 +00002346int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00002347{
thughesb2717cb2004-08-22 22:56:25 +00002348 return FORWARD(open, __libc_open, pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00002349}
2350
thughesa555ea72004-06-03 18:00:58 +00002351typedef
2352int (*close_t)(int fd);
sewardj11f0bb42003-04-26 20:11:15 +00002353WEAK
sewardje663cb92002-04-12 10:26:32 +00002354int close(int fd)
2355{
sewardjd140e442002-05-29 01:21:19 +00002356 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002357 return FORWARD(close, __libc_close, fd);
sewardje663cb92002-04-12 10:26:32 +00002358}
2359
2360
thughesa555ea72004-06-03 18:00:58 +00002361typedef
2362pid_t (*waitpid_t)(pid_t pid, int *status, int options);
sewardj11f0bb42003-04-26 20:11:15 +00002363WEAK
sewardje663cb92002-04-12 10:26:32 +00002364pid_t waitpid(pid_t pid, int *status, int options)
2365{
sewardjd140e442002-05-29 01:21:19 +00002366 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002367 return FORWARD(waitpid, __libc_waitpid, pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00002368}
2369
2370
thughesa555ea72004-06-03 18:00:58 +00002371typedef
thughesb2717cb2004-08-22 22:56:25 +00002372int (*__nanosleep_t)(const struct timespec *req, struct timespec *rem);
sewardj11f0bb42003-04-26 20:11:15 +00002373WEAK
jsgf855d93d2003-10-13 22:26:55 +00002374int __nanosleep(const struct timespec *req, struct timespec *rem)
sewardje663cb92002-04-12 10:26:32 +00002375{
sewardjd140e442002-05-29 01:21:19 +00002376 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002377 return FORWARD(__nanosleep, __libc_nanosleep, req, rem);
sewardje663cb92002-04-12 10:26:32 +00002378}
2379
thughesa555ea72004-06-03 18:00:58 +00002380typedef
2381int (*pause_t)(void);
jsgf855d93d2003-10-13 22:26:55 +00002382WEAK
thughesb2717cb2004-08-22 22:56:25 +00002383int pause(void)
jsgf855d93d2003-10-13 22:26:55 +00002384{
2385 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002386 return FORWARD(pause, __libc_pause);
jsgf855d93d2003-10-13 22:26:55 +00002387}
2388
sewardjbe32e452002-04-24 20:29:58 +00002389
thughesa555ea72004-06-03 18:00:58 +00002390typedef
thughesb2717cb2004-08-22 22:56:25 +00002391int (*__tcdrain_t)(int fd);
thughesd27c7f52004-03-31 15:23:13 +00002392WEAK
2393int __tcdrain(int fd)
2394{
2395 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002396 return FORWARD(__tcdrain, __libc_tcdrain, fd);
thughesd27c7f52004-03-31 15:23:13 +00002397}
2398
2399
thughesa555ea72004-06-03 18:00:58 +00002400typedef
2401int (*fsync_t)(int fd);
sewardj11f0bb42003-04-26 20:11:15 +00002402WEAK
sewardje663cb92002-04-12 10:26:32 +00002403int fsync(int fd)
2404{
sewardjd140e442002-05-29 01:21:19 +00002405 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002406 return FORWARD(fsync, __libc_fsync, fd);
sewardje663cb92002-04-12 10:26:32 +00002407}
2408
sewardjbe32e452002-04-24 20:29:58 +00002409
thughesa555ea72004-06-03 18:00:58 +00002410typedef
2411off_t (*lseek_t)(int fildes, off_t offset, int whence);
sewardj11f0bb42003-04-26 20:11:15 +00002412WEAK
sewardj70c75362002-04-13 04:18:32 +00002413off_t lseek(int fildes, off_t offset, int whence)
2414{
sewardjd140e442002-05-29 01:21:19 +00002415 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002416 return FORWARD(lseek, __libc_lseek, fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00002417}
2418
sewardjbe32e452002-04-24 20:29:58 +00002419
thughesa555ea72004-06-03 18:00:58 +00002420typedef
2421__off64_t (*lseek64_t)(int fildes, __off64_t offset, int whence);
sewardj11f0bb42003-04-26 20:11:15 +00002422WEAK
sewardjbe32e452002-04-24 20:29:58 +00002423__off64_t lseek64(int fildes, __off64_t offset, int whence)
2424{
sewardjd140e442002-05-29 01:21:19 +00002425 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002426 return FORWARD(lseek64, __libc_lseek64, fildes, offset, whence);
sewardjbe32e452002-04-24 20:29:58 +00002427}
2428
2429
thughesa555ea72004-06-03 18:00:58 +00002430typedef
2431ssize_t (*__pread64_t) (int __fd, void *__buf, size_t __nbytes,
sewardj726c4122002-05-16 23:39:10 +00002432 __off64_t __offset);
2433ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
2434 __off64_t __offset)
2435{
sewardjd140e442002-05-29 01:21:19 +00002436 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002437 return FORWARD(__pread64, __libc_pread64, __fd, __buf, __nbytes, __offset);
sewardj726c4122002-05-16 23:39:10 +00002438}
2439
2440
thughesa555ea72004-06-03 18:00:58 +00002441typedef
2442ssize_t (*__pwrite64_t) (int __fd, const void *__buf, size_t __nbytes,
2443 __off64_t __offset);
sewardja18e2102002-05-18 10:43:22 +00002444ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
2445 __off64_t __offset)
2446{
sewardjd140e442002-05-29 01:21:19 +00002447 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002448 return FORWARD(__pwrite64, __libc_pwrite64, __fd, __buf, __nbytes, __offset);
sewardja18e2102002-05-18 10:43:22 +00002449}
2450
sewardj726c4122002-05-16 23:39:10 +00002451
thughesa555ea72004-06-03 18:00:58 +00002452typedef
2453ssize_t (*pwrite_t)(int fd, const void *buf, size_t count, off_t offset);
sewardj11f0bb42003-04-26 20:11:15 +00002454WEAK
sewardj39b93b12002-05-18 10:56:27 +00002455ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
2456{
sewardjd140e442002-05-29 01:21:19 +00002457 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002458 return FORWARD(pwrite, __libc_pwrite, fd, buf, count, offset);
sewardj39b93b12002-05-18 10:56:27 +00002459}
2460
2461
thughesa555ea72004-06-03 18:00:58 +00002462typedef
2463ssize_t (*pread_t)(int fd, void *buf, size_t count, off_t offset);
sewardj11f0bb42003-04-26 20:11:15 +00002464WEAK
sewardj39b93b12002-05-18 10:56:27 +00002465ssize_t pread(int fd, void *buf, size_t count, off_t offset)
2466{
sewardjd140e442002-05-29 01:21:19 +00002467 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002468 return FORWARD(pread, __libc_pread, fd, buf, count, offset);
sewardj39b93b12002-05-18 10:56:27 +00002469}
2470
thughesa555ea72004-06-03 18:00:58 +00002471typedef
nethercotec79ce472004-11-04 19:11:19 +00002472ssize_t (*recv_t)(int s, void *msg, size_t len, int flags);
jsgf855d93d2003-10-13 22:26:55 +00002473WEAK
nethercotec79ce472004-11-04 19:11:19 +00002474ssize_t recv(int s, void *msg, size_t len, int flags)
sewardj6af4b5d2002-04-16 04:40:49 +00002475{
jsgf855d93d2003-10-13 22:26:55 +00002476 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002477 return FORWARD(recv, __libc_recv, s, msg, len, flags);
sewardj6af4b5d2002-04-16 04:40:49 +00002478}
2479
thughesa555ea72004-06-03 18:00:58 +00002480typedef
nethercotec79ce472004-11-04 19:11:19 +00002481ssize_t (*send_t)(int s, const void *msg, size_t len, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002482WEAK
nethercotec79ce472004-11-04 19:11:19 +00002483ssize_t send(int s, const void *msg, size_t len, int flags)
sewardj6af4b5d2002-04-16 04:40:49 +00002484{
sewardjd140e442002-05-29 01:21:19 +00002485 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002486 return FORWARD(send, __libc_send, s, msg, len, flags);
sewardj6af4b5d2002-04-16 04:40:49 +00002487}
2488
sewardjbe32e452002-04-24 20:29:58 +00002489
thughesa555ea72004-06-03 18:00:58 +00002490typedef
nethercotec79ce472004-11-04 19:11:19 +00002491ssize_t (*sendmsg_t)(int s, const struct msghdr *msg, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002492WEAK
nethercotec79ce472004-11-04 19:11:19 +00002493ssize_t sendmsg(int s, const struct msghdr *msg, int flags)
sewardj3665ded2002-05-16 16:57:25 +00002494{
sewardjd140e442002-05-29 01:21:19 +00002495 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002496 return FORWARD(sendmsg, __libc_sendmsg, s, msg, flags);
sewardj3665ded2002-05-16 16:57:25 +00002497}
2498
2499
thughesa555ea72004-06-03 18:00:58 +00002500typedef
nethercotec79ce472004-11-04 19:11:19 +00002501ssize_t (*recvmsg_t)(int s, struct msghdr *msg, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002502WEAK
nethercotec79ce472004-11-04 19:11:19 +00002503ssize_t recvmsg(int s, struct msghdr *msg, int flags)
sewardj59da27a2002-06-06 08:33:54 +00002504{
2505 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002506 return FORWARD(recvmsg, __libc_recvmsg, s, msg, flags);
sewardj59da27a2002-06-06 08:33:54 +00002507}
2508
2509
thughesa555ea72004-06-03 18:00:58 +00002510typedef
nethercotec79ce472004-11-04 19:11:19 +00002511ssize_t (*recvfrom_t)(int s, void *buf, size_t len, int flags,
thughesa555ea72004-06-03 18:00:58 +00002512 struct sockaddr *from, socklen_t *fromlen);
sewardj11f0bb42003-04-26 20:11:15 +00002513WEAK
nethercotec79ce472004-11-04 19:11:19 +00002514ssize_t recvfrom(int s, void *buf, size_t len, int flags,
2515 struct sockaddr *from, socklen_t *fromlen)
sewardj436e0582002-04-26 14:31:40 +00002516{
sewardjd140e442002-05-29 01:21:19 +00002517 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002518 return FORWARD(recvfrom, __libc_recfrom, s, buf, len, flags, from, fromlen);
sewardj436e0582002-04-26 14:31:40 +00002519}
2520
2521
thughesa555ea72004-06-03 18:00:58 +00002522typedef
nethercotec79ce472004-11-04 19:11:19 +00002523ssize_t (*sendto_t)(int s, const void *msg, size_t len, int flags,
2524 const struct sockaddr *to, socklen_t tolen);
sewardj11f0bb42003-04-26 20:11:15 +00002525WEAK
nethercotec79ce472004-11-04 19:11:19 +00002526ssize_t sendto(int s, const void *msg, size_t len, int flags,
2527 const struct sockaddr *to, socklen_t tolen)
sewardj796d6a22002-04-24 02:28:34 +00002528{
sewardjd140e442002-05-29 01:21:19 +00002529 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002530 return FORWARD(sendto, __libc_sendto, s, msg, len, flags, to, tolen);
sewardj796d6a22002-04-24 02:28:34 +00002531}
2532
sewardjbe32e452002-04-24 20:29:58 +00002533
thughesa555ea72004-06-03 18:00:58 +00002534typedef
2535int (*system_t)(const char* str);
sewardj11f0bb42003-04-26 20:11:15 +00002536WEAK
sewardj369b1702002-04-24 13:28:15 +00002537int system(const char* str)
2538{
sewardjd140e442002-05-29 01:21:19 +00002539 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002540 return FORWARD(system, __libc_system, str);
sewardj369b1702002-04-24 13:28:15 +00002541}
2542
sewardjbe32e452002-04-24 20:29:58 +00002543
thughesa555ea72004-06-03 18:00:58 +00002544typedef
2545pid_t (*wait_t)(int *status);
sewardj11f0bb42003-04-26 20:11:15 +00002546WEAK
sewardjab0b1c32002-04-24 19:26:47 +00002547pid_t wait(int *status)
2548{
sewardjd140e442002-05-29 01:21:19 +00002549 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002550 return FORWARD(wait, __libc_wait, status);
sewardjab0b1c32002-04-24 19:26:47 +00002551}
2552
sewardj45b4b372002-04-16 22:50:32 +00002553
thughesa555ea72004-06-03 18:00:58 +00002554typedef
2555int (*msync_t)(const void *start, size_t length, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002556WEAK
sewardj67f1d582002-05-24 02:11:32 +00002557int msync(const void *start, size_t length, int flags)
2558{
sewardjd140e442002-05-29 01:21:19 +00002559 __my_pthread_testcancel();
thughesb2717cb2004-08-22 22:56:25 +00002560 return FORWARD(msync, __libc_msync, start, length, flags);
sewardj67f1d582002-05-24 02:11:32 +00002561}
2562
jsgf855d93d2003-10-13 22:26:55 +00002563strong_alias(close, __close)
2564strong_alias(fcntl, __fcntl)
2565strong_alias(lseek, __lseek)
2566strong_alias(open, __open)
2567strong_alias(open64, __open64)
2568strong_alias(read, __read)
2569strong_alias(wait, __wait)
2570strong_alias(write, __write)
2571strong_alias(connect, __connect)
2572strong_alias(send, __send)
thughesb2717cb2004-08-22 22:56:25 +00002573strong_alias(pause, __pause)
jsgf855d93d2003-10-13 22:26:55 +00002574
2575weak_alias (__pread64, pread64)
2576weak_alias (__pwrite64, pwrite64)
2577weak_alias(__nanosleep, nanosleep)
thughesd27c7f52004-03-31 15:23:13 +00002578weak_alias(__tcdrain, tcdrain)
jsgf855d93d2003-10-13 22:26:55 +00002579
2580
thughesa555ea72004-06-03 18:00:58 +00002581typedef
2582void (*longjmp_t)(jmp_buf env, int val) __attribute((noreturn));
jsgf855d93d2003-10-13 22:26:55 +00002583/* not weak: WEAK */
2584void longjmp(jmp_buf env, int val)
2585{
thughesb2717cb2004-08-22 22:56:25 +00002586 FORWARD(longjmp, __libc_longjmp, env, val);
jsgf855d93d2003-10-13 22:26:55 +00002587}
2588
2589
thughesa555ea72004-06-03 18:00:58 +00002590typedef void (*siglongjmp_t) (sigjmp_buf env, int val)
2591 __attribute__ ((noreturn));
jsgf855d93d2003-10-13 22:26:55 +00002592void siglongjmp(sigjmp_buf env, int val)
2593{
nethercoteaad8c192003-11-20 14:23:09 +00002594 kludged("siglongjmp", "(it ignores cleanup handlers)");
thughesb2717cb2004-08-22 22:56:25 +00002595 FORWARD(siglongjmp, __libc_siglongjmp, env, val);
jsgf855d93d2003-10-13 22:26:55 +00002596}
2597
sewardj5905fae2002-04-26 13:25:00 +00002598
sewardj2cb00342002-06-28 01:46:26 +00002599/*--- fork and its helper ---*/
2600
2601static
2602void run_fork_handlers ( int what )
2603{
2604 ForkHandlerEntry entry;
2605 int n_h, n_handlers, i, res;
2606
2607 my_assert(what == 0 || what == 1 || what == 2);
2608
2609 /* Fetch old counter */
2610 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2611 VG_USERREQ__GET_FHSTACK_USED,
2612 0, 0, 0, 0);
2613 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2614
2615 /* Prepare handlers (what == 0) are called in opposite order of
2616 calls to pthread_atfork. Parent and child handlers are called
2617 in the same order as calls to pthread_atfork. */
2618 if (what == 0)
2619 n_h = n_handlers - 1;
2620 else
2621 n_h = 0;
2622
2623 for (i = 0; i < n_handlers; i++) {
2624 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2625 VG_USERREQ__GET_FHSTACK_ENTRY,
2626 n_h, &entry, 0, 0);
2627 my_assert(res == 0);
2628 switch (what) {
2629 case 0: if (entry.prepare) entry.prepare();
2630 n_h--; break;
2631 case 1: if (entry.parent) entry.parent();
2632 n_h++; break;
2633 case 2: if (entry.child) entry.child();
2634 n_h++; break;
2635 default: barf("run_fork_handlers: invalid what");
2636 }
2637 }
2638
2639 if (what != 0 /* prepare */) {
2640 /* Empty out the stack. */
2641 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2642 VG_USERREQ__SET_FHSTACK_USED,
2643 0, 0, 0, 0);
2644 my_assert(res == 0);
2645 }
2646}
2647
thughesa555ea72004-06-03 18:00:58 +00002648typedef
2649pid_t (*__fork_t)(void);
sewardj2cb00342002-06-28 01:46:26 +00002650pid_t __fork(void)
2651{
2652 pid_t pid;
2653 __my_pthread_testcancel();
2654 __pthread_mutex_lock(&pthread_atfork_lock);
2655
2656 run_fork_handlers(0 /* prepare */);
thughesb2717cb2004-08-22 22:56:25 +00002657 pid = FORWARD(__fork, __libc_fork);
sewardj2cb00342002-06-28 01:46:26 +00002658 if (pid == 0) {
2659 /* I am the child */
2660 run_fork_handlers(2 /* child */);
sewardjd8acdf22002-11-13 21:57:52 +00002661 __pthread_mutex_unlock(&pthread_atfork_lock);
sewardj2cb00342002-06-28 01:46:26 +00002662 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2663 } else {
2664 /* I am the parent */
2665 run_fork_handlers(1 /* parent */);
2666 __pthread_mutex_unlock(&pthread_atfork_lock);
2667 }
2668 return pid;
2669}
2670
2671
njn25e49d8e72002-09-23 09:36:25 +00002672pid_t __vfork(void)
2673{
2674 return __fork();
2675}
sewardj2cb00342002-06-28 01:46:26 +00002676
2677
sewardj08a4c3f2002-04-13 03:45:44 +00002678
sewardj3b13f0e2002-04-25 20:17:29 +00002679/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002680 Hacky implementation of semaphores.
2681 ------------------------------------------------------------------ */
2682
2683#include <semaphore.h>
2684
sewardj8f253ff2002-05-19 00:13:34 +00002685typedef
2686 struct {
2687 pthread_mutex_t se_mx;
2688 pthread_cond_t se_cv;
2689 int count;
jseward556c9f82004-01-02 11:39:06 +00002690 int waiters;
sewardj8f253ff2002-05-19 00:13:34 +00002691 }
2692 vg_sem_t;
2693
thughes4dea4ab2004-03-23 19:48:54 +00002694#define SEM_CHECK_MAGIC 0x5b1d0772
sewardj8f253ff2002-05-19 00:13:34 +00002695
thughes4dea4ab2004-03-23 19:48:54 +00002696typedef
2697 struct {
2698 union {
2699 vg_sem_t* p;
2700 int i;
2701 } shadow;
2702 int err_check;
2703 }
2704 user_sem_t;
sewardj8f253ff2002-05-19 00:13:34 +00002705
thughes4dea4ab2004-03-23 19:48:54 +00002706
2707static vg_sem_t* se_new ( sem_t* orig )
sewardj8f253ff2002-05-19 00:13:34 +00002708{
thughes4dea4ab2004-03-23 19:48:54 +00002709 user_sem_t* u_sem = (user_sem_t*)orig;
2710 vg_sem_t* vg_sem;
sewardj8f253ff2002-05-19 00:13:34 +00002711
thughes4dea4ab2004-03-23 19:48:54 +00002712 vg_sem = my_malloc(sizeof(vg_sem_t));
2713
2714 u_sem->shadow.p = vg_sem;
2715 u_sem->err_check = u_sem->shadow.i ^ SEM_CHECK_MAGIC;
2716
2717 return vg_sem;
sewardj8f253ff2002-05-19 00:13:34 +00002718}
2719
thughes4dea4ab2004-03-23 19:48:54 +00002720static vg_sem_t* se_lookup ( sem_t* orig )
jseward556c9f82004-01-02 11:39:06 +00002721{
thughes4dea4ab2004-03-23 19:48:54 +00002722 user_sem_t* u_sem = (user_sem_t*) orig;
jseward556c9f82004-01-02 11:39:06 +00002723
thughes4dea4ab2004-03-23 19:48:54 +00002724 if(!u_sem->shadow.p || ((u_sem->shadow.i ^ SEM_CHECK_MAGIC) != u_sem->err_check))
2725 return NULL;
2726
2727 return u_sem->shadow.p;
2728}
2729
2730static void se_free( sem_t* orig )
2731{
2732 user_sem_t* u_sem = (user_sem_t*) orig;
2733
2734 my_free(u_sem->shadow.p);
2735
2736 u_sem->shadow.p = NULL;
2737 u_sem->err_check = 0;
2738
2739 return;
jseward556c9f82004-01-02 11:39:06 +00002740}
sewardj8f253ff2002-05-19 00:13:34 +00002741
2742int sem_init(sem_t *sem, int pshared, unsigned int value)
2743{
2744 int res;
2745 vg_sem_t* vg_sem;
2746 ensure_valgrind("sem_init");
2747 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002748 pthread_error("sem_init: unsupported pshared value");
sewardj25418ae2003-05-09 23:40:34 +00002749 *(__errno_location()) = ENOSYS;
sewardj8f253ff2002-05-19 00:13:34 +00002750 return -1;
2751 }
thughes4dea4ab2004-03-23 19:48:54 +00002752 vg_sem = se_new(sem);
2753
sewardj8f253ff2002-05-19 00:13:34 +00002754 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002755 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002756 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002757 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002758 vg_sem->count = value;
thughes4dea4ab2004-03-23 19:48:54 +00002759 vg_sem->waiters = 0;
sewardj8f253ff2002-05-19 00:13:34 +00002760 return 0;
2761}
2762
sewardj8f253ff2002-05-19 00:13:34 +00002763int sem_wait ( sem_t* sem )
2764{
2765 int res;
2766 vg_sem_t* vg_sem;
2767 ensure_valgrind("sem_wait");
thughes4dea4ab2004-03-23 19:48:54 +00002768 vg_sem = se_lookup(sem);
2769 if(!vg_sem) {
2770 pthread_error("sem_wait: semaphore overwritten or not initialized");
2771 *(__errno_location()) = EINVAL;
2772 return -1;
2773 }
sewardj8f253ff2002-05-19 00:13:34 +00002774 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002775 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002776 while (vg_sem->count == 0) {
jseward556c9f82004-01-02 11:39:06 +00002777 ++vg_sem->waiters;
sewardj8f253ff2002-05-19 00:13:34 +00002778 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
jseward556c9f82004-01-02 11:39:06 +00002779 --vg_sem->waiters;
sewardj2d94c112002-06-03 01:25:54 +00002780 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002781 }
2782 vg_sem->count--;
2783 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002784 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002785 return 0;
2786}
2787
2788int sem_post ( sem_t* sem )
2789{
2790 int res;
2791 vg_sem_t* vg_sem;
2792 ensure_valgrind("sem_post");
thughes4dea4ab2004-03-23 19:48:54 +00002793 vg_sem = se_lookup(sem);
2794 if(!vg_sem) {
2795 pthread_error("sem_post: semaphore overwritten or not initialized");
2796 *(__errno_location()) = EINVAL;
2797 return -1;
2798 }
sewardj8f253ff2002-05-19 00:13:34 +00002799 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002800 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002801 if (vg_sem->count == 0) {
2802 vg_sem->count++;
2803 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002804 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002805 } else {
2806 vg_sem->count++;
2807 }
2808 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002809 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002810 return 0;
2811}
2812
2813
2814int sem_trywait ( sem_t* sem )
2815{
2816 int ret, res;
2817 vg_sem_t* vg_sem;
2818 ensure_valgrind("sem_trywait");
thughes4dea4ab2004-03-23 19:48:54 +00002819 vg_sem = se_lookup(sem);
2820 if(!vg_sem) {
2821 pthread_error("sem_trywait: semaphore overwritten or not initialized");
2822 *(__errno_location()) = EINVAL;
2823 return -1;
2824 }
sewardj8f253ff2002-05-19 00:13:34 +00002825 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002826 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002827 if (vg_sem->count > 0) {
2828 vg_sem->count--;
2829 ret = 0;
2830 } else {
2831 ret = -1;
sewardj25418ae2003-05-09 23:40:34 +00002832 *(__errno_location()) = EAGAIN;
sewardj8f253ff2002-05-19 00:13:34 +00002833 }
2834 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002835 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002836 return ret;
2837}
2838
2839
2840int sem_getvalue(sem_t* sem, int * sval)
2841{
jseward556c9f82004-01-02 11:39:06 +00002842 int res;
sewardj8f253ff2002-05-19 00:13:34 +00002843 vg_sem_t* vg_sem;
jseward556c9f82004-01-02 11:39:06 +00002844 ensure_valgrind("sem_getvalue");
thughes4dea4ab2004-03-23 19:48:54 +00002845 vg_sem = se_lookup(sem);
2846 if(!vg_sem) {
2847 pthread_error("sem_getvalue: semaphore overwritten or not initialized");
2848 *(__errno_location()) = EINVAL;
2849 return -1;
2850 }
jseward556c9f82004-01-02 11:39:06 +00002851 res = __pthread_mutex_lock(&vg_sem->se_mx);
2852 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002853 *sval = vg_sem->count;
jseward556c9f82004-01-02 11:39:06 +00002854 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2855 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002856 return 0;
2857}
2858
2859
2860int sem_destroy(sem_t * sem)
2861{
sewardj8f253ff2002-05-19 00:13:34 +00002862 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
jseward556c9f82004-01-02 11:39:06 +00002863 vg_sem_t* vg_sem;
2864 int res;
2865 ensure_valgrind("sem_destroy");
thughes4dea4ab2004-03-23 19:48:54 +00002866 vg_sem = se_lookup(sem);
2867 if(!vg_sem) {
2868 pthread_error("sem_destroy: semaphore overwritten or not initialized");
2869 *(__errno_location()) = EINVAL;
2870 return -1;
2871 }
jseward556c9f82004-01-02 11:39:06 +00002872 res = __pthread_mutex_lock(&vg_sem->se_mx);
2873 my_assert(res == 0);
2874 if (vg_sem->waiters > 0)
2875 {
2876 *(__errno_location()) = EBUSY;
2877 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2878 my_assert(res == 0);
2879 return -1;
2880 }
2881 res = pthread_cond_destroy(&vg_sem->se_cv);
2882 my_assert(res == 0);
2883 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2884 my_assert(res == 0);
2885 res = pthread_mutex_destroy(&vg_sem->se_mx);
2886 my_assert(res == 0);
thughes4dea4ab2004-03-23 19:48:54 +00002887 se_free(sem);
sewardj8f253ff2002-05-19 00:13:34 +00002888 return 0;
2889}
2890
sewardj9ad92d92002-10-16 19:45:06 +00002891
2892int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2893{
2894 int res;
2895 vg_sem_t* vg_sem;
2896 ensure_valgrind("sem_timedwait");
thughes4dea4ab2004-03-23 19:48:54 +00002897 vg_sem = se_lookup(sem);
2898 if(!vg_sem) {
2899 pthread_error("sem_timedwait: semaphore overwritten or not initialized");
2900 *(__errno_location()) = EINVAL;
2901 return -1;
2902 }
sewardj9ad92d92002-10-16 19:45:06 +00002903 res = __pthread_mutex_lock(&vg_sem->se_mx);
2904 my_assert(res == 0);
2905 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
jseward556c9f82004-01-02 11:39:06 +00002906 ++vg_sem->waiters;
sewardj9ad92d92002-10-16 19:45:06 +00002907 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
jseward556c9f82004-01-02 11:39:06 +00002908 --vg_sem->waiters;
sewardj9ad92d92002-10-16 19:45:06 +00002909 }
2910 if ( vg_sem->count > 0 ) {
2911 vg_sem->count--;
2912 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2913 my_assert(res == 0 );
2914 return 0;
2915 } else {
2916 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2917 my_assert(res == 0 );
2918 *(__errno_location()) = ETIMEDOUT;
2919 return -1;
2920 }
2921}
2922
sewardj8f253ff2002-05-19 00:13:34 +00002923
2924/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002925 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002926 ------------------------------------------------------------------ */
2927
sewardj2d8b3f02002-06-01 14:14:19 +00002928typedef
2929 struct {
sewardj2d8b3f02002-06-01 14:14:19 +00002930 int prefer_w; /* != 0 --> prefer writer */
2931 int nwait_r; /* # of waiting readers */
2932 int nwait_w; /* # of waiting writers */
2933 pthread_cond_t cv_r; /* for signalling readers */
2934 pthread_cond_t cv_w; /* for signalling writers */
2935 pthread_mutex_t mx;
2936 int status;
2937 /* allowed range for status: >= -1. -1 means 1 writer currently
2938 active, >= 0 means N readers currently active. */
2939 }
2940 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002941
2942
thughes8542e0f2004-10-16 14:49:53 +00002943static pthread_mutex_t rw_new_mx = PTHREAD_MUTEX_INITIALIZER;
sewardja1ac5cb2002-05-27 13:00:05 +00002944
thughes8542e0f2004-10-16 14:49:53 +00002945#define RWLOCK_CHECK_MAGIC 0xb5d17027
sewardja1ac5cb2002-05-27 13:00:05 +00002946
sewardj2d8b3f02002-06-01 14:14:19 +00002947
thughes8542e0f2004-10-16 14:49:53 +00002948static void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
sewardj2d8b3f02002-06-01 14:14:19 +00002949{
2950 int res = 0;
sewardj2d8b3f02002-06-01 14:14:19 +00002951 vg_rwl->prefer_w = 1;
2952 vg_rwl->nwait_r = 0;
2953 vg_rwl->nwait_w = 0;
2954 vg_rwl->status = 0;
2955 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2956 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2957 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002958 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002959}
2960
thughes8542e0f2004-10-16 14:49:53 +00002961static vg_rwlock_t* rw_new ( pthread_rwlock_t* orig )
sewardja1ac5cb2002-05-27 13:00:05 +00002962{
thughes8542e0f2004-10-16 14:49:53 +00002963 int res;
2964 vg_rwlock_t* rwl;
nethercote1f0173b2004-02-28 15:40:36 +00002965 vg_pthread_rwlock_t* vg_orig;
nethercote1f0173b2004-02-28 15:40:36 +00002966 CONVERT(rwlock, orig, vg_orig);
sewardja1ac5cb2002-05-27 13:00:05 +00002967
thughes8542e0f2004-10-16 14:49:53 +00002968 res = __pthread_mutex_lock(&rw_new_mx);
2969 my_assert(res == 0);
2970
2971 rwl = my_malloc(sizeof(vg_rwlock_t));
2972
2973 vg_orig->__vg_rw_writer = rwl;
2974 vg_orig->__vg_rw_read_waiting = (void *)((Addr)rwl ^ RWLOCK_CHECK_MAGIC);
2975
2976 init_vg_rwlock(rwl);
2977 if (vg_orig->__vg_rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
2978 rwl->prefer_w = 0;
2979
2980 res = __pthread_mutex_unlock(&rw_new_mx);
2981 my_assert(res == 0);
2982
2983 return rwl;
sewardja1ac5cb2002-05-27 13:00:05 +00002984}
2985
thughes8542e0f2004-10-16 14:49:53 +00002986static vg_rwlock_t* rw_lookup ( pthread_rwlock_t* orig )
2987{
2988 vg_rwlock_t* rwl;
2989 vg_pthread_rwlock_t* vg_orig;
2990 CONVERT(rwlock, orig, vg_orig);
2991
2992 if (vg_orig->__vg_rw_writer == NULL)
thughesf24712c2004-10-18 23:03:24 +00002993 rwl = rw_new ((pthread_rwlock_t*)vg_orig);
thughes8542e0f2004-10-16 14:49:53 +00002994 else if (((Addr)vg_orig->__vg_rw_writer ^ RWLOCK_CHECK_MAGIC) == (Addr)vg_orig->__vg_rw_read_waiting)
2995 rwl = vg_orig->__vg_rw_writer;
2996 else
2997 rwl = NULL;
2998
2999 return rwl;
3000}
3001
3002static void rw_free ( pthread_rwlock_t* orig )
3003{
3004 int res;
3005 vg_rwlock_t* rwl;
3006 vg_pthread_rwlock_t* vg_orig;
3007 CONVERT(rwlock, orig, vg_orig);
3008
3009 rwl = vg_orig->__vg_rw_writer;
3010
3011 vg_orig->__vg_rw_writer = NULL;
3012 vg_orig->__vg_rw_read_waiting = NULL;
3013
3014 res = __pthread_mutex_unlock(&rwl->mx);
3015 my_assert(res == 0);
3016
3017 res = pthread_cond_destroy(&rwl->cv_w);
3018 res |= pthread_cond_destroy(&rwl->cv_r);
3019 res |= pthread_mutex_destroy(&rwl->mx);
3020 my_assert(res == 0);
3021
3022 my_free(rwl);
3023
3024 return;
3025}
sewardja1ac5cb2002-05-27 13:00:05 +00003026
sewardja1ac5cb2002-05-27 13:00:05 +00003027int pthread_rwlock_init ( pthread_rwlock_t* orig,
3028 const pthread_rwlockattr_t* attr )
3029{
sewardja1ac5cb2002-05-27 13:00:05 +00003030 vg_rwlock_t* rwl;
nethercote1f0173b2004-02-28 15:40:36 +00003031 vg_pthread_rwlock_t* vg_orig;
3032 vg_pthread_rwlockattr_t* vg_attr;
3033 CONVERT(rwlock, orig, vg_orig);
3034 CONVERT(rwlockattr, attr, vg_attr);
3035
sewardja1ac5cb2002-05-27 13:00:05 +00003036 if (0) printf ("pthread_rwlock_init\n");
sewardja1ac5cb2002-05-27 13:00:05 +00003037 /* Install the lock preference; the remapper needs to know it. */
nethercote1f0173b2004-02-28 15:40:36 +00003038 if (vg_attr)
3039 vg_orig->__vg_rw_kind = vg_attr->__vg_lockkind;
thughes8542e0f2004-10-16 14:49:53 +00003040 else
3041 vg_orig->__vg_rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
3042 /* Allocate the shadow */
3043 rwl = rw_new ((pthread_rwlock_t *)vg_orig);
sewardj2d8b3f02002-06-01 14:14:19 +00003044 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003045}
3046
sewardj2d8b3f02002-06-01 14:14:19 +00003047
3048static
3049void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00003050{
sewardj2d8b3f02002-06-01 14:14:19 +00003051 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
3052 rwl->nwait_r--;
3053 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00003054}
3055
sewardj2d8b3f02002-06-01 14:14:19 +00003056
sewardja1ac5cb2002-05-27 13:00:05 +00003057int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
3058{
3059 int res;
3060 vg_rwlock_t* rwl;
nethercote1f0173b2004-02-28 15:40:36 +00003061
sewardja1ac5cb2002-05-27 13:00:05 +00003062 if (0) printf ("pthread_rwlock_rdlock\n");
thughes8542e0f2004-10-16 14:49:53 +00003063 rwl = rw_lookup (orig);
3064 if(!rwl) {
3065 pthread_error("pthread_rwlock_rdlock: lock overwritten or not initialized");
sewardj2d8b3f02002-06-01 14:14:19 +00003066 return EINVAL;
3067 }
thughes8542e0f2004-10-16 14:49:53 +00003068 res = __pthread_mutex_lock(&rwl->mx);
3069 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003070 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00003071 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00003072 rwl->nwait_r++;
3073 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
3074 while (1) {
3075 if (rwl->status == 0) break;
3076 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003077 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003078 }
3079 pthread_cleanup_pop(0);
3080 rwl->nwait_r--;
3081 }
sewardj2d94c112002-06-03 01:25:54 +00003082 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003083 rwl->status++;
3084 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003085 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003086 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003087}
3088
sewardj2d8b3f02002-06-01 14:14:19 +00003089
sewardja1ac5cb2002-05-27 13:00:05 +00003090int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
3091{
3092 int res;
3093 vg_rwlock_t* rwl;
nethercote1f0173b2004-02-28 15:40:36 +00003094
sewardja1ac5cb2002-05-27 13:00:05 +00003095 if (0) printf ("pthread_rwlock_tryrdlock\n");
thughes8542e0f2004-10-16 14:49:53 +00003096 rwl = rw_lookup (orig);
3097 if(!rwl) {
3098 pthread_error("pthread_rwlock_tryrdlock: lock overwritten or not initialized");
sewardj2d8b3f02002-06-01 14:14:19 +00003099 return EINVAL;
3100 }
thughes8542e0f2004-10-16 14:49:53 +00003101 res = __pthread_mutex_lock(&rwl->mx);
3102 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003103 if (rwl->status == -1) {
3104 /* Writer active; we have to give up. */
3105 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003106 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003107 return EBUSY;
3108 }
3109 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00003110 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003111 rwl->status++;
3112 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003113 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003114 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003115}
3116
sewardj2d8b3f02002-06-01 14:14:19 +00003117
3118static
3119void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
3120{
3121 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
3122 rwl->nwait_w--;
3123 pthread_mutex_unlock (&rwl->mx);
3124}
3125
3126
sewardja1ac5cb2002-05-27 13:00:05 +00003127int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
3128{
3129 int res;
3130 vg_rwlock_t* rwl;
nethercote1f0173b2004-02-28 15:40:36 +00003131
sewardja1ac5cb2002-05-27 13:00:05 +00003132 if (0) printf ("pthread_rwlock_wrlock\n");
thughes8542e0f2004-10-16 14:49:53 +00003133 rwl = rw_lookup (orig);
3134 if(!rwl) {
3135 pthread_error("pthread_rwlock_wrlock: lock overwritten or not initialized");
sewardj2d8b3f02002-06-01 14:14:19 +00003136 return EINVAL;
3137 }
thughes8542e0f2004-10-16 14:49:53 +00003138 res = __pthread_mutex_lock(&rwl->mx);
3139 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003140 if (rwl->status != 0) {
3141 rwl->nwait_w++;
3142 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
3143 while (1) {
3144 if (rwl->status == 0) break;
3145 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003146 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003147 }
3148 pthread_cleanup_pop(0);
3149 rwl->nwait_w--;
3150 }
sewardj2d94c112002-06-03 01:25:54 +00003151 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003152 rwl->status = -1;
3153 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003154 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003155 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003156}
3157
sewardj2d8b3f02002-06-01 14:14:19 +00003158
sewardja1ac5cb2002-05-27 13:00:05 +00003159int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
3160{
3161 int res;
3162 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00003163 if (0) printf ("pthread_wrlock_trywrlock\n");
thughes8542e0f2004-10-16 14:49:53 +00003164 rwl = rw_lookup (orig);
3165 if(!rwl) {
3166 pthread_error("pthread_rwlock_trywrlock: lock overwritten or not initialized");
sewardj2d8b3f02002-06-01 14:14:19 +00003167 return EINVAL;
3168 }
thughes8542e0f2004-10-16 14:49:53 +00003169 res = __pthread_mutex_lock(&rwl->mx);
3170 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003171 if (rwl->status != 0) {
3172 /* Reader(s) or a writer active; we have to give up. */
3173 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003174 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003175 return EBUSY;
3176 }
3177 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00003178 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003179 rwl->status = -1;
3180 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003181 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003182 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003183}
3184
sewardj2d8b3f02002-06-01 14:14:19 +00003185
sewardja1ac5cb2002-05-27 13:00:05 +00003186int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
3187{
3188 int res;
3189 vg_rwlock_t* rwl;
3190 if (0) printf ("pthread_rwlock_unlock\n");
thughes8542e0f2004-10-16 14:49:53 +00003191 rwl = rw_lookup (orig);
3192 if(!rwl) {
3193 pthread_error("pthread_rwlock_unlock: lock overwritten or not initialized");
sewardj2d8b3f02002-06-01 14:14:19 +00003194 return EINVAL;
3195 }
thughes8542e0f2004-10-16 14:49:53 +00003196 res = __pthread_mutex_lock(&rwl->mx);
3197 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003198 if (rwl->status == 0) {
3199 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003200 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003201 return EPERM;
3202 }
sewardj2d94c112002-06-03 01:25:54 +00003203 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003204 if (rwl->status == -1) {
3205 rwl->status = 0;
3206 } else {
sewardj2d94c112002-06-03 01:25:54 +00003207 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003208 rwl->status--;
3209 }
3210
sewardj2d94c112002-06-03 01:25:54 +00003211 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003212
3213 if (rwl->prefer_w) {
3214
3215 /* Favour waiting writers, if any. */
3216 if (rwl->nwait_w > 0) {
3217 /* Writer(s) are waiting. */
3218 if (rwl->status == 0) {
3219 /* We can let a writer in. */
3220 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00003221 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003222 } else {
3223 /* There are still readers active. Do nothing; eventually
3224 they will disappear, at which point a writer will be
3225 admitted. */
3226 }
3227 }
3228 else
3229 /* No waiting writers. */
3230 if (rwl->nwait_r > 0) {
3231 /* Let in a waiting reader. */
3232 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00003233 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003234 }
3235
3236 } else {
3237
3238 /* Favour waiting readers, if any. */
3239 if (rwl->nwait_r > 0) {
3240 /* Reader(s) are waiting; let one in. */
3241 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00003242 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003243 }
3244 else
3245 /* No waiting readers. */
3246 if (rwl->nwait_w > 0 && rwl->status == 0) {
3247 /* We have waiting writers and no active readers; let a
3248 writer in. */
3249 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00003250 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003251 }
3252 }
3253
3254 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003255 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003256 return 0;
3257}
3258
3259
3260int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
3261{
3262 int res;
3263 vg_rwlock_t* rwl;
3264 if (0) printf ("pthread_rwlock_destroy\n");
thughes8542e0f2004-10-16 14:49:53 +00003265 rwl = rw_lookup (orig);
3266 if(!rwl) {
3267 pthread_error("pthread_rwlock_destroy: lock overwritten or not initialized");
sewardj2d8b3f02002-06-01 14:14:19 +00003268 return EINVAL;
3269 }
thughes8542e0f2004-10-16 14:49:53 +00003270 res = __pthread_mutex_lock(&rwl->mx);
3271 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003272 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
3273 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003274 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003275 return EBUSY;
3276 }
thughes8542e0f2004-10-16 14:49:53 +00003277 rw_free (orig);
sewardj2d8b3f02002-06-01 14:14:19 +00003278 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003279}
3280
3281
sewardj47e4e312002-06-18 09:24:34 +00003282/* Copied directly from LinuxThreads. */
3283int
3284pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
3285{
nethercote1f0173b2004-02-28 15:40:36 +00003286 vg_pthread_rwlockattr_t* vg_attr;
3287 CONVERT(rwlockattr, attr, vg_attr);
3288 vg_attr->__vg_lockkind = 0;
3289 vg_attr->__vg_pshared = PTHREAD_PROCESS_PRIVATE;
3290 return 0;
sewardj47e4e312002-06-18 09:24:34 +00003291}
3292
sewardjfe18eb82002-07-13 12:58:44 +00003293/* Copied directly from LinuxThreads. */
3294int
sewardj5706bfa2002-12-08 23:42:17 +00003295pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
3296{
3297 return 0;
3298}
3299
3300/* Copied directly from LinuxThreads. */
3301int
sewardjfe18eb82002-07-13 12:58:44 +00003302pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
3303{
nethercote1f0173b2004-02-28 15:40:36 +00003304 vg_pthread_rwlockattr_t* vg_attr;
3305 CONVERT(rwlockattr, attr, vg_attr);
sewardjfe18eb82002-07-13 12:58:44 +00003306
nethercote1f0173b2004-02-28 15:40:36 +00003307 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
3308 return EINVAL;
sewardjfe18eb82002-07-13 12:58:44 +00003309
nethercote1f0173b2004-02-28 15:40:36 +00003310 /* For now it is not possible to shared a conditional variable. */
3311 if (pshared != PTHREAD_PROCESS_PRIVATE)
3312 return ENOSYS;
sewardjfe18eb82002-07-13 12:58:44 +00003313
nethercote1f0173b2004-02-28 15:40:36 +00003314 vg_attr->__vg_pshared = pshared;
3315
3316 return 0;
sewardjfe18eb82002-07-13 12:58:44 +00003317}
3318
sewardj47e4e312002-06-18 09:24:34 +00003319
sewardj262b5be2003-04-26 21:19:53 +00003320
3321/* ---------------------------------------------------------------------
jsgf855d93d2003-10-13 22:26:55 +00003322 Manage the allocation and use of RT signals. The Valgrind core
3323 uses one. glibc needs us to implement this to make RT signals
3324 work; things just seem to crash if we don't.
sewardj262b5be2003-04-26 21:19:53 +00003325 ------------------------------------------------------------------ */
sewardj262b5be2003-04-26 21:19:53 +00003326int __libc_current_sigrtmin (void)
3327{
fitzhardinge98abfc72003-12-16 02:05:15 +00003328 int res;
3329
3330 VALGRIND_MAGIC_SEQUENCE(res, 0,
3331 VG_USERREQ__GET_SIGRT_MIN,
3332 0, 0, 0, 0);
3333
3334 return res;
sewardj262b5be2003-04-26 21:19:53 +00003335}
3336
3337int __libc_current_sigrtmax (void)
3338{
fitzhardinge98abfc72003-12-16 02:05:15 +00003339 int res;
3340
3341 VALGRIND_MAGIC_SEQUENCE(res, 0,
3342 VG_USERREQ__GET_SIGRT_MAX,
3343 0, 0, 0, 0);
3344
3345 return res;
sewardj262b5be2003-04-26 21:19:53 +00003346}
3347
3348int __libc_allocate_rtsig (int high)
3349{
fitzhardinge98abfc72003-12-16 02:05:15 +00003350 int res;
3351
3352 VALGRIND_MAGIC_SEQUENCE(res, 0,
3353 VG_USERREQ__ALLOC_RTSIG,
3354 high, 0, 0, 0);
3355
3356 return res;
sewardj262b5be2003-04-26 21:19:53 +00003357}
3358
sewardjd5bef572002-10-23 21:49:33 +00003359/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00003360 B'stard.
3361 ------------------------------------------------------------------ */
sewardj5905fae2002-04-26 13:25:00 +00003362strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
thughese321d492004-10-17 15:00:20 +00003363strong_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock)
sewardj5905fae2002-04-26 13:25:00 +00003364strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
3365strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
3366strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
3367 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
thughescca97252004-10-13 18:29:54 +00003368 weak_alias(__pthread_mutexattr_gettype, pthread_mutexattr_gettype)
sewardjf0995512003-07-06 01:29:49 +00003369 weak_alias(__pthread_mutexattr_setpshared, pthread_mutexattr_setpshared)
sewardj5905fae2002-04-26 13:25:00 +00003370strong_alias(__pthread_mutex_init, pthread_mutex_init)
3371strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
3372strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
3373strong_alias(__pthread_once, pthread_once)
3374strong_alias(__pthread_atfork, pthread_atfork)
3375strong_alias(__pthread_key_create, pthread_key_create)
3376strong_alias(__pthread_getspecific, pthread_getspecific)
3377strong_alias(__pthread_setspecific, pthread_setspecific)
3378
sewardjd529a442002-05-04 19:49:21 +00003379#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00003380strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00003381#endif
3382
sewardj5905fae2002-04-26 13:25:00 +00003383weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00003384weak_alias(__vfork, vfork)
sewardjf0b06452002-06-04 08:38:04 +00003385weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00003386
3387/*--------------------------------------------------*/
3388
sewardj5905fae2002-04-26 13:25:00 +00003389weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00003390weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00003391weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00003392
sewardja1ac5cb2002-05-27 13:00:05 +00003393weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
3394weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
3395weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
3396weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
3397
sewardj060b04f2002-04-26 21:01:13 +00003398
njnff28df92003-10-12 17:26:04 +00003399#ifndef __UCLIBC__
fitzhardinge47735af2004-01-21 01:27:27 +00003400/* These are called as part of stdio to lock the FILE structure for MT
3401 programs. Unfortunately, the lock is not always a pthreads lock -
3402 the NPTL version uses a lighter-weight lock which uses futex
3403 directly (and uses a structure which is smaller than
3404 pthread_mutex). So basically, this is completely broken on recent
3405 glibcs. */
3406
sewardj3b13f0e2002-04-25 20:17:29 +00003407#undef _IO_flockfile
3408void _IO_flockfile ( _IO_FILE * file )
3409{
sewardj853f55d2002-04-26 00:27:53 +00003410 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003411}
fitzhardinge47735af2004-01-21 01:27:27 +00003412strong_alias(_IO_flockfile, __flockfile);
sewardj5905fae2002-04-26 13:25:00 +00003413weak_alias(_IO_flockfile, flockfile);
3414
sewardj3b13f0e2002-04-25 20:17:29 +00003415#undef _IO_funlockfile
3416void _IO_funlockfile ( _IO_FILE * file )
3417{
sewardj853f55d2002-04-26 00:27:53 +00003418 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003419}
fitzhardinge47735af2004-01-21 01:27:27 +00003420strong_alias(_IO_funlockfile, __funlockfile);
sewardj5905fae2002-04-26 13:25:00 +00003421weak_alias(_IO_funlockfile, funlockfile);
njnff28df92003-10-12 17:26:04 +00003422#endif
sewardj5905fae2002-04-26 13:25:00 +00003423
sewardj3b13f0e2002-04-25 20:17:29 +00003424
sewardjd4f2c712002-04-30 10:20:10 +00003425/* This doesn't seem to be needed to simulate libpthread.so's external
3426 interface, but many people complain about its absence. */
3427
3428strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
3429weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00003430
sewardj439d45e2002-05-03 20:43:10 +00003431/*--------------------------------------------------------------------*/
nethercote691e8ee2004-10-19 11:38:48 +00003432/*--- end ---*/
sewardj439d45e2002-05-03 20:43:10 +00003433/*--------------------------------------------------------------------*/