blob: ee194fc1106455d50a28938cd1dd63fbd1b20bf8 [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
njn0e1b5142003-04-15 14:58:06 +000011 Copyright (C) 2000-2003 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
sewardje12a45f2003-03-15 20:03:33 +000055/* Sidestep the normal check which disallows using valgrind.h
56 directly. */
57#define __VALGRIND_SOMESKIN_H
sewardje663cb92002-04-12 10:26:32 +000058#include "valgrind.h" /* For the request-passing mechanism */
sewardje12a45f2003-03-15 20:03:33 +000059
sewardje663cb92002-04-12 10:26:32 +000060#include "vg_include.h" /* For the VG_USERREQ__* constants */
61
sewardja1ac5cb2002-05-27 13:00:05 +000062#define __USE_UNIX98
63#include <sys/types.h>
64#include <pthread.h>
65#undef __USE_UNIX98
66
sewardje663cb92002-04-12 10:26:32 +000067#include <unistd.h>
68#include <string.h>
sewardj2a1dcce2002-04-22 12:45:25 +000069#ifdef GLIBC_2_1
70#include <sys/time.h>
71#endif
sewardjf912dfc2002-11-13 21:51:10 +000072#include <sys/stat.h>
73#include <sys/poll.h>
sewardj2d94c112002-06-03 01:25:54 +000074#include <stdio.h>
75
sewardj705d3cb2002-05-23 13:13:12 +000076
77/* ---------------------------------------------------------------------
78 Forwardses.
79 ------------------------------------------------------------------ */
80
sewardj11f0bb42003-04-26 20:11:15 +000081#define WEAK __attribute__((weak))
82
sewardj705d3cb2002-05-23 13:13:12 +000083
sewardj9a2224b2002-06-19 10:17:40 +000084static
sewardj08c7f012002-10-07 23:56:55 +000085int my_do_syscall1 ( int syscallno, int arg1 );
86
87static
sewardj9a2224b2002-06-19 10:17:40 +000088int my_do_syscall2 ( int syscallno,
89 int arg1, int arg2 );
90
sewardj08c7f012002-10-07 23:56:55 +000091static
92int my_do_syscall3 ( int syscallno,
93 int arg1, int arg2, int arg3 );
94
sewardjfd7747b2002-12-01 10:25:53 +000095static
96__inline__
97int is_kerror ( int res )
98{
99 if (res >= -4095 && res <= -1)
100 return 1;
101 else
102 return 0;
103}
104
sewardj08c7f012002-10-07 23:56:55 +0000105
106#ifdef GLIBC_2_3
107 /* kludge by JRS (not from glibc) ... */
108 typedef void* __locale_t;
109
110 /* Copied from locale/locale.h in glibc-2.2.93 sources */
111 /* This value can be passed to `uselocale' and may be returned by
112 it. Passing this value to any other function has undefined
113 behavior. */
114# define LC_GLOBAL_LOCALE ((__locale_t) -1L)
115 extern __locale_t __uselocale ( __locale_t );
116#endif
117
sewardj00a66b12002-10-12 16:42:35 +0000118static
119void init_libc_tsd_keys ( void );
120
sewardj705d3cb2002-05-23 13:13:12 +0000121
sewardje663cb92002-04-12 10:26:32 +0000122/* ---------------------------------------------------------------------
123 Helpers. We have to be pretty self-sufficient.
124 ------------------------------------------------------------------ */
125
sewardj436e0582002-04-26 14:31:40 +0000126/* Number of times any given error message is printed. */
127#define N_MOANS 3
128
sewardj45b4b372002-04-16 22:50:32 +0000129/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
130 Returns 0 (none) if not running on Valgrind. */
131static
132int get_pt_trace_level ( void )
133{
134 int res;
135 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
136 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
137 0, 0, 0, 0);
138 return res;
139}
140
sewardje663cb92002-04-12 10:26:32 +0000141static
sewardj2d94c112002-06-03 01:25:54 +0000142void my_exit ( int arg )
sewardje663cb92002-04-12 10:26:32 +0000143{
sewardj08c7f012002-10-07 23:56:55 +0000144 my_do_syscall1(__NR_exit, arg);
145 /*NOTREACHED*/
sewardje663cb92002-04-12 10:26:32 +0000146}
147
sewardje0cfe2a2002-11-30 14:04:45 +0000148/* Apparently unused.
sewardj08c7f012002-10-07 23:56:55 +0000149static
150void my_write ( int fd, const void *buf, int count )
151{
152 my_do_syscall3(__NR_write, fd, (int)buf, count );
153}
sewardje0cfe2a2002-11-30 14:04:45 +0000154*/
sewardje663cb92002-04-12 10:26:32 +0000155
sewardj68b2dd92002-05-10 21:03:56 +0000156/* We need this guy -- it's in valgrind.so. */
157extern void VG_(startup) ( void );
158
159
160/* Just start up Valgrind if it's not already going. VG_(startup)()
161 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000162static __inline__
sewardje663cb92002-04-12 10:26:32 +0000163void ensure_valgrind ( char* caller )
164{
sewardj68b2dd92002-05-10 21:03:56 +0000165 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000166}
167
sewardjbea1caa2002-05-10 23:20:58 +0000168/* While we're at it ... hook our own startup function into this
169 game. */
170__asm__ (
171 ".section .init\n"
172 "\tcall vgPlain_startup"
173);
174
sewardje663cb92002-04-12 10:26:32 +0000175
176static
sewardj3b5d8862002-04-20 13:53:23 +0000177__attribute__((noreturn))
daywalker3222e0a2003-09-18 01:39:50 +0000178void barf ( const char* str )
sewardje663cb92002-04-12 10:26:32 +0000179{
sewardj69a72a52002-11-03 13:41:41 +0000180 char buf[1000];
daywalker3222e0a2003-09-18 01:39:50 +0000181 strcpy(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000182 strcat(buf, str);
183 strcat(buf, "\n\n");
njn4c791212003-05-02 17:53:54 +0000184 VALGRIND_NON_SIMD_CALL2(VG_(message), Vg_UserMsg, buf);
sewardj2d94c112002-06-03 01:25:54 +0000185 my_exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000186 /* We have to persuade gcc into believing this doesn't return. */
187 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000188}
189
190
sewardj69a72a52002-11-03 13:41:41 +0000191static void cat_n_send ( char* pre, char* msg )
sewardj2a3d28c2002-04-14 13:27:00 +0000192{
sewardj69a72a52002-11-03 13:41:41 +0000193 char buf[1000];
sewardj436e0582002-04-26 14:31:40 +0000194 if (get_pt_trace_level() >= 0) {
sewardj69a72a52002-11-03 13:41:41 +0000195 snprintf(buf, sizeof(buf), "%s%s", pre, msg );
196 buf[sizeof(buf)-1] = '\0';
njn4c791212003-05-02 17:53:54 +0000197 VALGRIND_NON_SIMD_CALL2(VG_(message), Vg_UserMsg, buf);
sewardj45b4b372002-04-16 22:50:32 +0000198 }
sewardj2a3d28c2002-04-14 13:27:00 +0000199}
200
sewardj69a72a52002-11-03 13:41:41 +0000201static void ignored ( char* msg )
202{
203 cat_n_send ( "valgrind's libpthread.so: IGNORED call to: ", msg );
204}
205
206
sewardj30671ff2002-04-21 00:13:57 +0000207static void kludged ( char* msg )
208{
sewardj69a72a52002-11-03 13:41:41 +0000209 cat_n_send ( "valgrind's libpthread.so: KLUDGED call to: ", msg );
sewardj439d45e2002-05-03 20:43:10 +0000210}
211
sewardj69a72a52002-11-03 13:41:41 +0000212
sewardjccef2e62002-05-29 19:26:32 +0000213__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000214void vgPlain_unimp ( char* what )
215{
sewardj69a72a52002-11-03 13:41:41 +0000216 cat_n_send (
217 "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ", what );
sewardj3b13f0e2002-04-25 20:17:29 +0000218 barf("Please report this bug to me at: jseward@acm.org");
219}
220
sewardje663cb92002-04-12 10:26:32 +0000221
sewardj457cc472002-06-03 23:13:47 +0000222static
daywalker3222e0a2003-09-18 01:39:50 +0000223void my_assert_fail ( const Char* expr, const Char* file, Int line, const Char* fn )
sewardj2d94c112002-06-03 01:25:54 +0000224{
sewardj69a72a52002-11-03 13:41:41 +0000225 char buf[1000];
sewardj2d94c112002-06-03 01:25:54 +0000226 static Bool entered = False;
227 if (entered)
228 my_exit(2);
229 entered = True;
sewardj69a72a52002-11-03 13:41:41 +0000230 sprintf(buf, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
231 "valgrind", file, line, fn, expr );
232 cat_n_send ( "", buf );
233 sprintf(buf, "Please report this bug to me at: %s\n\n",
234 VG_EMAIL_ADDR);
235 cat_n_send ( "", buf );
sewardj2d94c112002-06-03 01:25:54 +0000236 my_exit(1);
237}
238
239#define MY__STRING(__str) #__str
240
241#define my_assert(expr) \
242 ((void) ((expr) ? 0 : \
243 (my_assert_fail (MY__STRING(expr), \
244 __FILE__, __LINE__, \
245 __PRETTY_FUNCTION__), 0)))
246
sewardj00a66b12002-10-12 16:42:35 +0000247static
248void my_free ( void* ptr )
249{
250 int res;
251 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
252 VG_USERREQ__FREE, ptr, 0, 0, 0);
253 my_assert(res == 0);
254}
255
256
257static
258void* my_malloc ( int nbytes )
259{
260 void* res;
261 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
262 VG_USERREQ__MALLOC, nbytes, 0, 0, 0);
263 my_assert(res != (void*)0);
264 return res;
265}
266
267
sewardj2d94c112002-06-03 01:25:54 +0000268
sewardje663cb92002-04-12 10:26:32 +0000269/* ---------------------------------------------------------------------
270 Pass pthread_ calls to Valgrind's request mechanism.
271 ------------------------------------------------------------------ */
272
sewardjf8f819e2002-04-17 23:21:37 +0000273#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000274#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000275
sewardja1ac5cb2002-05-27 13:00:05 +0000276
sewardjf8f819e2002-04-17 23:21:37 +0000277/* ---------------------------------------------------
sewardj4dced352002-06-04 22:54:20 +0000278 Ummm ..
279 ------------------------------------------------ */
280
281static
282void pthread_error ( const char* msg )
283{
284 int res;
285 VALGRIND_MAGIC_SEQUENCE(res, 0,
286 VG_USERREQ__PTHREAD_ERROR,
287 msg, 0, 0, 0);
288}
289
290
291/* ---------------------------------------------------
sewardj00a66b12002-10-12 16:42:35 +0000292 Here so it can be inlined without complaint.
293 ------------------------------------------------ */
294
295__inline__
296pthread_t pthread_self(void)
297{
298 int tid;
299 ensure_valgrind("pthread_self");
300 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
301 VG_USERREQ__PTHREAD_GET_THREADID,
302 0, 0, 0, 0);
303 if (tid < 1 || tid >= VG_N_THREADS)
304 barf("pthread_self: invalid ThreadId");
305 return tid;
306}
307
308
309/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000310 THREAD ATTRIBUTES
311 ------------------------------------------------ */
312
sewardj6af4b5d2002-04-16 04:40:49 +0000313int pthread_attr_init(pthread_attr_t *attr)
314{
sewardj7989d0c2002-05-28 11:00:01 +0000315 /* Just initialise the fields which we might look at. */
316 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj111b14c2002-10-20 16:22:57 +0000317 /* Linuxthreads sets this field to the value __getpagesize(), so I
318 guess the following is OK. */
319 attr->__guardsize = VKI_BYTES_PER_PAGE; return 0;
sewardj6af4b5d2002-04-16 04:40:49 +0000320}
321
322int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
323{
sewardj7989d0c2002-05-28 11:00:01 +0000324 if (detachstate != PTHREAD_CREATE_JOINABLE
sewardj4dced352002-06-04 22:54:20 +0000325 && detachstate != PTHREAD_CREATE_DETACHED) {
326 pthread_error("pthread_attr_setdetachstate: "
327 "detachstate is invalid");
sewardj7989d0c2002-05-28 11:00:01 +0000328 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000329 }
sewardj7989d0c2002-05-28 11:00:01 +0000330 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000331 return 0;
332}
333
njn25e49d8e72002-09-23 09:36:25 +0000334int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
335{
336 *detachstate = attr->__detachstate;
337 return 0;
338}
339
sewardj30671ff2002-04-21 00:13:57 +0000340int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
341{
sewardj436e0582002-04-26 14:31:40 +0000342 static int moans = N_MOANS;
343 if (moans-- > 0)
344 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000345 return 0;
346}
sewardj6af4b5d2002-04-16 04:40:49 +0000347
sewardj11f0bb42003-04-26 20:11:15 +0000348WEAK
sewardj0286dd52002-05-16 20:51:15 +0000349int pthread_attr_setstacksize (pthread_attr_t *__attr,
350 size_t __stacksize)
351{
sewardja18e2102002-05-18 10:43:22 +0000352 size_t limit;
sewardj3d7c8d62002-06-04 20:59:16 +0000353 char buf[1024];
sewardj0286dd52002-05-16 20:51:15 +0000354 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000355 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
356 - 1000; /* paranoia */
357 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000358 return 0;
sewardj3d7c8d62002-06-04 20:59:16 +0000359 snprintf(buf, sizeof(buf), "pthread_attr_setstacksize: "
360 "requested size %d >= VG_PTHREAD_STACK_SIZE\n "
361 "edit vg_include.h and rebuild.", __stacksize);
362 buf[sizeof(buf)-1] = '\0'; /* Make sure it is zero terminated */
363 barf(buf);
sewardj0286dd52002-05-16 20:51:15 +0000364}
365
366
sewardj30671ff2002-04-21 00:13:57 +0000367/* This is completely bogus. */
368int pthread_attr_getschedparam(const pthread_attr_t *attr,
369 struct sched_param *param)
370{
sewardj436e0582002-04-26 14:31:40 +0000371 static int moans = N_MOANS;
372 if (moans-- > 0)
373 kludged("pthread_attr_getschedparam");
sewardj3e909ce2002-06-03 13:27:15 +0000374# ifdef HAVE_SCHED_PRIORITY
sewardj72d58482002-04-24 02:20:20 +0000375 if (param) param->sched_priority = 0; /* who knows */
376# else
sewardj30671ff2002-04-21 00:13:57 +0000377 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000378# endif
sewardj30671ff2002-04-21 00:13:57 +0000379 return 0;
380}
381
382int pthread_attr_setschedparam(pthread_attr_t *attr,
383 const struct sched_param *param)
384{
sewardj436e0582002-04-26 14:31:40 +0000385 static int moans = N_MOANS;
386 if (moans-- > 0)
387 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000388 return 0;
389}
390
391int pthread_attr_destroy(pthread_attr_t *attr)
392{
sewardj436e0582002-04-26 14:31:40 +0000393 static int moans = N_MOANS;
394 if (moans-- > 0)
395 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000396 return 0;
397}
sewardjf8f819e2002-04-17 23:21:37 +0000398
sewardj0d844232002-06-02 09:29:31 +0000399/* These are no-ops, as with LinuxThreads. */
400int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
401{
402 ensure_valgrind("pthread_attr_setscope");
403 if (scope == PTHREAD_SCOPE_SYSTEM)
404 return 0;
sewardj4dced352002-06-04 22:54:20 +0000405 pthread_error("pthread_attr_setscope: "
406 "invalid or unsupported scope");
sewardj0d844232002-06-02 09:29:31 +0000407 if (scope == PTHREAD_SCOPE_PROCESS)
408 return ENOTSUP;
409 return EINVAL;
410}
411
412int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
413{
414 ensure_valgrind("pthread_attr_setscope");
415 if (scope)
416 *scope = PTHREAD_SCOPE_SYSTEM;
417 return 0;
418}
419
sewardj64039bb2002-06-03 00:58:18 +0000420
421/* Pretty bogus. Avoid if possible. */
422int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
423{
424 int detached;
425 size_t limit;
426 ensure_valgrind("pthread_getattr_np");
427 kludged("pthread_getattr_np");
428 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
429 - 1000; /* paranoia */
430 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
431 attr->__schedpolicy = SCHED_OTHER;
432 attr->__schedparam.sched_priority = 0;
433 attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
434 attr->__scope = PTHREAD_SCOPE_SYSTEM;
435 attr->__guardsize = VKI_BYTES_PER_PAGE;
436 attr->__stackaddr = NULL;
437 attr->__stackaddr_set = 0;
438 attr->__stacksize = limit;
439 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
440 VG_USERREQ__SET_OR_GET_DETACH,
441 2 /* get */, thread, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000442 my_assert(detached == 0 || detached == 1);
sewardj64039bb2002-06-03 00:58:18 +0000443 if (detached)
444 attr->__detachstate = PTHREAD_CREATE_DETACHED;
445 return 0;
446}
447
448
449/* Bogus ... */
sewardj11f0bb42003-04-26 20:11:15 +0000450WEAK
sewardj64039bb2002-06-03 00:58:18 +0000451int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
452 void ** stackaddr )
453{
454 ensure_valgrind("pthread_attr_getstackaddr");
455 kludged("pthread_attr_getstackaddr");
456 if (stackaddr)
457 *stackaddr = NULL;
458 return 0;
459}
460
461/* Not bogus (!) */
sewardj11f0bb42003-04-26 20:11:15 +0000462WEAK
sewardj64039bb2002-06-03 00:58:18 +0000463int pthread_attr_getstacksize ( const pthread_attr_t * _attr,
464 size_t * __stacksize )
465{
466 size_t limit;
467 ensure_valgrind("pthread_attr_getstacksize");
468 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
469 - 1000; /* paranoia */
470 if (__stacksize)
471 *__stacksize = limit;
472 return 0;
473}
474
sewardja3be12f2002-06-17 12:19:44 +0000475int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
476{
477 if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
478 return EINVAL;
479 attr->__schedpolicy = policy;
480 return 0;
481}
482
483int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
484{
485 *policy = attr->__schedpolicy;
486 return 0;
487}
488
489
sewardj111b14c2002-10-20 16:22:57 +0000490/* This is completely bogus. We reject all attempts to change it from
491 VKI_BYTES_PER_PAGE. I don't have a clue what it's for so it seems
492 safest to be paranoid. */
sewardj11f0bb42003-04-26 20:11:15 +0000493WEAK
sewardj111b14c2002-10-20 16:22:57 +0000494int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
495{
496 static int moans = N_MOANS;
497
498 if (guardsize == VKI_BYTES_PER_PAGE)
499 return 0;
500
501 if (moans-- > 0)
502 ignored("pthread_attr_setguardsize: ignoring guardsize != 4096");
503
504 return 0;
505}
506
507/* A straight copy of the LinuxThreads code. */
sewardj11f0bb42003-04-26 20:11:15 +0000508WEAK
sewardj111b14c2002-10-20 16:22:57 +0000509int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
510{
511 *guardsize = attr->__guardsize;
512 return 0;
513}
514
sewardjab2e1232002-12-26 12:16:11 +0000515/* Again, like LinuxThreads. */
516
517static int concurrency_current_level = 0;
518
sewardj11f0bb42003-04-26 20:11:15 +0000519WEAK
sewardjb34e4db2002-12-08 23:51:32 +0000520int pthread_setconcurrency(int new_level)
521{
522 if (new_level < 0)
523 return EINVAL;
sewardjab2e1232002-12-26 12:16:11 +0000524 else {
525 concurrency_current_level = new_level;
sewardjb34e4db2002-12-08 23:51:32 +0000526 return 0;
sewardjab2e1232002-12-26 12:16:11 +0000527 }
sewardjb34e4db2002-12-08 23:51:32 +0000528}
529
sewardj11f0bb42003-04-26 20:11:15 +0000530WEAK
sewardjab2e1232002-12-26 12:16:11 +0000531int pthread_getconcurrency(void)
532{
533 return concurrency_current_level;
534}
535
536
sewardj111b14c2002-10-20 16:22:57 +0000537
sewardj20917d82002-05-28 01:36:45 +0000538/* ---------------------------------------------------
539 Helper functions for running a thread
540 and for clearing up afterwards.
541 ------------------------------------------------ */
542
543/* All exiting threads eventually pass through here, bearing the
544 return value, or PTHREAD_CANCELED, in ret_val. */
545static
546__attribute__((noreturn))
547void thread_exit_wrapper ( void* ret_val )
548{
sewardj870497a2002-05-29 01:06:47 +0000549 int detached, res;
550 CleanupEntry cu;
551 pthread_key_t key;
sewardj00a66b12002-10-12 16:42:35 +0000552 void** specifics_ptr;
sewardj870497a2002-05-29 01:06:47 +0000553
sewardj20917d82002-05-28 01:36:45 +0000554 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000555 while (1) {
556 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
557 VG_USERREQ__CLEANUP_POP,
558 &cu, 0, 0, 0);
559 if (res == -1) break; /* stack empty */
sewardj2d94c112002-06-03 01:25:54 +0000560 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000561 if (0) printf("running exit cleanup handler");
562 cu.fn ( cu.arg );
563 }
564
sewardj870497a2002-05-29 01:06:47 +0000565 /* Run this thread's key finalizers. Really this should be run
566 PTHREAD_DESTRUCTOR_ITERATIONS times. */
567 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
568 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
569 VG_USERREQ__GET_KEY_D_AND_S,
570 key, &cu, 0, 0 );
571 if (res == 0) {
572 /* valid key */
573 if (cu.fn && cu.arg)
574 cu.fn /* destructor for key */
575 ( cu.arg /* specific for key for this thread */ );
576 continue;
577 }
sewardj2d94c112002-06-03 01:25:54 +0000578 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000579 }
sewardj20917d82002-05-28 01:36:45 +0000580
sewardj00a66b12002-10-12 16:42:35 +0000581 /* Free up my specifics space, if any. */
582 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
583 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
584 pthread_self(), 0, 0, 0);
585 my_assert(specifics_ptr != (void**)3);
586 my_assert(specifics_ptr != (void**)1); /* 1 means invalid thread */
587 if (specifics_ptr != NULL)
588 my_free(specifics_ptr);
589
sewardj20917d82002-05-28 01:36:45 +0000590 /* Decide on my final disposition. */
591 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
592 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000593 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000594 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000595
596 if (detached) {
597 /* Detached; I just quit right now. */
598 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
599 VG_USERREQ__QUIT, 0, 0, 0, 0);
600 } else {
601 /* Not detached; so I wait for a joiner. */
602 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
603 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
604 }
605 /* NOTREACHED */
606 barf("thread_exit_wrapper: still alive?!");
607}
608
609
610/* This function is a wrapper function for running a thread. It runs
611 the root function specified in pthread_create, and then, should the
612 root function return a value, it arranges to run the thread's
613 cleanup handlers and exit correctly. */
614
sewardj728a5272002-06-20 10:25:37 +0000615/* Struct used to convey info from pthread_create to thread_wrapper.
616 Must be careful not to pass to the child thread any pointers to
617 objects which might be on the parent's stack. */
sewardj20917d82002-05-28 01:36:45 +0000618typedef
619 struct {
sewardj728a5272002-06-20 10:25:37 +0000620 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000621 void* (*root_fn) ( void* );
622 void* arg;
623 }
624 NewThreadInfo;
625
626
627/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
628 not return. Note that this runs in the new thread, not the
629 parent. */
630static
631__attribute__((noreturn))
632void thread_wrapper ( NewThreadInfo* info )
633{
sewardj728a5272002-06-20 10:25:37 +0000634 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000635 void* (*root_fn) ( void* );
636 void* arg;
637 void* ret_val;
638
sewardj728a5272002-06-20 10:25:37 +0000639 attr__detachstate = info->attr__detachstate;
640 root_fn = info->root_fn;
641 arg = info->arg;
sewardj20917d82002-05-28 01:36:45 +0000642
sewardj20917d82002-05-28 01:36:45 +0000643 /* Free up the arg block that pthread_create malloced. */
sewardj00a66b12002-10-12 16:42:35 +0000644 my_free(info);
sewardj20917d82002-05-28 01:36:45 +0000645
sewardj7989d0c2002-05-28 11:00:01 +0000646 /* Minimally observe the attributes supplied. */
sewardj728a5272002-06-20 10:25:37 +0000647 if (attr__detachstate != PTHREAD_CREATE_DETACHED
648 && attr__detachstate != PTHREAD_CREATE_JOINABLE)
649 pthread_error("thread_wrapper: invalid attr->__detachstate");
650 if (attr__detachstate == PTHREAD_CREATE_DETACHED)
651 pthread_detach(pthread_self());
sewardj7989d0c2002-05-28 11:00:01 +0000652
sewardj00a66b12002-10-12 16:42:35 +0000653# ifdef GLIBC_2_3
654 /* Set this thread's locale to the global (default) locale. A hack
655 in support of glibc-2.3. This does the biz for the all new
656 threads; the root thread is done with a horrible hack in
657 init_libc_tsd_keys() below.
658 */
659 __uselocale(LC_GLOBAL_LOCALE);
660# endif
661
sewardj20917d82002-05-28 01:36:45 +0000662 /* The root function might not return. But if it does we simply
663 move along to thread_exit_wrapper. All other ways out for the
664 thread (cancellation, or calling pthread_exit) lead there
665 too. */
666 ret_val = root_fn(arg);
667 thread_exit_wrapper(ret_val);
668 /* NOTREACHED */
669}
670
671
sewardjf8f819e2002-04-17 23:21:37 +0000672/* ---------------------------------------------------
673 THREADs
674 ------------------------------------------------ */
675
sewardjc91a4ff2003-07-11 00:12:58 +0000676static void __valgrind_pthread_yield ( void )
sewardjff42d1d2002-05-22 13:17:31 +0000677{
678 int res;
679 ensure_valgrind("pthread_yield");
680 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
681 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
sewardjc91a4ff2003-07-11 00:12:58 +0000682}
683
684WEAK
685int pthread_yield ( void )
686{
687 __valgrind_pthread_yield();
sewardjff42d1d2002-05-22 13:17:31 +0000688 return 0;
689}
690
691
sewardj6072c362002-04-19 14:40:57 +0000692int pthread_equal(pthread_t thread1, pthread_t thread2)
693{
694 return thread1 == thread2 ? 1 : 0;
695}
696
697
sewardj20917d82002-05-28 01:36:45 +0000698/* Bundle up the args into a malloc'd block and create a new thread
699 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000700int
sewardj1462c8b2002-07-24 09:41:52 +0000701pthread_create (pthread_t *__restrict __thredd,
sewardje663cb92002-04-12 10:26:32 +0000702 __const pthread_attr_t *__restrict __attr,
703 void *(*__start_routine) (void *),
704 void *__restrict __arg)
705{
sewardj20917d82002-05-28 01:36:45 +0000706 int tid_child;
707 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000708
sewardj20917d82002-05-28 01:36:45 +0000709 ensure_valgrind("pthread_create");
710
sewardj00a66b12002-10-12 16:42:35 +0000711 /* make sure the tsd keys, and hence locale info, are initialised
712 before we get into complications making new threads. */
713 init_libc_tsd_keys();
714
sewardj20917d82002-05-28 01:36:45 +0000715 /* Allocate space for the arg block. thread_wrapper will free
716 it. */
sewardj00a66b12002-10-12 16:42:35 +0000717 info = my_malloc(sizeof(NewThreadInfo));
sewardj2d94c112002-06-03 01:25:54 +0000718 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000719
sewardj728a5272002-06-20 10:25:37 +0000720 if (__attr)
721 info->attr__detachstate = __attr->__detachstate;
722 else
723 info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
724
sewardj20917d82002-05-28 01:36:45 +0000725 info->root_fn = __start_routine;
726 info->arg = __arg;
727 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
728 VG_USERREQ__APPLY_IN_NEW_THREAD,
729 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000730 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000731
sewardj1462c8b2002-07-24 09:41:52 +0000732 if (__thredd)
733 *__thredd = tid_child;
sewardj20917d82002-05-28 01:36:45 +0000734 return 0; /* success */
735}
sewardje663cb92002-04-12 10:26:32 +0000736
737
738int
739pthread_join (pthread_t __th, void **__thread_return)
740{
741 int res;
742 ensure_valgrind("pthread_join");
743 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
744 VG_USERREQ__PTHREAD_JOIN,
745 __th, __thread_return, 0, 0);
746 return res;
747}
748
749
sewardj3b5d8862002-04-20 13:53:23 +0000750void pthread_exit(void *retval)
751{
sewardj3b5d8862002-04-20 13:53:23 +0000752 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000753 /* Simple! */
754 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000755}
756
sewardje663cb92002-04-12 10:26:32 +0000757
sewardj853f55d2002-04-26 00:27:53 +0000758int pthread_detach(pthread_t th)
759{
sewardj20917d82002-05-28 01:36:45 +0000760 int res;
761 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000762 /* First we enquire as to the current detach state. */
763 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000764 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000765 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000766 if (res == -1) {
767 /* not found */
768 pthread_error("pthread_detach: "
769 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000770 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000771 }
772 if (res == 1) {
773 /* already detached */
774 pthread_error("pthread_detach: "
775 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000776 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000777 }
sewardj7989d0c2002-05-28 11:00:01 +0000778 if (res == 0) {
779 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
780 VG_USERREQ__SET_OR_GET_DETACH,
781 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000782 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000783 return 0;
784 }
785 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000786}
787
788
sewardjf8f819e2002-04-17 23:21:37 +0000789/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000790 CLEANUP STACKS
791 ------------------------------------------------ */
792
793void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
794 void (*__routine) (void *),
795 void *__arg)
796{
797 int res;
798 CleanupEntry cu;
799 ensure_valgrind("_pthread_cleanup_push");
800 cu.fn = __routine;
801 cu.arg = __arg;
802 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
803 VG_USERREQ__CLEANUP_PUSH,
804 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000805 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000806}
807
808
809void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
810 void (*__routine) (void *),
811 void *__arg)
812{
813 /* As _pthread_cleanup_push, but first save the thread's original
814 cancellation type in __buffer and set it to Deferred. */
815 int orig_ctype;
816 ensure_valgrind("_pthread_cleanup_push_defer");
817 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000818 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
819 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
820 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000821 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
822 VG_USERREQ__SET_CANCELTYPE,
823 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000824 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000825 *((int*)(__buffer)) = orig_ctype;
826 /* Now push the cleanup. */
827 _pthread_cleanup_push(NULL, __routine, __arg);
828}
829
830
831void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
832 int __execute)
833{
834 int res;
835 CleanupEntry cu;
836 ensure_valgrind("_pthread_cleanup_push");
837 cu.fn = cu.arg = NULL; /* paranoia */
838 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
839 VG_USERREQ__CLEANUP_POP,
840 &cu, 0, 0, 0);
841 if (res == 0) {
842 /* pop succeeded */
843 if (__execute) {
844 cu.fn ( cu.arg );
845 }
846 return;
847 }
848 if (res == -1) {
849 /* stack underflow */
850 return;
851 }
852 barf("_pthread_cleanup_pop");
853}
854
855
856void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
857 int __execute)
858{
859 int orig_ctype, fake_ctype;
860 /* As _pthread_cleanup_pop, but after popping/running the handler,
861 restore the thread's original cancellation type from the first
862 word of __buffer. */
863 _pthread_cleanup_pop(NULL, __execute);
864 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000865 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000866 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000867 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
868 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
869 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000870 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
871 VG_USERREQ__SET_CANCELTYPE,
872 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000873 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000874}
875
876
877/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000878 MUTEX ATTRIBUTES
879 ------------------------------------------------ */
880
sewardj5905fae2002-04-26 13:25:00 +0000881int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000882{
sewardjf8f819e2002-04-17 23:21:37 +0000883 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000884 return 0;
sewardje663cb92002-04-12 10:26:32 +0000885}
886
sewardj5905fae2002-04-26 13:25:00 +0000887int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000888{
889 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000890# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000891 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000892 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000893# endif
sewardja1679dd2002-05-10 22:31:40 +0000894# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000895 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000896# endif
sewardjf8f819e2002-04-17 23:21:37 +0000897 case PTHREAD_MUTEX_RECURSIVE_NP:
898 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000899 attr->__mutexkind = type;
900 return 0;
901 default:
sewardj4dced352002-06-04 22:54:20 +0000902 pthread_error("pthread_mutexattr_settype: "
903 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000904 return EINVAL;
905 }
906}
907
sewardj5905fae2002-04-26 13:25:00 +0000908int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000909{
910 return 0;
911}
912
sewardjf0995512003-07-06 01:29:49 +0000913int __pthread_mutexattr_setpshared ( pthread_mutexattr_t* attr, int pshared)
sewardj7685cae2003-07-06 01:23:11 +0000914{
915 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
916 return EINVAL;
917
918 /* For now it is not possible to shared a conditional variable. */
919 if (pshared != PTHREAD_PROCESS_PRIVATE)
920 return ENOSYS;
921
922 return 0;
923}
924
sewardjf8f819e2002-04-17 23:21:37 +0000925
926/* ---------------------------------------------------
927 MUTEXes
928 ------------------------------------------------ */
929
sewardj5905fae2002-04-26 13:25:00 +0000930int __pthread_mutex_init(pthread_mutex_t *mutex,
931 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000932{
sewardj604ec3c2002-04-18 22:38:41 +0000933 mutex->__m_count = 0;
934 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
935 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
936 if (mutexattr)
937 mutex->__m_kind = mutexattr->__mutexkind;
938 return 0;
sewardje663cb92002-04-12 10:26:32 +0000939}
940
sewardj439d45e2002-05-03 20:43:10 +0000941
sewardj5905fae2002-04-26 13:25:00 +0000942int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000943{
944 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000945
sewardj439d45e2002-05-03 20:43:10 +0000946 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000947 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
948 VG_USERREQ__PTHREAD_MUTEX_LOCK,
949 mutex, 0, 0, 0);
950 return res;
sewardj439d45e2002-05-03 20:43:10 +0000951 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000952 /* Play at locking */
953 if (0)
954 kludged("prehistoric lock");
955 mutex->__m_owner = (_pthread_descr)1;
956 mutex->__m_count = 1;
957 mutex->__m_kind |= VG_PTHREAD_PREHISTORY;
sewardj439d45e2002-05-03 20:43:10 +0000958 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000959 }
960}
961
sewardj439d45e2002-05-03 20:43:10 +0000962
sewardj5905fae2002-04-26 13:25:00 +0000963int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000964{
965 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000966
sewardj439d45e2002-05-03 20:43:10 +0000967 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000968 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
969 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
970 mutex, 0, 0, 0);
971 return res;
sewardj439d45e2002-05-03 20:43:10 +0000972 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000973 /* Play at locking */
974 if (0)
975 kludged("prehistoric trylock");
976 mutex->__m_owner = (_pthread_descr)1;
977 mutex->__m_count = 1;
978 mutex->__m_kind |= VG_PTHREAD_PREHISTORY;
979 return 0; /* success */
sewardj30671ff2002-04-21 00:13:57 +0000980 }
981}
982
sewardj439d45e2002-05-03 20:43:10 +0000983
sewardj5905fae2002-04-26 13:25:00 +0000984int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000985{
986 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000987
sewardj439d45e2002-05-03 20:43:10 +0000988 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000989 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
990 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
991 mutex, 0, 0, 0);
992 return res;
sewardj439d45e2002-05-03 20:43:10 +0000993 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000994 /* Play at locking */
995 if (0)
996 kludged("prehistoric unlock");
997 mutex->__m_owner = 0;
998 mutex->__m_count = 0;
999 mutex->__m_kind &= ~VG_PTHREAD_PREHISTORY;
1000 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +00001001 }
1002}
1003
sewardj439d45e2002-05-03 20:43:10 +00001004
sewardj5905fae2002-04-26 13:25:00 +00001005int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +00001006{
sewardj604ec3c2002-04-18 22:38:41 +00001007 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
1008 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +00001009 if (mutex->__m_count > 0) {
sewardjd8acdf22002-11-13 21:57:52 +00001010 /* Oh, the horror. glibc's internal use of pthreads "knows"
1011 that destroying a lock does an implicit unlock. Make it
1012 explicit. */
1013 __pthread_mutex_unlock(mutex);
1014 pthread_error("pthread_mutex_destroy: "
1015 "mutex is still in use");
1016 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +00001017 }
1018 mutex->__m_count = 0;
1019 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
1020 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
1021 return 0;
sewardje663cb92002-04-12 10:26:32 +00001022}
1023
1024
sewardjf8f819e2002-04-17 23:21:37 +00001025/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +00001026 CONDITION VARIABLES
1027 ------------------------------------------------ */
1028
1029/* LinuxThreads supports no attributes for conditions. Hence ... */
1030
1031int pthread_condattr_init(pthread_condattr_t *attr)
1032{
1033 return 0;
1034}
1035
sewardj0738a592002-04-20 13:59:33 +00001036int pthread_condattr_destroy(pthread_condattr_t *attr)
1037{
1038 return 0;
1039}
sewardj6072c362002-04-19 14:40:57 +00001040
1041int pthread_cond_init( pthread_cond_t *cond,
1042 const pthread_condattr_t *cond_attr)
1043{
1044 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
1045 return 0;
1046}
1047
sewardjf854f472002-04-21 12:19:41 +00001048int pthread_cond_destroy(pthread_cond_t *cond)
1049{
1050 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +00001051 static int moans = N_MOANS;
1052 if (moans-- > 0)
1053 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +00001054 return 0;
1055}
sewardj6072c362002-04-19 14:40:57 +00001056
1057/* ---------------------------------------------------
1058 SCHEDULING
1059 ------------------------------------------------ */
1060
1061/* This is completely bogus. */
1062int pthread_getschedparam(pthread_t target_thread,
1063 int *policy,
1064 struct sched_param *param)
1065{
sewardj436e0582002-04-26 14:31:40 +00001066 static int moans = N_MOANS;
1067 if (moans-- > 0)
1068 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +00001069 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +00001070# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +00001071 if (param) param->sched_priority = 0; /* who knows */
1072# else
sewardj6072c362002-04-19 14:40:57 +00001073 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +00001074# endif
sewardj6072c362002-04-19 14:40:57 +00001075 return 0;
1076}
1077
1078int pthread_setschedparam(pthread_t target_thread,
1079 int policy,
1080 const struct sched_param *param)
1081{
sewardj436e0582002-04-26 14:31:40 +00001082 static int moans = N_MOANS;
1083 if (moans-- > 0)
1084 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +00001085 return 0;
1086}
1087
sewardj3b5d8862002-04-20 13:53:23 +00001088int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
1089{
1090 int res;
1091 ensure_valgrind("pthread_cond_wait");
1092 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1093 VG_USERREQ__PTHREAD_COND_WAIT,
1094 cond, mutex, 0, 0);
1095 return res;
1096}
1097
sewardj5f07b662002-04-23 16:52:51 +00001098int pthread_cond_timedwait ( pthread_cond_t *cond,
1099 pthread_mutex_t *mutex,
1100 const struct timespec *abstime )
1101{
1102 int res;
1103 unsigned int ms_now, ms_end;
1104 struct timeval timeval_now;
1105 unsigned long long int ull_ms_now_after_1970;
1106 unsigned long long int ull_ms_end_after_1970;
1107
1108 ensure_valgrind("pthread_cond_timedwait");
1109 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1110 VG_USERREQ__READ_MILLISECOND_TIMER,
1111 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001112 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001113 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +00001114 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001115
1116 ull_ms_now_after_1970
1117 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
1118 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
1119 ull_ms_end_after_1970
1120 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
1121 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +00001122 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
1123 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +00001124 ms_end
1125 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
1126 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1127 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
1128 cond, mutex, ms_end, 0);
1129 return res;
1130}
1131
1132
sewardj3b5d8862002-04-20 13:53:23 +00001133int pthread_cond_signal(pthread_cond_t *cond)
1134{
1135 int res;
1136 ensure_valgrind("pthread_cond_signal");
1137 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1138 VG_USERREQ__PTHREAD_COND_SIGNAL,
1139 cond, 0, 0, 0);
1140 return res;
1141}
1142
1143int pthread_cond_broadcast(pthread_cond_t *cond)
1144{
1145 int res;
1146 ensure_valgrind("pthread_cond_broadcast");
1147 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1148 VG_USERREQ__PTHREAD_COND_BROADCAST,
1149 cond, 0, 0, 0);
1150 return res;
1151}
1152
sewardj6072c362002-04-19 14:40:57 +00001153
1154/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001155 CANCELLATION
1156 ------------------------------------------------ */
1157
sewardj853f55d2002-04-26 00:27:53 +00001158int pthread_setcancelstate(int state, int *oldstate)
1159{
sewardj20917d82002-05-28 01:36:45 +00001160 int res;
1161 ensure_valgrind("pthread_setcancelstate");
1162 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +00001163 && state != PTHREAD_CANCEL_DISABLE) {
1164 pthread_error("pthread_setcancelstate: "
1165 "invalid state");
sewardj20917d82002-05-28 01:36:45 +00001166 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001167 }
sewardj2d94c112002-06-03 01:25:54 +00001168 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1169 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001170 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1171 VG_USERREQ__SET_CANCELSTATE,
1172 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001173 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001174 if (oldstate)
1175 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001176 return 0;
1177}
1178
sewardje663cb92002-04-12 10:26:32 +00001179int pthread_setcanceltype(int type, int *oldtype)
1180{
sewardj20917d82002-05-28 01:36:45 +00001181 int res;
1182 ensure_valgrind("pthread_setcanceltype");
1183 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001184 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1185 pthread_error("pthread_setcanceltype: "
1186 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001187 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001188 }
sewardj2d94c112002-06-03 01:25:54 +00001189 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1190 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001191 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1192 VG_USERREQ__SET_CANCELTYPE,
1193 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001194 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001195 if (oldtype)
1196 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001197 return 0;
1198}
1199
sewardje663cb92002-04-12 10:26:32 +00001200int pthread_cancel(pthread_t thread)
1201{
1202 int res;
1203 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001204 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1205 VG_USERREQ__SET_CANCELPEND,
1206 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001207 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001208 return res;
1209}
1210
sewardjd140e442002-05-29 01:21:19 +00001211static __inline__
1212void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001213{
sewardj20917d82002-05-28 01:36:45 +00001214 int res;
njn25e49d8e72002-09-23 09:36:25 +00001215 ensure_valgrind("__my_pthread_testcancel");
sewardj20917d82002-05-28 01:36:45 +00001216 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1217 VG_USERREQ__TESTCANCEL,
1218 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001219 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001220}
1221
sewardjd140e442002-05-29 01:21:19 +00001222void pthread_testcancel ( void )
1223{
1224 __my_pthread_testcancel();
1225}
1226
sewardj20917d82002-05-28 01:36:45 +00001227
sewardjef037c72002-05-30 00:40:03 +00001228/* Not really sure what this is for. I suspect for doing the POSIX
1229 requirements for fork() and exec(). We do this internally anyway
1230 whenever those syscalls are observed, so this could be superfluous,
1231 but hey ...
1232*/
sewardj853f55d2002-04-26 00:27:53 +00001233void __pthread_kill_other_threads_np ( void )
1234{
sewardjef037c72002-05-30 00:40:03 +00001235 int res;
1236 ensure_valgrind("__pthread_kill_other_threads_np");
1237 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1238 VG_USERREQ__NUKE_OTHER_THREADS,
1239 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001240 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001241}
1242
sewardje663cb92002-04-12 10:26:32 +00001243
sewardjf8f819e2002-04-17 23:21:37 +00001244/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001245 SIGNALS
1246 ------------------------------------------------ */
1247
1248#include <signal.h>
1249
1250int pthread_sigmask(int how, const sigset_t *newmask,
1251 sigset_t *oldmask)
1252{
1253 int res;
1254
1255 /* A bit subtle, because the scheduler expects newmask and oldmask
1256 to be vki_sigset_t* rather than sigset_t*, and the two are
1257 different. Fortunately the first 64 bits of a sigset_t are
1258 exactly a vki_sigset_t, so we just pass the pointers through
1259 unmodified. Haaaack!
1260
1261 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001262 constants to VKI_ constants, so that the former do not have to
1263 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001264
1265 ensure_valgrind("pthread_sigmask");
1266
1267 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001268 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1269 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1270 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001271 default: pthread_error("pthread_sigmask: invalid how");
1272 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001273 }
1274
1275 /* Crude check */
1276 if (newmask == NULL)
1277 return EFAULT;
1278
1279 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1280 VG_USERREQ__PTHREAD_SIGMASK,
1281 how, newmask, oldmask, 0);
1282
1283 /* The scheduler tells us of any memory violations. */
1284 return res == 0 ? 0 : EFAULT;
1285}
1286
1287
1288int sigwait ( const sigset_t* set, int* sig )
1289{
1290 int res;
1291 ensure_valgrind("sigwait");
1292 /* As with pthread_sigmask we deliberately confuse sigset_t with
1293 vki_ksigset_t. */
1294 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1295 VG_USERREQ__SIGWAIT,
1296 set, sig, 0, 0);
1297 return res;
1298}
1299
1300
sewardj018f7622002-05-15 21:13:39 +00001301int pthread_kill(pthread_t thread, int signo)
1302{
1303 int res;
1304 ensure_valgrind("pthread_kill");
1305 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1306 VG_USERREQ__PTHREAD_KILL,
1307 thread, signo, 0, 0);
1308 return res;
1309}
1310
1311
sewardj3665ded2002-05-16 16:57:25 +00001312/* Copied verbatim from Linuxthreads */
1313/* Redefine raise() to send signal to calling thread only,
1314 as per POSIX 1003.1c */
1315int raise (int sig)
1316{
1317 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001318 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001319 return 0;
sewardj4dced352002-06-04 22:54:20 +00001320 } else {
sewardj25418ae2003-05-09 23:40:34 +00001321 *(__errno_location()) = retcode;
sewardj3665ded2002-05-16 16:57:25 +00001322 return -1;
1323 }
1324}
1325
1326
sewardj9a2224b2002-06-19 10:17:40 +00001327int pause ( void )
1328{
1329 unsigned int n_orig, n_now;
1330 struct vki_timespec nanosleep_interval;
1331 ensure_valgrind("pause");
1332
1333 /* This is surely a cancellation point. */
1334 __my_pthread_testcancel();
1335
1336 VALGRIND_MAGIC_SEQUENCE(n_orig, 0xFFFFFFFF /* default */,
1337 VG_USERREQ__GET_N_SIGS_RETURNED,
1338 0, 0, 0, 0);
1339 my_assert(n_orig != 0xFFFFFFFF);
1340
1341 while (1) {
1342 VALGRIND_MAGIC_SEQUENCE(n_now, 0xFFFFFFFF /* default */,
1343 VG_USERREQ__GET_N_SIGS_RETURNED,
1344 0, 0, 0, 0);
1345 my_assert(n_now != 0xFFFFFFFF);
1346 my_assert(n_now >= n_orig);
1347 if (n_now != n_orig) break;
1348
1349 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001350 nanosleep_interval.tv_nsec = 12 * 1000 * 1000; /* 12 milliseconds */
sewardj9a2224b2002-06-19 10:17:40 +00001351 /* It's critical here that valgrind's nanosleep implementation
1352 is nonblocking. */
1353 (void)my_do_syscall2(__NR_nanosleep,
1354 (int)(&nanosleep_interval), (int)NULL);
1355 }
1356
sewardj25418ae2003-05-09 23:40:34 +00001357 *(__errno_location()) = EINTR;
sewardj9a2224b2002-06-19 10:17:40 +00001358 return -1;
1359}
1360
1361
sewardjb48e5002002-05-13 00:16:03 +00001362/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001363 THREAD-SPECIFICs
1364 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001365
sewardj00a66b12002-10-12 16:42:35 +00001366static
1367int key_is_valid (pthread_key_t key)
1368{
1369 int res;
1370 VALGRIND_MAGIC_SEQUENCE(res, 2 /* default */,
1371 VG_USERREQ__PTHREAD_KEY_VALIDATE,
1372 key, 0, 0, 0);
1373 my_assert(res != 2);
1374 return res;
1375}
1376
1377
1378/* Returns NULL if thread is invalid. Otherwise, if the thread
1379 already has a specifics area, return that. Otherwise allocate it
1380 one. */
1381static
1382void** get_or_allocate_specifics_ptr ( pthread_t thread )
1383{
1384 int res, i;
1385 void** specifics_ptr;
1386 ensure_valgrind("get_or_allocate_specifics_ptr");
1387
1388 /* Returns zero if the thread has no specific_ptr. One if thread
1389 is invalid. Otherwise, the specific_ptr value. This is
1390 allocated with my_malloc and so is aligned and cannot be
1391 confused with 1 or 3. */
1392 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
1393 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
1394 thread, 0, 0, 0);
1395 my_assert(specifics_ptr != (void**)3);
1396
1397 if (specifics_ptr == (void**)1)
1398 return NULL; /* invalid thread */
1399
1400 if (specifics_ptr != NULL)
1401 return specifics_ptr; /* already has a specifics ptr. */
1402
1403 /* None yet ... allocate a new one. Should never fail. */
1404 specifics_ptr = my_malloc( VG_N_THREAD_KEYS * sizeof(void*) );
1405 my_assert(specifics_ptr != NULL);
1406
1407 VALGRIND_MAGIC_SEQUENCE(res, -1 /* default */,
1408 VG_USERREQ__PTHREAD_SETSPECIFIC_PTR,
1409 specifics_ptr, 0, 0, 0);
1410 my_assert(res == 0);
1411
1412 /* POSIX sez: "Upon thread creation, the value NULL shall be
1413 associated with all defined keys in the new thread." This
1414 allocation is in effect a delayed allocation of the specific
1415 data for a thread, at its first-use. Hence we initialise it
1416 here. */
1417 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
1418 specifics_ptr[i] = NULL;
1419 }
1420
1421 return specifics_ptr;
1422}
1423
1424
sewardj5905fae2002-04-26 13:25:00 +00001425int __pthread_key_create(pthread_key_t *key,
1426 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001427{
sewardj00a66b12002-10-12 16:42:35 +00001428 void** specifics_ptr;
1429 int res, i;
sewardj5f07b662002-04-23 16:52:51 +00001430 ensure_valgrind("pthread_key_create");
sewardj00a66b12002-10-12 16:42:35 +00001431
1432 /* This writes *key if successful. It should never fail. */
1433 VALGRIND_MAGIC_SEQUENCE(res, 1 /* default */,
sewardj5f07b662002-04-23 16:52:51 +00001434 VG_USERREQ__PTHREAD_KEY_CREATE,
1435 key, destr_function, 0, 0);
sewardj00a66b12002-10-12 16:42:35 +00001436 my_assert(res == 0);
1437
1438 /* POSIX sez: "Upon key creation, the value NULL shall be
1439 associated with the new key in all active threads." */
1440 for (i = 0; i < VG_N_THREADS; i++) {
1441 specifics_ptr = get_or_allocate_specifics_ptr(i);
1442 /* we get NULL if i is an invalid thread. */
1443 if (specifics_ptr != NULL)
1444 specifics_ptr[*key] = NULL;
1445 }
1446
sewardj5f07b662002-04-23 16:52:51 +00001447 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001448}
1449
1450int pthread_key_delete(pthread_key_t key)
1451{
sewardj00a66b12002-10-12 16:42:35 +00001452 int res;
njndfc9b8c2003-09-29 12:58:37 +00001453 ensure_valgrind("pthread_key_delete");
sewardj00a66b12002-10-12 16:42:35 +00001454 if (!key_is_valid(key))
1455 return EINVAL;
1456 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1457 VG_USERREQ__PTHREAD_KEY_DELETE,
1458 key, 0, 0, 0);
1459 my_assert(res == 0);
sewardj5e5fa512002-04-14 13:13:05 +00001460 return 0;
1461}
1462
sewardj5905fae2002-04-26 13:25:00 +00001463int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001464{
sewardj00a66b12002-10-12 16:42:35 +00001465 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001466 ensure_valgrind("pthread_setspecific");
sewardj00a66b12002-10-12 16:42:35 +00001467
1468 if (!key_is_valid(key))
1469 return EINVAL;
1470
1471 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1472 specifics_ptr[key] = (void*)pointer;
1473 return 0;
sewardj5e5fa512002-04-14 13:13:05 +00001474}
1475
sewardj5905fae2002-04-26 13:25:00 +00001476void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001477{
sewardj00a66b12002-10-12 16:42:35 +00001478 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001479 ensure_valgrind("pthread_getspecific");
sewardj00a66b12002-10-12 16:42:35 +00001480
1481 if (!key_is_valid(key))
1482 return NULL;
1483
1484 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1485 return specifics_ptr[key];
1486}
1487
1488
sewardj9aa918d2002-10-20 16:25:55 +00001489#ifdef GLIBC_2_3
sewardj00a66b12002-10-12 16:42:35 +00001490static
1491void ** __pthread_getspecific_addr(pthread_key_t key)
1492{
1493 void** specifics_ptr;
1494 ensure_valgrind("pthread_getspecific_addr");
1495
1496 if (!key_is_valid(key))
1497 return NULL;
1498
1499 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1500 return &(specifics_ptr[key]);
sewardj5e5fa512002-04-14 13:13:05 +00001501}
sewardj9aa918d2002-10-20 16:25:55 +00001502#endif
sewardjf8f819e2002-04-17 23:21:37 +00001503
sewardjc91a4ff2003-07-11 00:12:58 +00001504
sewardjf8f819e2002-04-17 23:21:37 +00001505/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001506 ONCEry
1507 ------------------------------------------------ */
1508
sewardjc91a4ff2003-07-11 00:12:58 +00001509/* This protects reads and writes of the once_control variable
1510 supplied. It is never held whilst any particular initialiser is
1511 running. */
sewardj89d3d852002-04-24 19:21:39 +00001512static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1513
sewardjc91a4ff2003-07-11 00:12:58 +00001514/* Initialiser needs to be run. */
1515#define P_ONCE_NOT_DONE ((PTHREAD_ONCE_INIT) + 0)
1516
1517/* Initialiser currently running. */
1518#define P_ONCE_RUNNING ((PTHREAD_ONCE_INIT) + 1)
1519
1520/* Initialiser has completed. */
1521#define P_ONCE_COMPLETED ((PTHREAD_ONCE_INIT) + 2)
sewardj89d3d852002-04-24 19:21:39 +00001522
sewardj5905fae2002-04-26 13:25:00 +00001523int __pthread_once ( pthread_once_t *once_control,
1524 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001525{
1526 int res;
sewardjc91a4ff2003-07-11 00:12:58 +00001527 int done;
sewardj89d3d852002-04-24 19:21:39 +00001528 ensure_valgrind("pthread_once");
1529
sewardjc91a4ff2003-07-11 00:12:58 +00001530# define TAKE_LOCK \
1531 res = __pthread_mutex_lock(&once_masterlock); \
1532 my_assert(res == 0);
sewardj89d3d852002-04-24 19:21:39 +00001533
sewardjc91a4ff2003-07-11 00:12:58 +00001534# define RELEASE_LOCK \
1535 res = __pthread_mutex_unlock(&once_masterlock); \
1536 my_assert(res == 0);
sewardj89d3d852002-04-24 19:21:39 +00001537
sewardjc91a4ff2003-07-11 00:12:58 +00001538 /* Grab the lock transiently, so we can safely see what state this
1539 once_control is in. */
1540
1541 TAKE_LOCK;
1542
1543 switch (*once_control) {
1544
1545 case P_ONCE_NOT_DONE:
1546 /* Not started. Change state to indicate running, drop the
1547 lock and run. */
1548 *once_control = P_ONCE_RUNNING;
1549 RELEASE_LOCK;
1550 init_routine();
1551 /* re-take the lock, and set state to indicate done. */
1552 TAKE_LOCK;
1553 *once_control = P_ONCE_COMPLETED;
1554 RELEASE_LOCK;
1555 break;
1556
1557 case P_ONCE_RUNNING:
1558 /* This is the tricky case. The initialiser is running in
1559 some other thread, but we have to delay this thread till
1560 the other one completes. So we sort-of busy wait. In
1561 fact it makes sense to yield now, because what we want to
1562 happen is for the thread running the initialiser to
1563 complete ASAP. */
1564 RELEASE_LOCK;
1565 done = 0;
1566 while (1) {
1567 /* Let others run for a while. */
1568 __valgrind_pthread_yield();
1569 /* Grab the lock and see if we're done waiting. */
1570 TAKE_LOCK;
1571 if (*once_control == P_ONCE_COMPLETED)
1572 done = 1;
1573 RELEASE_LOCK;
1574 if (done)
1575 break;
1576 }
1577 break;
1578
1579 case P_ONCE_COMPLETED:
1580 default:
1581 /* Easy. It's already done. Just drop the lock. */
1582 RELEASE_LOCK;
1583 break;
sewardj89d3d852002-04-24 19:21:39 +00001584 }
1585
sewardj89d3d852002-04-24 19:21:39 +00001586 return 0;
sewardjc91a4ff2003-07-11 00:12:58 +00001587
1588# undef TAKE_LOCK
1589# undef RELEASE_LOCK
sewardj89d3d852002-04-24 19:21:39 +00001590}
1591
sewardjc91a4ff2003-07-11 00:12:58 +00001592#undef P_ONCE_NOT_DONE
1593#undef P_ONCE_RUNNING
1594#undef P_ONCE_COMPLETED
1595
sewardj89d3d852002-04-24 19:21:39 +00001596
1597/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001598 MISC
1599 ------------------------------------------------ */
1600
sewardj2cb00342002-06-28 01:46:26 +00001601static pthread_mutex_t pthread_atfork_lock
1602 = PTHREAD_MUTEX_INITIALIZER;
1603
sewardj5905fae2002-04-26 13:25:00 +00001604int __pthread_atfork ( void (*prepare)(void),
1605 void (*parent)(void),
1606 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001607{
sewardj2cb00342002-06-28 01:46:26 +00001608 int n, res;
1609 ForkHandlerEntry entry;
1610
1611 ensure_valgrind("pthread_atfork");
1612 __pthread_mutex_lock(&pthread_atfork_lock);
1613
1614 /* Fetch old counter */
1615 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1616 VG_USERREQ__GET_FHSTACK_USED,
1617 0, 0, 0, 0);
1618 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1619 if (n == VG_N_FORKHANDLERSTACK-1)
1620 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1621 "increase and recompile");
1622
1623 /* Add entry */
1624 entry.prepare = *prepare;
1625 entry.parent = *parent;
1626 entry.child = *child;
1627 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1628 VG_USERREQ__SET_FHSTACK_ENTRY,
1629 n, &entry, 0, 0);
1630 my_assert(res == 0);
1631
1632 /* Bump counter */
1633 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1634 VG_USERREQ__SET_FHSTACK_USED,
1635 n+1, 0, 0, 0);
1636 my_assert(res == 0);
1637
1638 __pthread_mutex_unlock(&pthread_atfork_lock);
1639 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001640}
1641
1642
sewardj9df78832003-05-04 12:35:54 +00001643#ifdef GLIBC_2_3
1644/* This seems to be a hook which appeared in glibc-2.3.2. */
1645int __register_atfork ( void (*prepare)(void),
1646 void (*parent)(void),
1647 void (*child)(void) )
1648{
1649 return __pthread_atfork(prepare,parent,child);
1650}
1651#endif
1652
sewardj11f0bb42003-04-26 20:11:15 +00001653WEAK
sewardjbb990782002-05-08 02:01:14 +00001654void __pthread_initialize ( void )
1655{
sewardjbea1caa2002-05-10 23:20:58 +00001656 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001657}
1658
1659
sewardj853f55d2002-04-26 00:27:53 +00001660/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001661 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001662 ------------------------------------------------ */
1663
sewardj3b13f0e2002-04-25 20:17:29 +00001664#include <resolv.h>
1665static int thread_specific_errno[VG_N_THREADS];
1666static int thread_specific_h_errno[VG_N_THREADS];
1667static struct __res_state
1668 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001669
sewardj25418ae2003-05-09 23:40:34 +00001670#undef errno
1671extern int errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001672int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001673{
1674 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001675 /* ensure_valgrind("__errno_location"); */
1676 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001677 VG_USERREQ__PTHREAD_GET_THREADID,
1678 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001679 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001680 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001681 barf("__errno_location: invalid ThreadId");
sewardj25418ae2003-05-09 23:40:34 +00001682 if (tid == 1)
1683 return &errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001684 return & thread_specific_errno[tid];
1685}
1686
sewardj25418ae2003-05-09 23:40:34 +00001687#undef h_errno
1688extern int h_errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001689int* __h_errno_location ( void )
1690{
1691 int tid;
1692 /* ensure_valgrind("__h_errno_location"); */
1693 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1694 VG_USERREQ__PTHREAD_GET_THREADID,
1695 0, 0, 0, 0);
1696 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001697 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001698 barf("__h_errno_location: invalid ThreadId");
sewardj25418ae2003-05-09 23:40:34 +00001699 if (tid == 1)
1700 return &h_errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001701 return & thread_specific_h_errno[tid];
1702}
1703
sewardjb0ff1032002-08-06 09:02:53 +00001704
1705#undef _res
1706extern struct __res_state _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001707struct __res_state* __res_state ( void )
1708{
1709 int tid;
1710 /* ensure_valgrind("__res_state"); */
1711 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1712 VG_USERREQ__PTHREAD_GET_THREADID,
1713 0, 0, 0, 0);
1714 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001715 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001716 barf("__res_state: invalid ThreadId");
sewardjb0ff1032002-08-06 09:02:53 +00001717 if (tid == 1)
1718 return & _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001719 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001720}
1721
1722
sewardj5716dbb2002-04-26 03:28:18 +00001723/* ---------------------------------------------------
1724 LIBC-PRIVATE SPECIFIC DATA
1725 ------------------------------------------------ */
1726
1727/* Relies on assumption that initial private data is NULL. This
1728 should be fixed somehow. */
1729
njn25e49d8e72002-09-23 09:36:25 +00001730/* The allowable keys (indices) (all 3 of them).
sewardj5716dbb2002-04-26 03:28:18 +00001731 From sysdeps/pthread/bits/libc-tsd.h
1732*/
sewardjcb7f08a2002-10-02 09:41:49 +00001733/* as per glibc anoncvs HEAD of 20021001. */
sewardj5716dbb2002-04-26 03:28:18 +00001734enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1735 _LIBC_TSD_KEY_DL_ERROR,
njn25e49d8e72002-09-23 09:36:25 +00001736 _LIBC_TSD_KEY_RPC_VARS,
sewardjcb7f08a2002-10-02 09:41:49 +00001737 _LIBC_TSD_KEY_LOCALE,
1738 _LIBC_TSD_KEY_CTYPE_B,
1739 _LIBC_TSD_KEY_CTYPE_TOLOWER,
1740 _LIBC_TSD_KEY_CTYPE_TOUPPER,
sewardj5716dbb2002-04-26 03:28:18 +00001741 _LIBC_TSD_KEY_N };
1742
1743/* Auto-initialising subsystem. libc_specifics_inited is set
1744 after initialisation. libc_specifics_inited_mx guards it. */
1745static int libc_specifics_inited = 0;
1746static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1747
sewardj00a66b12002-10-12 16:42:35 +00001748
sewardj5716dbb2002-04-26 03:28:18 +00001749/* These are the keys we must initialise the first time. */
sewardjcb7f08a2002-10-02 09:41:49 +00001750static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N];
sewardj5716dbb2002-04-26 03:28:18 +00001751
sewardj00a66b12002-10-12 16:42:35 +00001752
sewardjcb7f08a2002-10-02 09:41:49 +00001753/* Initialise the keys, if they are not already initialised. */
sewardj5716dbb2002-04-26 03:28:18 +00001754static
1755void init_libc_tsd_keys ( void )
1756{
1757 int res, i;
1758 pthread_key_t k;
1759
sewardj08c7f012002-10-07 23:56:55 +00001760 /* Don't fall into deadlock if we get called again whilst we still
1761 hold the lock, via the __uselocale() call herein. */
1762 if (libc_specifics_inited != 0)
1763 return;
1764
1765 /* Take the lock. */
sewardj00a66b12002-10-12 16:42:35 +00001766 res = __pthread_mutex_lock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001767 if (res != 0) barf("init_libc_tsd_keys: lock");
1768
sewardj08c7f012002-10-07 23:56:55 +00001769 /* Now test again, to be sure there is no mistake. */
1770 if (libc_specifics_inited != 0) {
sewardj00a66b12002-10-12 16:42:35 +00001771 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj08c7f012002-10-07 23:56:55 +00001772 if (res != 0) barf("init_libc_tsd_keys: unlock(1)");
1773 return;
sewardj5716dbb2002-04-26 03:28:18 +00001774 }
1775
sewardj08c7f012002-10-07 23:56:55 +00001776 /* Actually do the initialisation. */
1777 /* printf("INIT libc specifics\n"); */
1778 for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
sewardj00a66b12002-10-12 16:42:35 +00001779 res = __pthread_key_create(&k, NULL);
sewardj08c7f012002-10-07 23:56:55 +00001780 if (res != 0) barf("init_libc_tsd_keys: create");
1781 libc_specifics_keys[i] = k;
1782 }
1783
1784 /* Signify init done. */
1785 libc_specifics_inited = 1;
1786
1787# ifdef GLIBC_2_3
1788 /* Set the initialising thread's locale to the global (default)
sewardj00a66b12002-10-12 16:42:35 +00001789 locale. A hack in support of glibc-2.3. This does the biz for
1790 the root thread. For all other threads we run this in
1791 thread_wrapper(), which does the real work of
1792 pthread_create(). */
1793 /* assert that we are the root thread. I don't know if this is
1794 really a valid assertion to make; if it breaks I'll reconsider
1795 it. */
1796 my_assert(pthread_self() == 1);
sewardj08c7f012002-10-07 23:56:55 +00001797 __uselocale(LC_GLOBAL_LOCALE);
1798# endif
1799
1800 /* Unlock and return. */
sewardj00a66b12002-10-12 16:42:35 +00001801 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001802 if (res != 0) barf("init_libc_tsd_keys: unlock");
1803}
1804
1805
1806static int
1807libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1808 const void * pointer )
1809{
sewardjcb7f08a2002-10-02 09:41:49 +00001810 int res;
sewardj5716dbb2002-04-26 03:28:18 +00001811 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardjcb7f08a2002-10-02 09:41:49 +00001812 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001813 barf("libc_internal_tsd_set: invalid key");
1814 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001815 res = __pthread_setspecific(libc_specifics_keys[key], pointer);
sewardj5716dbb2002-04-26 03:28:18 +00001816 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1817 return 0;
1818}
1819
1820static void *
1821libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1822{
sewardjcb7f08a2002-10-02 09:41:49 +00001823 void* v;
sewardj5716dbb2002-04-26 03:28:18 +00001824 /* printf("GET GET GET key %d\n", key); */
sewardjcb7f08a2002-10-02 09:41:49 +00001825 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001826 barf("libc_internal_tsd_get: invalid key");
1827 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001828 v = __pthread_getspecific(libc_specifics_keys[key]);
sewardj5716dbb2002-04-26 03:28:18 +00001829 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1830 return v;
1831}
1832
1833
sewardj70adeb22002-04-27 01:35:38 +00001834int (*__libc_internal_tsd_set)
1835 (enum __libc_tsd_key_t key, const void * pointer)
1836 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001837
sewardj70adeb22002-04-27 01:35:38 +00001838void* (*__libc_internal_tsd_get)
1839 (enum __libc_tsd_key_t key)
1840 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001841
1842
sewardj00a66b12002-10-12 16:42:35 +00001843#ifdef GLIBC_2_3
1844/* This one was first spotted be me in the glibc-2.2.93 sources. */
1845static void**
1846libc_internal_tsd_address ( enum __libc_tsd_key_t key )
1847{
1848 void** v;
1849 /* printf("ADDR ADDR ADDR key %d\n", key); */
1850 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
1851 barf("libc_internal_tsd_address: invalid key");
1852 init_libc_tsd_keys();
1853 v = __pthread_getspecific_addr(libc_specifics_keys[key]);
1854 return v;
1855}
1856
1857void ** (*__libc_internal_tsd_address)
1858 (enum __libc_tsd_key_t key)
1859 = libc_internal_tsd_address;
1860#endif
1861
1862
sewardje663cb92002-04-12 10:26:32 +00001863/* ---------------------------------------------------------------------
1864 These are here (I think) because they are deemed cancellation
1865 points by POSIX. For the moment we'll simply pass the call along
1866 to the corresponding thread-unaware (?) libc routine.
1867 ------------------------------------------------------------------ */
1868
sewardjd529a442002-05-04 19:49:21 +00001869#ifdef GLIBC_2_1
1870extern
1871int __sigaction
1872 (int signum,
1873 const struct sigaction *act,
1874 struct sigaction *oldact);
1875#else
sewardje663cb92002-04-12 10:26:32 +00001876extern
1877int __libc_sigaction
1878 (int signum,
1879 const struct sigaction *act,
1880 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001881#endif
sewardje663cb92002-04-12 10:26:32 +00001882int sigaction(int signum,
1883 const struct sigaction *act,
1884 struct sigaction *oldact)
1885{
sewardjd140e442002-05-29 01:21:19 +00001886 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001887# ifdef GLIBC_2_1
1888 return __sigaction(signum, act, oldact);
1889# else
sewardj45b4b372002-04-16 22:50:32 +00001890 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001891# endif
sewardje663cb92002-04-12 10:26:32 +00001892}
1893
1894
1895extern
1896int __libc_connect(int sockfd,
1897 const struct sockaddr *serv_addr,
1898 socklen_t addrlen);
sewardj11f0bb42003-04-26 20:11:15 +00001899WEAK
sewardje663cb92002-04-12 10:26:32 +00001900int connect(int sockfd,
1901 const struct sockaddr *serv_addr,
1902 socklen_t addrlen)
1903{
sewardjd140e442002-05-29 01:21:19 +00001904 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001905 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001906}
1907
1908
1909extern
1910int __libc_fcntl(int fd, int cmd, long arg);
sewardj11f0bb42003-04-26 20:11:15 +00001911WEAK
sewardje663cb92002-04-12 10:26:32 +00001912int fcntl(int fd, int cmd, long arg)
1913{
sewardjd140e442002-05-29 01:21:19 +00001914 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001915 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001916}
1917
1918
1919extern
1920ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj11f0bb42003-04-26 20:11:15 +00001921WEAK
sewardje663cb92002-04-12 10:26:32 +00001922ssize_t write(int fd, const void *buf, size_t count)
1923{
sewardjd140e442002-05-29 01:21:19 +00001924 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001925 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001926}
1927
1928
1929extern
1930ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj11f0bb42003-04-26 20:11:15 +00001931WEAK
sewardje663cb92002-04-12 10:26:32 +00001932ssize_t read(int fd, void *buf, size_t count)
1933{
sewardjd140e442002-05-29 01:21:19 +00001934 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001935 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001936}
1937
sewardjf912dfc2002-11-13 21:51:10 +00001938/*
1939 * Ugh, this is horrible but here goes:
1940 *
1941 * Open of a named pipe (fifo file) can block. In a threaded program,
1942 * this means that the whole thing can block. We therefore need to
1943 * make the open appear to block to the caller, but still keep polling
1944 * for everyone else.
1945 *
1946 * There are four cases:
1947 *
1948 * - the caller asked for O_NONBLOCK. The easy one: we just do it.
1949 *
1950 * - the caller asked for a blocking O_RDONLY open. We open it with
1951 * O_NONBLOCK and then use poll to wait for it to become ready.
1952 *
1953 * - the caller asked for a blocking O_WRONLY open. Unfortunately, this
1954 * will fail with ENXIO when we make it non-blocking. Doubly
1955 * unfortunate is that we can only rely on these semantics if it is
1956 * actually a fifo file; the hack is that if we see that it is a
1957 * O_WRONLY open and we get ENXIO, then stat the path and see if it
1958 * actually is a fifo. This is racy, but it is the best we can do.
1959 * If it is a fifo, then keep trying the open until it works; if not
1960 * just return the error.
1961 *
1962 * - the caller asked for a blocking O_RDWR open. Well, under Linux,
1963 * this never blocks, so we just clear the non-blocking flag and
1964 * return.
1965 *
1966 * This code assumes that for whatever we open, O_NONBLOCK followed by
1967 * a fcntl clearing O_NONBLOCK is the same as opening without
1968 * O_NONBLOCK. Also assumes that stat and fstat have no side-effects.
1969 *
1970 * XXX Should probably put in special cases for some devices as well,
1971 * like serial ports. Unfortunately they don't work like fifos, so
1972 * this logic will become even more tortured. Wait until we really
1973 * need it.
1974 */
sewardj56867352003-10-12 10:27:06 +00001975static int _open(const char *pathname, int flags, mode_t mode,
1976 int (*openp)(const char *, int, mode_t))
sewardjbe32e452002-04-24 20:29:58 +00001977{
sewardjf912dfc2002-11-13 21:51:10 +00001978 int fd;
1979 struct stat st;
1980 struct vki_timespec nanosleep_interval;
1981 int saved_errno;
1982
sewardjd140e442002-05-29 01:21:19 +00001983 __my_pthread_testcancel();
sewardjf912dfc2002-11-13 21:51:10 +00001984
1985 /* Assume we can only get O_RDONLY, O_WRONLY or O_RDWR */
1986 my_assert((flags & VKI_O_ACCMODE) != VKI_O_ACCMODE);
1987
1988 for(;;) {
1989 fd = (*openp)(pathname, flags | VKI_O_NONBLOCK, mode);
1990
1991 /* return immediately if caller wanted nonblocking anyway */
1992 if (flags & VKI_O_NONBLOCK)
1993 return fd;
1994
sewardj25418ae2003-05-09 23:40:34 +00001995 saved_errno = *(__errno_location());
sewardjf912dfc2002-11-13 21:51:10 +00001996
1997 if (fd != -1)
1998 break; /* open worked */
1999
2000 /* If we got ENXIO and we're opening WRONLY, and it turns out
2001 to really be a FIFO, then poll waiting for open to succeed */
sewardj25418ae2003-05-09 23:40:34 +00002002 if (*(__errno_location()) == ENXIO &&
sewardjf912dfc2002-11-13 21:51:10 +00002003 (flags & VKI_O_ACCMODE) == VKI_O_WRONLY &&
2004 (stat(pathname, &st) == 0 && S_ISFIFO(st.st_mode))) {
2005
2006 /* OK, we're opening a FIFO for writing; sleep and spin */
2007 nanosleep_interval.tv_sec = 0;
2008 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
2009 /* It's critical here that valgrind's nanosleep implementation
2010 is nonblocking. */
2011 (void)my_do_syscall2(__NR_nanosleep,
2012 (int)(&nanosleep_interval), (int)NULL);
2013 } else {
2014 /* it was just an error */
sewardj25418ae2003-05-09 23:40:34 +00002015 *(__errno_location()) = saved_errno;
sewardjf912dfc2002-11-13 21:51:10 +00002016 return -1;
2017 }
2018 }
2019
2020 /* OK, we've got a nonblocking FD for a caller who wants blocking;
2021 reset the flags to what they asked for */
2022 fcntl(fd, VKI_F_SETFL, flags);
2023
2024 /* Return now if one of:
2025 - we were opening O_RDWR (never blocks)
2026 - we opened with O_WRONLY (polling already done)
2027 - the thing we opened wasn't a FIFO after all (or fstat failed)
2028 */
2029 if ((flags & VKI_O_ACCMODE) != VKI_O_RDONLY ||
2030 (fstat(fd, &st) == -1 || !S_ISFIFO(st.st_mode))) {
sewardj25418ae2003-05-09 23:40:34 +00002031 *(__errno_location()) = saved_errno;
sewardjf912dfc2002-11-13 21:51:10 +00002032 return fd;
2033 }
2034
2035 /* OK, drop into the poll loop looking for something to read on the fd */
2036 my_assert((flags & VKI_O_ACCMODE) == VKI_O_RDONLY);
2037 for(;;) {
2038 struct pollfd pollfd;
2039 int res;
2040
2041 pollfd.fd = fd;
2042 pollfd.events = POLLIN;
2043 pollfd.revents = 0;
2044
2045 res = my_do_syscall3(__NR_poll, (int)&pollfd, 1, 0);
2046
2047 my_assert(res == 0 || res == 1);
2048
2049 if (res == 1) {
2050 /* OK, got it.
2051
2052 XXX This is wrong: we're waiting for either something to
2053 read or a HUP on the file descriptor, but the semantics of
2054 fifo open are that we should unblock as soon as someone
2055 simply opens the other end, not that they write something.
2056 With luck this won't matter in practice.
2057 */
2058 my_assert(pollfd.revents & (POLLIN|POLLHUP));
2059 break;
2060 }
2061
2062 /* Still nobody home; sleep and spin */
2063 nanosleep_interval.tv_sec = 0;
2064 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
2065 /* It's critical here that valgrind's nanosleep implementation
2066 is nonblocking. */
2067 (void)my_do_syscall2(__NR_nanosleep,
2068 (int)(&nanosleep_interval), (int)NULL);
2069 }
2070
sewardj25418ae2003-05-09 23:40:34 +00002071 *(__errno_location()) = saved_errno;
sewardjf912dfc2002-11-13 21:51:10 +00002072 return fd;
sewardjbe32e452002-04-24 20:29:58 +00002073}
2074
sewardjf912dfc2002-11-13 21:51:10 +00002075extern
2076int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj11f0bb42003-04-26 20:11:15 +00002077/* WEAK */
sewardjf912dfc2002-11-13 21:51:10 +00002078int open64(const char *pathname, int flags, mode_t mode)
2079{
2080 return _open(pathname, flags, mode, __libc_open64);
2081}
sewardje663cb92002-04-12 10:26:32 +00002082
2083extern
sewardj853f55d2002-04-26 00:27:53 +00002084int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj11f0bb42003-04-26 20:11:15 +00002085/* WEAK */
sewardj853f55d2002-04-26 00:27:53 +00002086int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00002087{
sewardjf912dfc2002-11-13 21:51:10 +00002088 return _open(pathname, flags, mode, __libc_open);
sewardje663cb92002-04-12 10:26:32 +00002089}
2090
sewardje663cb92002-04-12 10:26:32 +00002091extern
2092int __libc_close(int fd);
sewardj11f0bb42003-04-26 20:11:15 +00002093WEAK
sewardje663cb92002-04-12 10:26:32 +00002094int close(int fd)
2095{
sewardjd140e442002-05-29 01:21:19 +00002096 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002097 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00002098}
2099
2100
sewardj11f0bb42003-04-26 20:11:15 +00002101WEAK
2102int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
sewardje663cb92002-04-12 10:26:32 +00002103{
sewardj11f0bb42003-04-26 20:11:15 +00002104 return VGR_(accept)(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00002105}
2106
sewardj11f0bb42003-04-26 20:11:15 +00002107WEAK
2108int recv(int s, void *buf, size_t len, int flags)
sewardj0c573af92002-10-23 21:55:01 +00002109{
sewardj11f0bb42003-04-26 20:11:15 +00002110 return VGR_(recv)(s, buf, len, flags);
sewardj0c573af92002-10-23 21:55:01 +00002111}
2112
sewardj11f0bb42003-04-26 20:11:15 +00002113WEAK
2114int readv(int fd, const struct iovec *iov, int count)
sewardj2a68e7e2002-11-16 11:04:18 +00002115{
sewardj11f0bb42003-04-26 20:11:15 +00002116 return VGR_(readv)(fd, iov, count);
sewardj2a68e7e2002-11-16 11:04:18 +00002117}
2118
sewardj11f0bb42003-04-26 20:11:15 +00002119WEAK
2120int writev(int fd, const struct iovec *iov, int count)
sewardj2a68e7e2002-11-16 11:04:18 +00002121{
sewardj11f0bb42003-04-26 20:11:15 +00002122 return VGR_(writev)(fd, iov, count);
sewardj2a68e7e2002-11-16 11:04:18 +00002123}
sewardje663cb92002-04-12 10:26:32 +00002124
2125extern
sewardje663cb92002-04-12 10:26:32 +00002126pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj11f0bb42003-04-26 20:11:15 +00002127WEAK
sewardje663cb92002-04-12 10:26:32 +00002128pid_t waitpid(pid_t pid, int *status, int options)
2129{
sewardjd140e442002-05-29 01:21:19 +00002130 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002131 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00002132}
2133
2134
2135extern
2136int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj11f0bb42003-04-26 20:11:15 +00002137WEAK
sewardje663cb92002-04-12 10:26:32 +00002138int nanosleep(const struct timespec *req, struct timespec *rem)
2139{
sewardjd140e442002-05-29 01:21:19 +00002140 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00002141 return __libc_nanosleep(req, rem);
2142}
2143
sewardjbe32e452002-04-24 20:29:58 +00002144
sewardje663cb92002-04-12 10:26:32 +00002145extern
2146int __libc_fsync(int fd);
sewardj11f0bb42003-04-26 20:11:15 +00002147WEAK
sewardje663cb92002-04-12 10:26:32 +00002148int fsync(int fd)
2149{
sewardjd140e442002-05-29 01:21:19 +00002150 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002151 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00002152}
2153
sewardjbe32e452002-04-24 20:29:58 +00002154
sewardj70c75362002-04-13 04:18:32 +00002155extern
2156off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj11f0bb42003-04-26 20:11:15 +00002157WEAK
sewardj70c75362002-04-13 04:18:32 +00002158off_t lseek(int fildes, off_t offset, int whence)
2159{
sewardjd140e442002-05-29 01:21:19 +00002160 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002161 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00002162}
2163
sewardjbe32e452002-04-24 20:29:58 +00002164
2165extern
2166__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj11f0bb42003-04-26 20:11:15 +00002167WEAK
sewardjbe32e452002-04-24 20:29:58 +00002168__off64_t lseek64(int fildes, __off64_t offset, int whence)
2169{
sewardjd140e442002-05-29 01:21:19 +00002170 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00002171 return __libc_lseek64(fildes, offset, whence);
2172}
2173
2174
sewardj726c4122002-05-16 23:39:10 +00002175extern
2176ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
2177 __off64_t __offset);
2178ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
2179 __off64_t __offset)
2180{
sewardjd140e442002-05-29 01:21:19 +00002181 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00002182 return __libc_pread64(__fd, __buf, __nbytes, __offset);
2183}
2184
2185
sewardja18e2102002-05-18 10:43:22 +00002186extern
2187ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
2188 __off64_t __offset);
2189ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
2190 __off64_t __offset)
2191{
sewardjd140e442002-05-29 01:21:19 +00002192 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00002193 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
2194}
2195
sewardj726c4122002-05-16 23:39:10 +00002196
sewardj39b93b12002-05-18 10:56:27 +00002197extern
2198ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
sewardj11f0bb42003-04-26 20:11:15 +00002199WEAK
sewardj39b93b12002-05-18 10:56:27 +00002200ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
2201{
sewardjd140e442002-05-29 01:21:19 +00002202 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00002203 return __libc_pwrite(fd, buf, count, offset);
2204}
2205
2206
2207extern
2208ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
sewardj11f0bb42003-04-26 20:11:15 +00002209WEAK
sewardj39b93b12002-05-18 10:56:27 +00002210ssize_t pread(int fd, void *buf, size_t count, off_t offset)
2211{
sewardjd140e442002-05-29 01:21:19 +00002212 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00002213 return __libc_pread(fd, buf, count, offset);
2214}
2215
2216
sewardj6af4b5d2002-04-16 04:40:49 +00002217extern
2218void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj11f0bb42003-04-26 20:11:15 +00002219/* not weak: WEAK */
sewardj6af4b5d2002-04-16 04:40:49 +00002220void longjmp(jmp_buf env, int val)
2221{
2222 __libc_longjmp(env, val);
2223}
2224
sewardjbe32e452002-04-24 20:29:58 +00002225
sewardj436c2db2002-06-18 09:07:54 +00002226extern void __libc_siglongjmp (sigjmp_buf env, int val)
2227 __attribute__ ((noreturn));
2228void siglongjmp(sigjmp_buf env, int val)
2229{
2230 kludged("siglongjmp (cleanup handlers are ignored)");
2231 __libc_siglongjmp(env, val);
2232}
2233
2234
sewardj6af4b5d2002-04-16 04:40:49 +00002235extern
2236int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002237WEAK
sewardj6af4b5d2002-04-16 04:40:49 +00002238int send(int s, const void *msg, size_t len, int flags)
2239{
sewardjd140e442002-05-29 01:21:19 +00002240 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00002241 return __libc_send(s, msg, len, flags);
2242}
2243
sewardjbe32e452002-04-24 20:29:58 +00002244
sewardj3665ded2002-05-16 16:57:25 +00002245extern
2246int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002247WEAK
sewardj3665ded2002-05-16 16:57:25 +00002248int sendmsg(int s, const struct msghdr *msg, int flags)
2249{
sewardjd140e442002-05-29 01:21:19 +00002250 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00002251 return __libc_sendmsg(s, msg, flags);
2252}
2253
2254
sewardj796d6a22002-04-24 02:28:34 +00002255extern
sewardj59da27a2002-06-06 08:33:54 +00002256int __libc_recvmsg(int s, struct msghdr *msg, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002257WEAK
sewardj59da27a2002-06-06 08:33:54 +00002258int recvmsg(int s, struct msghdr *msg, int flags)
2259{
2260 __my_pthread_testcancel();
2261 return __libc_recvmsg(s, msg, flags);
2262}
2263
2264
2265extern
sewardj436e0582002-04-26 14:31:40 +00002266int __libc_recvfrom(int s, void *buf, size_t len, int flags,
2267 struct sockaddr *from, socklen_t *fromlen);
sewardj11f0bb42003-04-26 20:11:15 +00002268WEAK
sewardj436e0582002-04-26 14:31:40 +00002269int recvfrom(int s, void *buf, size_t len, int flags,
2270 struct sockaddr *from, socklen_t *fromlen)
2271{
sewardjd140e442002-05-29 01:21:19 +00002272 __my_pthread_testcancel();
sewardj11f0bb42003-04-26 20:11:15 +00002273 VGR_(wait_for_fd_to_be_readable_or_erring)(s);
sewardj2e207632002-06-13 17:29:53 +00002274 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00002275 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
2276}
2277
2278
2279extern
sewardj796d6a22002-04-24 02:28:34 +00002280int __libc_sendto(int s, const void *msg, size_t len, int flags,
2281 const struct sockaddr *to, socklen_t tolen);
sewardj11f0bb42003-04-26 20:11:15 +00002282WEAK
sewardj796d6a22002-04-24 02:28:34 +00002283int sendto(int s, const void *msg, size_t len, int flags,
2284 const struct sockaddr *to, socklen_t tolen)
2285{
sewardjd140e442002-05-29 01:21:19 +00002286 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00002287 return __libc_sendto(s, msg, len, flags, to, tolen);
2288}
2289
sewardjbe32e452002-04-24 20:29:58 +00002290
sewardj369b1702002-04-24 13:28:15 +00002291extern
2292int __libc_system(const char* str);
sewardj11f0bb42003-04-26 20:11:15 +00002293WEAK
sewardj369b1702002-04-24 13:28:15 +00002294int system(const char* str)
2295{
sewardjd140e442002-05-29 01:21:19 +00002296 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00002297 return __libc_system(str);
2298}
2299
sewardjbe32e452002-04-24 20:29:58 +00002300
sewardjab0b1c32002-04-24 19:26:47 +00002301extern
2302pid_t __libc_wait(int *status);
sewardj11f0bb42003-04-26 20:11:15 +00002303WEAK
sewardjab0b1c32002-04-24 19:26:47 +00002304pid_t wait(int *status)
2305{
sewardjd140e442002-05-29 01:21:19 +00002306 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00002307 return __libc_wait(status);
2308}
2309
sewardj45b4b372002-04-16 22:50:32 +00002310
sewardj67f1d582002-05-24 02:11:32 +00002311extern
2312int __libc_msync(const void *start, size_t length, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002313WEAK
sewardj67f1d582002-05-24 02:11:32 +00002314int msync(const void *start, size_t length, int flags)
2315{
sewardjd140e442002-05-29 01:21:19 +00002316 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00002317 return __libc_msync(start, length, flags);
2318}
2319
sewardj5905fae2002-04-26 13:25:00 +00002320
sewardj2cb00342002-06-28 01:46:26 +00002321/*--- fork and its helper ---*/
2322
2323static
2324void run_fork_handlers ( int what )
2325{
2326 ForkHandlerEntry entry;
2327 int n_h, n_handlers, i, res;
2328
2329 my_assert(what == 0 || what == 1 || what == 2);
2330
2331 /* Fetch old counter */
2332 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2333 VG_USERREQ__GET_FHSTACK_USED,
2334 0, 0, 0, 0);
2335 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2336
2337 /* Prepare handlers (what == 0) are called in opposite order of
2338 calls to pthread_atfork. Parent and child handlers are called
2339 in the same order as calls to pthread_atfork. */
2340 if (what == 0)
2341 n_h = n_handlers - 1;
2342 else
2343 n_h = 0;
2344
2345 for (i = 0; i < n_handlers; i++) {
2346 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2347 VG_USERREQ__GET_FHSTACK_ENTRY,
2348 n_h, &entry, 0, 0);
2349 my_assert(res == 0);
2350 switch (what) {
2351 case 0: if (entry.prepare) entry.prepare();
2352 n_h--; break;
2353 case 1: if (entry.parent) entry.parent();
2354 n_h++; break;
2355 case 2: if (entry.child) entry.child();
2356 n_h++; break;
2357 default: barf("run_fork_handlers: invalid what");
2358 }
2359 }
2360
2361 if (what != 0 /* prepare */) {
2362 /* Empty out the stack. */
2363 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2364 VG_USERREQ__SET_FHSTACK_USED,
2365 0, 0, 0, 0);
2366 my_assert(res == 0);
2367 }
2368}
2369
2370extern
2371pid_t __libc_fork(void);
2372pid_t __fork(void)
2373{
2374 pid_t pid;
2375 __my_pthread_testcancel();
2376 __pthread_mutex_lock(&pthread_atfork_lock);
2377
2378 run_fork_handlers(0 /* prepare */);
2379 pid = __libc_fork();
2380 if (pid == 0) {
2381 /* I am the child */
2382 run_fork_handlers(2 /* child */);
sewardjd8acdf22002-11-13 21:57:52 +00002383 __pthread_mutex_unlock(&pthread_atfork_lock);
sewardj2cb00342002-06-28 01:46:26 +00002384 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2385 } else {
2386 /* I am the parent */
2387 run_fork_handlers(1 /* parent */);
2388 __pthread_mutex_unlock(&pthread_atfork_lock);
2389 }
2390 return pid;
2391}
2392
2393
njn25e49d8e72002-09-23 09:36:25 +00002394pid_t __vfork(void)
2395{
2396 return __fork();
2397}
sewardj2cb00342002-06-28 01:46:26 +00002398
2399
sewardj08a4c3f2002-04-13 03:45:44 +00002400static
sewardj08a4c3f2002-04-13 03:45:44 +00002401int my_do_syscall1 ( int syscallno, int arg1 )
2402{
2403 int __res;
2404 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2405 : "=a" (__res)
2406 : "0" (syscallno),
2407 "d" (arg1) );
2408 return __res;
2409}
2410
2411static
2412int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00002413 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00002414{
2415 int __res;
2416 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2417 : "=a" (__res)
2418 : "0" (syscallno),
2419 "d" (arg1),
2420 "c" (arg2) );
2421 return __res;
2422}
2423
2424static
sewardjf854f472002-04-21 12:19:41 +00002425int my_do_syscall3 ( int syscallno,
2426 int arg1, int arg2, int arg3 )
2427{
2428 int __res;
2429 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
2430 : "=a" (__res)
2431 : "0" (syscallno),
2432 "S" (arg1),
2433 "c" (arg2),
2434 "d" (arg3) );
2435 return __res;
2436}
2437
sewardjd5bef572002-10-23 21:49:33 +00002438static inline
2439int my_do_syscall5 ( int syscallno,
2440 int arg1, int arg2, int arg3, int arg4, int arg5 )
2441{
2442 int __res;
2443 __asm__ volatile ("int $0x80"
2444 : "=a" (__res)
2445 : "0" (syscallno),
2446 "b" (arg1),
2447 "c" (arg2),
2448 "d" (arg3),
2449 "S" (arg4),
2450 "D" (arg5));
2451 return __res;
2452}
2453
sewardj11f0bb42003-04-26 20:11:15 +00002454
2455WEAK
2456int select ( int n,
2457 fd_set *rfds,
2458 fd_set *wfds,
2459 fd_set *xfds,
2460 struct timeval *timeout )
sewardj08a4c3f2002-04-13 03:45:44 +00002461{
sewardj11f0bb42003-04-26 20:11:15 +00002462 return VGR_(select)(n, rfds, wfds, xfds, timeout);
sewardj08a4c3f2002-04-13 03:45:44 +00002463}
2464
2465
sewardj3b13f0e2002-04-25 20:17:29 +00002466/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002467 Hacky implementation of semaphores.
2468 ------------------------------------------------------------------ */
2469
2470#include <semaphore.h>
2471
2472/* This is a terrible way to do the remapping. Plan is to import an
2473 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002474
2475typedef
2476 struct {
2477 pthread_mutex_t se_mx;
2478 pthread_cond_t se_cv;
2479 int count;
2480 }
2481 vg_sem_t;
2482
2483static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2484
2485static int se_remap_used = 0;
2486static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2487static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2488
2489static vg_sem_t* se_remap ( sem_t* orig )
2490{
2491 int res, i;
2492 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002493 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002494
2495 for (i = 0; i < se_remap_used; i++) {
2496 if (se_remap_orig[i] == orig)
2497 break;
2498 }
2499 if (i == se_remap_used) {
2500 if (se_remap_used == VG_N_SEMAPHORES) {
2501 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002502 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002503 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002504 }
2505 se_remap_used++;
2506 se_remap_orig[i] = orig;
2507 /* printf("allocated semaphore %d\n", i); */
2508 }
2509 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002510 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002511 return &se_remap_new[i];
2512}
2513
2514
2515int sem_init(sem_t *sem, int pshared, unsigned int value)
2516{
2517 int res;
2518 vg_sem_t* vg_sem;
2519 ensure_valgrind("sem_init");
2520 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002521 pthread_error("sem_init: unsupported pshared value");
sewardj25418ae2003-05-09 23:40:34 +00002522 *(__errno_location()) = ENOSYS;
sewardj8f253ff2002-05-19 00:13:34 +00002523 return -1;
2524 }
2525 vg_sem = se_remap(sem);
2526 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002527 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002528 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002529 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002530 vg_sem->count = value;
2531 return 0;
2532}
2533
2534
2535int sem_wait ( sem_t* sem )
2536{
2537 int res;
2538 vg_sem_t* vg_sem;
2539 ensure_valgrind("sem_wait");
2540 vg_sem = se_remap(sem);
2541 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002542 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002543 while (vg_sem->count == 0) {
2544 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002545 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002546 }
2547 vg_sem->count--;
2548 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002549 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002550 return 0;
2551}
2552
2553int sem_post ( sem_t* sem )
2554{
2555 int res;
2556 vg_sem_t* vg_sem;
2557 ensure_valgrind("sem_post");
2558 vg_sem = se_remap(sem);
2559 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002560 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002561 if (vg_sem->count == 0) {
2562 vg_sem->count++;
2563 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002564 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002565 } else {
2566 vg_sem->count++;
2567 }
2568 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002569 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002570 return 0;
2571}
2572
2573
2574int sem_trywait ( sem_t* sem )
2575{
2576 int ret, res;
2577 vg_sem_t* vg_sem;
2578 ensure_valgrind("sem_trywait");
2579 vg_sem = se_remap(sem);
2580 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002581 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002582 if (vg_sem->count > 0) {
2583 vg_sem->count--;
2584 ret = 0;
2585 } else {
2586 ret = -1;
sewardj25418ae2003-05-09 23:40:34 +00002587 *(__errno_location()) = EAGAIN;
sewardj8f253ff2002-05-19 00:13:34 +00002588 }
2589 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002590 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002591 return ret;
2592}
2593
2594
2595int sem_getvalue(sem_t* sem, int * sval)
2596{
2597 vg_sem_t* vg_sem;
2598 ensure_valgrind("sem_trywait");
2599 vg_sem = se_remap(sem);
2600 *sval = vg_sem->count;
2601 return 0;
2602}
2603
2604
2605int sem_destroy(sem_t * sem)
2606{
2607 kludged("sem_destroy");
2608 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2609 return 0;
2610}
2611
sewardj9ad92d92002-10-16 19:45:06 +00002612
2613int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2614{
2615 int res;
2616 vg_sem_t* vg_sem;
2617 ensure_valgrind("sem_timedwait");
2618 vg_sem = se_remap(sem);
2619 res = __pthread_mutex_lock(&vg_sem->se_mx);
2620 my_assert(res == 0);
2621 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
2622 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
2623 }
2624 if ( vg_sem->count > 0 ) {
2625 vg_sem->count--;
2626 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2627 my_assert(res == 0 );
2628 return 0;
2629 } else {
2630 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2631 my_assert(res == 0 );
2632 *(__errno_location()) = ETIMEDOUT;
2633 return -1;
2634 }
2635}
2636
sewardj8f253ff2002-05-19 00:13:34 +00002637
2638/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002639 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002640 ------------------------------------------------------------------ */
2641
sewardj2d8b3f02002-06-01 14:14:19 +00002642typedef
2643 struct {
2644 int initted; /* != 0 --> in use; sanity check only */
2645 int prefer_w; /* != 0 --> prefer writer */
2646 int nwait_r; /* # of waiting readers */
2647 int nwait_w; /* # of waiting writers */
2648 pthread_cond_t cv_r; /* for signalling readers */
2649 pthread_cond_t cv_w; /* for signalling writers */
2650 pthread_mutex_t mx;
2651 int status;
2652 /* allowed range for status: >= -1. -1 means 1 writer currently
2653 active, >= 0 means N readers currently active. */
2654 }
2655 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002656
2657
2658static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2659
2660static int rw_remap_used = 0;
2661static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2662static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2663
sewardj2d8b3f02002-06-01 14:14:19 +00002664
2665static
2666void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2667{
2668 int res = 0;
2669 vg_rwl->initted = 1;
2670 vg_rwl->prefer_w = 1;
2671 vg_rwl->nwait_r = 0;
2672 vg_rwl->nwait_w = 0;
2673 vg_rwl->status = 0;
2674 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2675 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2676 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002677 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002678}
2679
2680
sewardja1ac5cb2002-05-27 13:00:05 +00002681/* Take the address of a LinuxThreads rwlock_t and return the shadow
2682 address of our version. Further, if the LinuxThreads version
2683 appears to have been statically initialised, do the same to the one
2684 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2685 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2686 uninitialised and non-zero meaning initialised.
2687*/
2688static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2689{
2690 int res, i;
2691 vg_rwlock_t* vg_rwl;
2692 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002693 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002694
2695 for (i = 0; i < rw_remap_used; i++) {
2696 if (rw_remap_orig[i] == orig)
2697 break;
2698 }
2699 if (i == rw_remap_used) {
2700 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002701 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002702 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002703 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2704 }
2705 rw_remap_used++;
2706 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002707 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002708 if (0) printf("allocated rwlock %d\n", i);
2709 }
2710 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002711 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002712 vg_rwl = &rw_remap_new[i];
2713
sewardj2d8b3f02002-06-01 14:14:19 +00002714 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002715 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002716 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002717 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002718 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002719 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002720 }
2721
2722 return vg_rwl;
2723}
2724
2725
sewardja1ac5cb2002-05-27 13:00:05 +00002726int pthread_rwlock_init ( pthread_rwlock_t* orig,
2727 const pthread_rwlockattr_t* attr )
2728{
sewardja1ac5cb2002-05-27 13:00:05 +00002729 vg_rwlock_t* rwl;
2730 if (0) printf ("pthread_rwlock_init\n");
2731 /* Force the remapper to initialise the shadow. */
2732 orig->__rw_readers = 0;
2733 /* Install the lock preference; the remapper needs to know it. */
2734 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2735 if (attr)
2736 orig->__rw_kind = attr->__lockkind;
2737 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002738 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002739}
2740
sewardj2d8b3f02002-06-01 14:14:19 +00002741
2742static
2743void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002744{
sewardj2d8b3f02002-06-01 14:14:19 +00002745 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2746 rwl->nwait_r--;
2747 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002748}
2749
sewardj2d8b3f02002-06-01 14:14:19 +00002750
sewardja1ac5cb2002-05-27 13:00:05 +00002751int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2752{
2753 int res;
2754 vg_rwlock_t* rwl;
2755 if (0) printf ("pthread_rwlock_rdlock\n");
2756 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002757 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002758 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002759 if (!rwl->initted) {
2760 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002761 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002762 return EINVAL;
2763 }
2764 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002765 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002766 rwl->nwait_r++;
2767 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2768 while (1) {
2769 if (rwl->status == 0) break;
2770 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002771 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002772 }
2773 pthread_cleanup_pop(0);
2774 rwl->nwait_r--;
2775 }
sewardj2d94c112002-06-03 01:25:54 +00002776 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002777 rwl->status++;
2778 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002779 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002780 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002781}
2782
sewardj2d8b3f02002-06-01 14:14:19 +00002783
sewardja1ac5cb2002-05-27 13:00:05 +00002784int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2785{
2786 int res;
2787 vg_rwlock_t* rwl;
2788 if (0) printf ("pthread_rwlock_tryrdlock\n");
2789 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002790 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002791 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002792 if (!rwl->initted) {
2793 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002794 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002795 return EINVAL;
2796 }
2797 if (rwl->status == -1) {
2798 /* Writer active; we have to give up. */
2799 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002800 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002801 return EBUSY;
2802 }
2803 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002804 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002805 rwl->status++;
2806 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002807 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002808 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002809}
2810
sewardj2d8b3f02002-06-01 14:14:19 +00002811
2812static
2813void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2814{
2815 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2816 rwl->nwait_w--;
2817 pthread_mutex_unlock (&rwl->mx);
2818}
2819
2820
sewardja1ac5cb2002-05-27 13:00:05 +00002821int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2822{
2823 int res;
2824 vg_rwlock_t* rwl;
2825 if (0) printf ("pthread_rwlock_wrlock\n");
2826 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002827 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002828 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002829 if (!rwl->initted) {
2830 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002831 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002832 return EINVAL;
2833 }
2834 if (rwl->status != 0) {
2835 rwl->nwait_w++;
2836 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2837 while (1) {
2838 if (rwl->status == 0) break;
2839 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002840 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002841 }
2842 pthread_cleanup_pop(0);
2843 rwl->nwait_w--;
2844 }
sewardj2d94c112002-06-03 01:25:54 +00002845 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002846 rwl->status = -1;
2847 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002848 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002849 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002850}
2851
sewardj2d8b3f02002-06-01 14:14:19 +00002852
sewardja1ac5cb2002-05-27 13:00:05 +00002853int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2854{
2855 int res;
2856 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002857 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002858 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002859 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002860 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002861 if (!rwl->initted) {
2862 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002863 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002864 return EINVAL;
2865 }
2866 if (rwl->status != 0) {
2867 /* Reader(s) or a writer active; we have to give up. */
2868 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002869 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002870 return EBUSY;
2871 }
2872 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002873 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002874 rwl->status = -1;
2875 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002876 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002877 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002878}
2879
sewardj2d8b3f02002-06-01 14:14:19 +00002880
sewardja1ac5cb2002-05-27 13:00:05 +00002881int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2882{
2883 int res;
2884 vg_rwlock_t* rwl;
2885 if (0) printf ("pthread_rwlock_unlock\n");
2886 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002887 rwl = rw_remap ( orig );
2888 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002889 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002890 if (!rwl->initted) {
2891 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002892 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002893 return EINVAL;
2894 }
2895 if (rwl->status == 0) {
2896 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002897 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002898 return EPERM;
2899 }
sewardj2d94c112002-06-03 01:25:54 +00002900 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002901 if (rwl->status == -1) {
2902 rwl->status = 0;
2903 } else {
sewardj2d94c112002-06-03 01:25:54 +00002904 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002905 rwl->status--;
2906 }
2907
sewardj2d94c112002-06-03 01:25:54 +00002908 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002909
2910 if (rwl->prefer_w) {
2911
2912 /* Favour waiting writers, if any. */
2913 if (rwl->nwait_w > 0) {
2914 /* Writer(s) are waiting. */
2915 if (rwl->status == 0) {
2916 /* We can let a writer in. */
2917 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002918 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002919 } else {
2920 /* There are still readers active. Do nothing; eventually
2921 they will disappear, at which point a writer will be
2922 admitted. */
2923 }
2924 }
2925 else
2926 /* No waiting writers. */
2927 if (rwl->nwait_r > 0) {
2928 /* Let in a waiting reader. */
2929 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002930 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002931 }
2932
2933 } else {
2934
2935 /* Favour waiting readers, if any. */
2936 if (rwl->nwait_r > 0) {
2937 /* Reader(s) are waiting; let one in. */
2938 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002939 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002940 }
2941 else
2942 /* No waiting readers. */
2943 if (rwl->nwait_w > 0 && rwl->status == 0) {
2944 /* We have waiting writers and no active readers; let a
2945 writer in. */
2946 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002947 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002948 }
2949 }
2950
2951 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002952 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002953 return 0;
2954}
2955
2956
2957int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2958{
2959 int res;
2960 vg_rwlock_t* rwl;
2961 if (0) printf ("pthread_rwlock_destroy\n");
2962 rwl = rw_remap ( orig );
2963 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002964 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002965 if (!rwl->initted) {
2966 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002967 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002968 return EINVAL;
2969 }
2970 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2971 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002972 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002973 return EBUSY;
2974 }
2975 rwl->initted = 0;
2976 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002977 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002978 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002979}
2980
2981
sewardj47e4e312002-06-18 09:24:34 +00002982/* Copied directly from LinuxThreads. */
2983int
2984pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
2985{
2986 attr->__lockkind = 0;
2987 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
2988
2989 return 0;
2990}
2991
sewardjfe18eb82002-07-13 12:58:44 +00002992/* Copied directly from LinuxThreads. */
2993int
sewardj5706bfa2002-12-08 23:42:17 +00002994pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
2995{
2996 return 0;
2997}
2998
2999/* Copied directly from LinuxThreads. */
3000int
sewardjfe18eb82002-07-13 12:58:44 +00003001pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
3002{
3003 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
3004 return EINVAL;
3005
3006 /* For now it is not possible to shared a conditional variable. */
3007 if (pshared != PTHREAD_PROCESS_PRIVATE)
3008 return ENOSYS;
3009
3010 attr->__pshared = pshared;
3011
3012 return 0;
3013}
3014
sewardj47e4e312002-06-18 09:24:34 +00003015
sewardja1ac5cb2002-05-27 13:00:05 +00003016/* ---------------------------------------------------------------------
sewardj11f0bb42003-04-26 20:11:15 +00003017 Make SYSV IPC not block everything -- pass to vg_intercept.c.
sewardjd5bef572002-10-23 21:49:33 +00003018 ------------------------------------------------------------------ */
3019
sewardj11f0bb42003-04-26 20:11:15 +00003020WEAK
3021int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
sewardjd5bef572002-10-23 21:49:33 +00003022{
sewardj11f0bb42003-04-26 20:11:15 +00003023 return VGR_(msgsnd)(msgid, msgp, msgsz, msgflg);
sewardjd5bef572002-10-23 21:49:33 +00003024}
3025
sewardj11f0bb42003-04-26 20:11:15 +00003026WEAK
3027int msgrcv(int msqid, void* msgp, size_t msgsz,
3028 long msgtyp, int msgflg )
sewardjd5bef572002-10-23 21:49:33 +00003029{
sewardj11f0bb42003-04-26 20:11:15 +00003030 return VGR_(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg );
sewardjd5bef572002-10-23 21:49:33 +00003031}
3032
sewardj262b5be2003-04-26 21:19:53 +00003033
3034/* ---------------------------------------------------------------------
3035 The glibc sources say that returning -1 in these 3 functions
3036 causes real time signals not to be used.
3037 ------------------------------------------------------------------ */
3038
3039int __libc_current_sigrtmin (void)
3040{
3041 static int moans = N_MOANS;
3042 if (moans-- > 0)
3043 kludged("__libc_current_sigrtmin");
3044 return -1;
3045}
3046
3047int __libc_current_sigrtmax (void)
3048{
3049 static int moans = N_MOANS;
3050 if (moans-- > 0)
3051 kludged("__libc_current_sigrtmax");
3052 return -1;
3053}
3054
3055int __libc_allocate_rtsig (int high)
3056{
3057 static int moans = N_MOANS;
3058 if (moans-- > 0)
3059 kludged("__libc_allocate_rtsig");
3060 return -1;
3061}
3062
3063
sewardjd5bef572002-10-23 21:49:33 +00003064/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00003065 B'stard.
3066 ------------------------------------------------------------------ */
3067
3068# define strong_alias(name, aliasname) \
3069 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
3070
sewardj5905fae2002-04-26 13:25:00 +00003071# define weak_alias(name, aliasname) \
3072 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00003073
sewardj5905fae2002-04-26 13:25:00 +00003074strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
3075strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
3076strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
3077strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
3078 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
sewardjf0995512003-07-06 01:29:49 +00003079 weak_alias(__pthread_mutexattr_setpshared, pthread_mutexattr_setpshared)
sewardj5905fae2002-04-26 13:25:00 +00003080strong_alias(__pthread_mutex_init, pthread_mutex_init)
3081strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
3082strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
3083strong_alias(__pthread_once, pthread_once)
3084strong_alias(__pthread_atfork, pthread_atfork)
3085strong_alias(__pthread_key_create, pthread_key_create)
3086strong_alias(__pthread_getspecific, pthread_getspecific)
3087strong_alias(__pthread_setspecific, pthread_setspecific)
3088
sewardjd529a442002-05-04 19:49:21 +00003089#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00003090strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00003091#endif
3092
sewardj5905fae2002-04-26 13:25:00 +00003093strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00003094strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00003095strong_alias(lseek, __lseek)
3096strong_alias(open, __open)
3097strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00003098strong_alias(read, __read)
3099strong_alias(wait, __wait)
3100strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00003101strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00003102strong_alias(send, __send)
3103
sewardj726c4122002-05-16 23:39:10 +00003104weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00003105weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00003106weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00003107weak_alias(__vfork, vfork)
sewardj7f6456d2002-05-21 00:51:21 +00003108
sewardjf0b06452002-06-04 08:38:04 +00003109weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00003110
3111/*--------------------------------------------------*/
3112
sewardj5905fae2002-04-26 13:25:00 +00003113weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00003114weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00003115weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00003116
sewardja1ac5cb2002-05-27 13:00:05 +00003117weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
3118weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
3119weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
3120weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
3121
sewardj060b04f2002-04-26 21:01:13 +00003122
sewardj3b13f0e2002-04-25 20:17:29 +00003123/* I've no idea what these are, but they get called quite a lot.
3124 Anybody know? */
3125
njnff28df92003-10-12 17:26:04 +00003126#ifndef __UCLIBC__
sewardj3b13f0e2002-04-25 20:17:29 +00003127#undef _IO_flockfile
3128void _IO_flockfile ( _IO_FILE * file )
3129{
sewardj853f55d2002-04-26 00:27:53 +00003130 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003131}
sewardj5905fae2002-04-26 13:25:00 +00003132weak_alias(_IO_flockfile, flockfile);
3133
sewardj3b13f0e2002-04-25 20:17:29 +00003134#undef _IO_funlockfile
3135void _IO_funlockfile ( _IO_FILE * file )
3136{
sewardj853f55d2002-04-26 00:27:53 +00003137 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003138}
sewardj5905fae2002-04-26 13:25:00 +00003139weak_alias(_IO_funlockfile, funlockfile);
njnff28df92003-10-12 17:26:04 +00003140#endif
sewardj5905fae2002-04-26 13:25:00 +00003141
sewardj3b13f0e2002-04-25 20:17:29 +00003142
sewardjd4f2c712002-04-30 10:20:10 +00003143/* This doesn't seem to be needed to simulate libpthread.so's external
3144 interface, but many people complain about its absence. */
3145
3146strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
3147weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00003148
sewardj5e657c32003-10-12 08:33:30 +00003149/* POSIX spinlocks, taken from glibc linuxthreads/sysdeps/i386 */
3150
3151typedef volatile int pthread_spinlock_t; /* Huh? Guarded by __USE_XOPEN2K */
3152
3153int pthread_spin_init(pthread_spinlock_t *lock, int pshared)
3154{
3155 /* We can ignore the `pshared' parameter. Since we are busy-waiting
3156 all processes which can access the memory location `lock' points
3157 to can use the spinlock. */
3158 *lock = 1;
3159 return 0;
3160}
3161
3162int pthread_spin_lock(pthread_spinlock_t *lock)
3163{
3164 asm volatile
3165 ("\n"
3166 "1:\n\t"
3167 "lock; decl %0\n\t"
3168 "js 2f\n\t"
3169 ".section .text.spinlock,\"ax\"\n"
3170 "2:\n\t"
3171 "cmpl $0,%0\n\t"
3172 "rep; nop\n\t"
3173 "jle 2b\n\t"
3174 "jmp 1b\n\t"
3175 ".previous"
3176 : "=m" (*lock));
3177 return 0;
3178}
3179
3180int pthread_spin_unlock(pthread_spinlock_t *lock)
3181{
3182 asm volatile
3183 ("movl $1,%0"
3184 : "=m" (*lock));
3185 return 0;
3186}
3187
3188int pthread_spin_destroy(pthread_spinlock_t *lock)
3189{
3190 /* Nothing to do. */
3191 return 0;
3192}
3193
3194int pthread_spin_trylock(pthread_spinlock_t *lock)
3195{
3196 int oldval;
3197
3198 asm volatile
3199 ("xchgl %0,%1"
3200 : "=r" (oldval), "=m" (*lock)
3201 : "0" (0));
3202 return oldval > 0 ? 0 : EBUSY;
3203}
sewardj439d45e2002-05-03 20:43:10 +00003204
3205/*--------------------------------------------------------------------*/
3206/*--- end vg_libpthread.c ---*/
3207/*--------------------------------------------------------------------*/