blob: 098c7f7a754b06f67b38f87349717592df528abd [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))
sewardje663cb92002-04-12 10:26:32 +0000178void barf ( char* str )
179{
sewardj69a72a52002-11-03 13:41:41 +0000180 char buf[1000];
sewardje663cb92002-04-12 10:26:32 +0000181 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000182 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000183 strcat(buf, str);
184 strcat(buf, "\n\n");
njn4c791212003-05-02 17:53:54 +0000185 VALGRIND_NON_SIMD_CALL2(VG_(message), Vg_UserMsg, buf);
sewardj2d94c112002-06-03 01:25:54 +0000186 my_exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000187 /* We have to persuade gcc into believing this doesn't return. */
188 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000189}
190
191
sewardj69a72a52002-11-03 13:41:41 +0000192static void cat_n_send ( char* pre, char* msg )
sewardj2a3d28c2002-04-14 13:27:00 +0000193{
sewardj69a72a52002-11-03 13:41:41 +0000194 char buf[1000];
sewardj436e0582002-04-26 14:31:40 +0000195 if (get_pt_trace_level() >= 0) {
sewardj69a72a52002-11-03 13:41:41 +0000196 snprintf(buf, sizeof(buf), "%s%s", pre, msg );
197 buf[sizeof(buf)-1] = '\0';
njn4c791212003-05-02 17:53:54 +0000198 VALGRIND_NON_SIMD_CALL2(VG_(message), Vg_UserMsg, buf);
sewardj45b4b372002-04-16 22:50:32 +0000199 }
sewardj2a3d28c2002-04-14 13:27:00 +0000200}
201
sewardj69a72a52002-11-03 13:41:41 +0000202static void ignored ( char* msg )
203{
204 cat_n_send ( "valgrind's libpthread.so: IGNORED call to: ", msg );
205}
206
207
sewardj30671ff2002-04-21 00:13:57 +0000208static void kludged ( char* msg )
209{
sewardj69a72a52002-11-03 13:41:41 +0000210 cat_n_send ( "valgrind's libpthread.so: KLUDGED call to: ", msg );
sewardj439d45e2002-05-03 20:43:10 +0000211}
212
sewardj69a72a52002-11-03 13:41:41 +0000213
sewardjccef2e62002-05-29 19:26:32 +0000214__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000215void vgPlain_unimp ( char* what )
216{
sewardj69a72a52002-11-03 13:41:41 +0000217 cat_n_send (
218 "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ", what );
sewardj3b13f0e2002-04-25 20:17:29 +0000219 barf("Please report this bug to me at: jseward@acm.org");
220}
221
sewardje663cb92002-04-12 10:26:32 +0000222
sewardj457cc472002-06-03 23:13:47 +0000223static
sewardj2d94c112002-06-03 01:25:54 +0000224void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
225{
sewardj69a72a52002-11-03 13:41:41 +0000226 char buf[1000];
sewardj2d94c112002-06-03 01:25:54 +0000227 static Bool entered = False;
228 if (entered)
229 my_exit(2);
230 entered = True;
sewardj69a72a52002-11-03 13:41:41 +0000231 sprintf(buf, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
232 "valgrind", file, line, fn, expr );
233 cat_n_send ( "", buf );
234 sprintf(buf, "Please report this bug to me at: %s\n\n",
235 VG_EMAIL_ADDR);
236 cat_n_send ( "", buf );
sewardj2d94c112002-06-03 01:25:54 +0000237 my_exit(1);
238}
239
240#define MY__STRING(__str) #__str
241
242#define my_assert(expr) \
243 ((void) ((expr) ? 0 : \
244 (my_assert_fail (MY__STRING(expr), \
245 __FILE__, __LINE__, \
246 __PRETTY_FUNCTION__), 0)))
247
sewardj00a66b12002-10-12 16:42:35 +0000248static
249void my_free ( void* ptr )
250{
251 int res;
252 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
253 VG_USERREQ__FREE, ptr, 0, 0, 0);
254 my_assert(res == 0);
255}
256
257
258static
259void* my_malloc ( int nbytes )
260{
261 void* res;
262 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
263 VG_USERREQ__MALLOC, nbytes, 0, 0, 0);
264 my_assert(res != (void*)0);
265 return res;
266}
267
268
sewardj2d94c112002-06-03 01:25:54 +0000269
sewardje663cb92002-04-12 10:26:32 +0000270/* ---------------------------------------------------------------------
271 Pass pthread_ calls to Valgrind's request mechanism.
272 ------------------------------------------------------------------ */
273
sewardjf8f819e2002-04-17 23:21:37 +0000274#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000275#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000276
sewardja1ac5cb2002-05-27 13:00:05 +0000277
sewardjf8f819e2002-04-17 23:21:37 +0000278/* ---------------------------------------------------
sewardj4dced352002-06-04 22:54:20 +0000279 Ummm ..
280 ------------------------------------------------ */
281
282static
283void pthread_error ( const char* msg )
284{
285 int res;
286 VALGRIND_MAGIC_SEQUENCE(res, 0,
287 VG_USERREQ__PTHREAD_ERROR,
288 msg, 0, 0, 0);
289}
290
291
292/* ---------------------------------------------------
sewardj00a66b12002-10-12 16:42:35 +0000293 Here so it can be inlined without complaint.
294 ------------------------------------------------ */
295
296__inline__
297pthread_t pthread_self(void)
298{
299 int tid;
300 ensure_valgrind("pthread_self");
301 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
302 VG_USERREQ__PTHREAD_GET_THREADID,
303 0, 0, 0, 0);
304 if (tid < 1 || tid >= VG_N_THREADS)
305 barf("pthread_self: invalid ThreadId");
306 return tid;
307}
308
309
310/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000311 THREAD ATTRIBUTES
312 ------------------------------------------------ */
313
sewardj6af4b5d2002-04-16 04:40:49 +0000314int pthread_attr_init(pthread_attr_t *attr)
315{
sewardj7989d0c2002-05-28 11:00:01 +0000316 /* Just initialise the fields which we might look at. */
317 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj111b14c2002-10-20 16:22:57 +0000318 /* Linuxthreads sets this field to the value __getpagesize(), so I
319 guess the following is OK. */
320 attr->__guardsize = VKI_BYTES_PER_PAGE; return 0;
sewardj6af4b5d2002-04-16 04:40:49 +0000321}
322
323int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
324{
sewardj7989d0c2002-05-28 11:00:01 +0000325 if (detachstate != PTHREAD_CREATE_JOINABLE
sewardj4dced352002-06-04 22:54:20 +0000326 && detachstate != PTHREAD_CREATE_DETACHED) {
327 pthread_error("pthread_attr_setdetachstate: "
328 "detachstate is invalid");
sewardj7989d0c2002-05-28 11:00:01 +0000329 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000330 }
sewardj7989d0c2002-05-28 11:00:01 +0000331 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000332 return 0;
333}
334
njn25e49d8e72002-09-23 09:36:25 +0000335int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
336{
337 *detachstate = attr->__detachstate;
338 return 0;
339}
340
sewardj30671ff2002-04-21 00:13:57 +0000341int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
342{
sewardj436e0582002-04-26 14:31:40 +0000343 static int moans = N_MOANS;
344 if (moans-- > 0)
345 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000346 return 0;
347}
sewardj6af4b5d2002-04-16 04:40:49 +0000348
sewardj11f0bb42003-04-26 20:11:15 +0000349WEAK
sewardj0286dd52002-05-16 20:51:15 +0000350int pthread_attr_setstacksize (pthread_attr_t *__attr,
351 size_t __stacksize)
352{
sewardja18e2102002-05-18 10:43:22 +0000353 size_t limit;
sewardj3d7c8d62002-06-04 20:59:16 +0000354 char buf[1024];
sewardj0286dd52002-05-16 20:51:15 +0000355 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000356 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
357 - 1000; /* paranoia */
358 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000359 return 0;
sewardj3d7c8d62002-06-04 20:59:16 +0000360 snprintf(buf, sizeof(buf), "pthread_attr_setstacksize: "
361 "requested size %d >= VG_PTHREAD_STACK_SIZE\n "
362 "edit vg_include.h and rebuild.", __stacksize);
363 buf[sizeof(buf)-1] = '\0'; /* Make sure it is zero terminated */
364 barf(buf);
sewardj0286dd52002-05-16 20:51:15 +0000365}
366
367
sewardj30671ff2002-04-21 00:13:57 +0000368/* This is completely bogus. */
369int pthread_attr_getschedparam(const pthread_attr_t *attr,
370 struct sched_param *param)
371{
sewardj436e0582002-04-26 14:31:40 +0000372 static int moans = N_MOANS;
373 if (moans-- > 0)
374 kludged("pthread_attr_getschedparam");
sewardj3e909ce2002-06-03 13:27:15 +0000375# ifdef HAVE_SCHED_PRIORITY
sewardj72d58482002-04-24 02:20:20 +0000376 if (param) param->sched_priority = 0; /* who knows */
377# else
sewardj30671ff2002-04-21 00:13:57 +0000378 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000379# endif
sewardj30671ff2002-04-21 00:13:57 +0000380 return 0;
381}
382
383int pthread_attr_setschedparam(pthread_attr_t *attr,
384 const struct sched_param *param)
385{
sewardj436e0582002-04-26 14:31:40 +0000386 static int moans = N_MOANS;
387 if (moans-- > 0)
388 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000389 return 0;
390}
391
392int pthread_attr_destroy(pthread_attr_t *attr)
393{
sewardj436e0582002-04-26 14:31:40 +0000394 static int moans = N_MOANS;
395 if (moans-- > 0)
396 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000397 return 0;
398}
sewardjf8f819e2002-04-17 23:21:37 +0000399
sewardj0d844232002-06-02 09:29:31 +0000400/* These are no-ops, as with LinuxThreads. */
401int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
402{
403 ensure_valgrind("pthread_attr_setscope");
404 if (scope == PTHREAD_SCOPE_SYSTEM)
405 return 0;
sewardj4dced352002-06-04 22:54:20 +0000406 pthread_error("pthread_attr_setscope: "
407 "invalid or unsupported scope");
sewardj0d844232002-06-02 09:29:31 +0000408 if (scope == PTHREAD_SCOPE_PROCESS)
409 return ENOTSUP;
410 return EINVAL;
411}
412
413int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
414{
415 ensure_valgrind("pthread_attr_setscope");
416 if (scope)
417 *scope = PTHREAD_SCOPE_SYSTEM;
418 return 0;
419}
420
sewardj64039bb2002-06-03 00:58:18 +0000421
422/* Pretty bogus. Avoid if possible. */
423int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
424{
425 int detached;
426 size_t limit;
427 ensure_valgrind("pthread_getattr_np");
428 kludged("pthread_getattr_np");
429 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
430 - 1000; /* paranoia */
431 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
432 attr->__schedpolicy = SCHED_OTHER;
433 attr->__schedparam.sched_priority = 0;
434 attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
435 attr->__scope = PTHREAD_SCOPE_SYSTEM;
436 attr->__guardsize = VKI_BYTES_PER_PAGE;
437 attr->__stackaddr = NULL;
438 attr->__stackaddr_set = 0;
439 attr->__stacksize = limit;
440 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
441 VG_USERREQ__SET_OR_GET_DETACH,
442 2 /* get */, thread, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000443 my_assert(detached == 0 || detached == 1);
sewardj64039bb2002-06-03 00:58:18 +0000444 if (detached)
445 attr->__detachstate = PTHREAD_CREATE_DETACHED;
446 return 0;
447}
448
449
450/* Bogus ... */
sewardj11f0bb42003-04-26 20:11:15 +0000451WEAK
sewardj64039bb2002-06-03 00:58:18 +0000452int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
453 void ** stackaddr )
454{
455 ensure_valgrind("pthread_attr_getstackaddr");
456 kludged("pthread_attr_getstackaddr");
457 if (stackaddr)
458 *stackaddr = NULL;
459 return 0;
460}
461
462/* Not bogus (!) */
sewardj11f0bb42003-04-26 20:11:15 +0000463WEAK
sewardj64039bb2002-06-03 00:58:18 +0000464int pthread_attr_getstacksize ( const pthread_attr_t * _attr,
465 size_t * __stacksize )
466{
467 size_t limit;
468 ensure_valgrind("pthread_attr_getstacksize");
469 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
470 - 1000; /* paranoia */
471 if (__stacksize)
472 *__stacksize = limit;
473 return 0;
474}
475
sewardja3be12f2002-06-17 12:19:44 +0000476int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
477{
478 if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
479 return EINVAL;
480 attr->__schedpolicy = policy;
481 return 0;
482}
483
484int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
485{
486 *policy = attr->__schedpolicy;
487 return 0;
488}
489
490
sewardj111b14c2002-10-20 16:22:57 +0000491/* This is completely bogus. We reject all attempts to change it from
492 VKI_BYTES_PER_PAGE. I don't have a clue what it's for so it seems
493 safest to be paranoid. */
sewardj11f0bb42003-04-26 20:11:15 +0000494WEAK
sewardj111b14c2002-10-20 16:22:57 +0000495int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
496{
497 static int moans = N_MOANS;
498
499 if (guardsize == VKI_BYTES_PER_PAGE)
500 return 0;
501
502 if (moans-- > 0)
503 ignored("pthread_attr_setguardsize: ignoring guardsize != 4096");
504
505 return 0;
506}
507
508/* A straight copy of the LinuxThreads code. */
sewardj11f0bb42003-04-26 20:11:15 +0000509WEAK
sewardj111b14c2002-10-20 16:22:57 +0000510int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
511{
512 *guardsize = attr->__guardsize;
513 return 0;
514}
515
sewardjab2e1232002-12-26 12:16:11 +0000516/* Again, like LinuxThreads. */
517
518static int concurrency_current_level = 0;
519
sewardj11f0bb42003-04-26 20:11:15 +0000520WEAK
sewardjb34e4db2002-12-08 23:51:32 +0000521int pthread_setconcurrency(int new_level)
522{
523 if (new_level < 0)
524 return EINVAL;
sewardjab2e1232002-12-26 12:16:11 +0000525 else {
526 concurrency_current_level = new_level;
sewardjb34e4db2002-12-08 23:51:32 +0000527 return 0;
sewardjab2e1232002-12-26 12:16:11 +0000528 }
sewardjb34e4db2002-12-08 23:51:32 +0000529}
530
sewardj11f0bb42003-04-26 20:11:15 +0000531WEAK
sewardjab2e1232002-12-26 12:16:11 +0000532int pthread_getconcurrency(void)
533{
534 return concurrency_current_level;
535}
536
537
sewardj111b14c2002-10-20 16:22:57 +0000538
sewardj20917d82002-05-28 01:36:45 +0000539/* ---------------------------------------------------
540 Helper functions for running a thread
541 and for clearing up afterwards.
542 ------------------------------------------------ */
543
544/* All exiting threads eventually pass through here, bearing the
545 return value, or PTHREAD_CANCELED, in ret_val. */
546static
547__attribute__((noreturn))
548void thread_exit_wrapper ( void* ret_val )
549{
sewardj870497a2002-05-29 01:06:47 +0000550 int detached, res;
551 CleanupEntry cu;
552 pthread_key_t key;
sewardj00a66b12002-10-12 16:42:35 +0000553 void** specifics_ptr;
sewardj870497a2002-05-29 01:06:47 +0000554
sewardj20917d82002-05-28 01:36:45 +0000555 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000556 while (1) {
557 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
558 VG_USERREQ__CLEANUP_POP,
559 &cu, 0, 0, 0);
560 if (res == -1) break; /* stack empty */
sewardj2d94c112002-06-03 01:25:54 +0000561 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000562 if (0) printf("running exit cleanup handler");
563 cu.fn ( cu.arg );
564 }
565
sewardj870497a2002-05-29 01:06:47 +0000566 /* Run this thread's key finalizers. Really this should be run
567 PTHREAD_DESTRUCTOR_ITERATIONS times. */
568 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
569 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
570 VG_USERREQ__GET_KEY_D_AND_S,
571 key, &cu, 0, 0 );
572 if (res == 0) {
573 /* valid key */
574 if (cu.fn && cu.arg)
575 cu.fn /* destructor for key */
576 ( cu.arg /* specific for key for this thread */ );
577 continue;
578 }
sewardj2d94c112002-06-03 01:25:54 +0000579 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000580 }
sewardj20917d82002-05-28 01:36:45 +0000581
sewardj00a66b12002-10-12 16:42:35 +0000582 /* Free up my specifics space, if any. */
583 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
584 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
585 pthread_self(), 0, 0, 0);
586 my_assert(specifics_ptr != (void**)3);
587 my_assert(specifics_ptr != (void**)1); /* 1 means invalid thread */
588 if (specifics_ptr != NULL)
589 my_free(specifics_ptr);
590
sewardj20917d82002-05-28 01:36:45 +0000591 /* Decide on my final disposition. */
592 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
593 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000594 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000595 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000596
597 if (detached) {
598 /* Detached; I just quit right now. */
599 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
600 VG_USERREQ__QUIT, 0, 0, 0, 0);
601 } else {
602 /* Not detached; so I wait for a joiner. */
603 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
604 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
605 }
606 /* NOTREACHED */
607 barf("thread_exit_wrapper: still alive?!");
608}
609
610
611/* This function is a wrapper function for running a thread. It runs
612 the root function specified in pthread_create, and then, should the
613 root function return a value, it arranges to run the thread's
614 cleanup handlers and exit correctly. */
615
sewardj728a5272002-06-20 10:25:37 +0000616/* Struct used to convey info from pthread_create to thread_wrapper.
617 Must be careful not to pass to the child thread any pointers to
618 objects which might be on the parent's stack. */
sewardj20917d82002-05-28 01:36:45 +0000619typedef
620 struct {
sewardj728a5272002-06-20 10:25:37 +0000621 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000622 void* (*root_fn) ( void* );
623 void* arg;
624 }
625 NewThreadInfo;
626
627
628/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
629 not return. Note that this runs in the new thread, not the
630 parent. */
631static
632__attribute__((noreturn))
633void thread_wrapper ( NewThreadInfo* info )
634{
sewardj728a5272002-06-20 10:25:37 +0000635 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000636 void* (*root_fn) ( void* );
637 void* arg;
638 void* ret_val;
639
sewardj728a5272002-06-20 10:25:37 +0000640 attr__detachstate = info->attr__detachstate;
641 root_fn = info->root_fn;
642 arg = info->arg;
sewardj20917d82002-05-28 01:36:45 +0000643
sewardj20917d82002-05-28 01:36:45 +0000644 /* Free up the arg block that pthread_create malloced. */
sewardj00a66b12002-10-12 16:42:35 +0000645 my_free(info);
sewardj20917d82002-05-28 01:36:45 +0000646
sewardj7989d0c2002-05-28 11:00:01 +0000647 /* Minimally observe the attributes supplied. */
sewardj728a5272002-06-20 10:25:37 +0000648 if (attr__detachstate != PTHREAD_CREATE_DETACHED
649 && attr__detachstate != PTHREAD_CREATE_JOINABLE)
650 pthread_error("thread_wrapper: invalid attr->__detachstate");
651 if (attr__detachstate == PTHREAD_CREATE_DETACHED)
652 pthread_detach(pthread_self());
sewardj7989d0c2002-05-28 11:00:01 +0000653
sewardj00a66b12002-10-12 16:42:35 +0000654# ifdef GLIBC_2_3
655 /* Set this thread's locale to the global (default) locale. A hack
656 in support of glibc-2.3. This does the biz for the all new
657 threads; the root thread is done with a horrible hack in
658 init_libc_tsd_keys() below.
659 */
660 __uselocale(LC_GLOBAL_LOCALE);
661# endif
662
sewardj20917d82002-05-28 01:36:45 +0000663 /* The root function might not return. But if it does we simply
664 move along to thread_exit_wrapper. All other ways out for the
665 thread (cancellation, or calling pthread_exit) lead there
666 too. */
667 ret_val = root_fn(arg);
668 thread_exit_wrapper(ret_val);
669 /* NOTREACHED */
670}
671
672
sewardjf8f819e2002-04-17 23:21:37 +0000673/* ---------------------------------------------------
674 THREADs
675 ------------------------------------------------ */
676
sewardj11f0bb42003-04-26 20:11:15 +0000677WEAK
sewardjff42d1d2002-05-22 13:17:31 +0000678int pthread_yield ( void )
679{
680 int res;
681 ensure_valgrind("pthread_yield");
682 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
683 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
684 return 0;
685}
686
687
sewardj6072c362002-04-19 14:40:57 +0000688int pthread_equal(pthread_t thread1, pthread_t thread2)
689{
690 return thread1 == thread2 ? 1 : 0;
691}
692
693
sewardj20917d82002-05-28 01:36:45 +0000694/* Bundle up the args into a malloc'd block and create a new thread
695 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000696int
sewardj1462c8b2002-07-24 09:41:52 +0000697pthread_create (pthread_t *__restrict __thredd,
sewardje663cb92002-04-12 10:26:32 +0000698 __const pthread_attr_t *__restrict __attr,
699 void *(*__start_routine) (void *),
700 void *__restrict __arg)
701{
sewardj20917d82002-05-28 01:36:45 +0000702 int tid_child;
703 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000704
sewardj20917d82002-05-28 01:36:45 +0000705 ensure_valgrind("pthread_create");
706
sewardj00a66b12002-10-12 16:42:35 +0000707 /* make sure the tsd keys, and hence locale info, are initialised
708 before we get into complications making new threads. */
709 init_libc_tsd_keys();
710
sewardj20917d82002-05-28 01:36:45 +0000711 /* Allocate space for the arg block. thread_wrapper will free
712 it. */
sewardj00a66b12002-10-12 16:42:35 +0000713 info = my_malloc(sizeof(NewThreadInfo));
sewardj2d94c112002-06-03 01:25:54 +0000714 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000715
sewardj728a5272002-06-20 10:25:37 +0000716 if (__attr)
717 info->attr__detachstate = __attr->__detachstate;
718 else
719 info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
720
sewardj20917d82002-05-28 01:36:45 +0000721 info->root_fn = __start_routine;
722 info->arg = __arg;
723 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
724 VG_USERREQ__APPLY_IN_NEW_THREAD,
725 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000726 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000727
sewardj1462c8b2002-07-24 09:41:52 +0000728 if (__thredd)
729 *__thredd = tid_child;
sewardj20917d82002-05-28 01:36:45 +0000730 return 0; /* success */
731}
sewardje663cb92002-04-12 10:26:32 +0000732
733
734int
735pthread_join (pthread_t __th, void **__thread_return)
736{
737 int res;
738 ensure_valgrind("pthread_join");
739 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
740 VG_USERREQ__PTHREAD_JOIN,
741 __th, __thread_return, 0, 0);
742 return res;
743}
744
745
sewardj3b5d8862002-04-20 13:53:23 +0000746void pthread_exit(void *retval)
747{
sewardj3b5d8862002-04-20 13:53:23 +0000748 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000749 /* Simple! */
750 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000751}
752
sewardje663cb92002-04-12 10:26:32 +0000753
sewardj853f55d2002-04-26 00:27:53 +0000754int pthread_detach(pthread_t th)
755{
sewardj20917d82002-05-28 01:36:45 +0000756 int res;
757 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000758 /* First we enquire as to the current detach state. */
759 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000760 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000761 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000762 if (res == -1) {
763 /* not found */
764 pthread_error("pthread_detach: "
765 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000766 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000767 }
768 if (res == 1) {
769 /* already detached */
770 pthread_error("pthread_detach: "
771 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000772 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000773 }
sewardj7989d0c2002-05-28 11:00:01 +0000774 if (res == 0) {
775 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
776 VG_USERREQ__SET_OR_GET_DETACH,
777 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000778 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000779 return 0;
780 }
781 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000782}
783
784
sewardjf8f819e2002-04-17 23:21:37 +0000785/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000786 CLEANUP STACKS
787 ------------------------------------------------ */
788
789void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
790 void (*__routine) (void *),
791 void *__arg)
792{
793 int res;
794 CleanupEntry cu;
795 ensure_valgrind("_pthread_cleanup_push");
796 cu.fn = __routine;
797 cu.arg = __arg;
798 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
799 VG_USERREQ__CLEANUP_PUSH,
800 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000801 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000802}
803
804
805void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
806 void (*__routine) (void *),
807 void *__arg)
808{
809 /* As _pthread_cleanup_push, but first save the thread's original
810 cancellation type in __buffer and set it to Deferred. */
811 int orig_ctype;
812 ensure_valgrind("_pthread_cleanup_push_defer");
813 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000814 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
815 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
816 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000817 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
818 VG_USERREQ__SET_CANCELTYPE,
819 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000820 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000821 *((int*)(__buffer)) = orig_ctype;
822 /* Now push the cleanup. */
823 _pthread_cleanup_push(NULL, __routine, __arg);
824}
825
826
827void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
828 int __execute)
829{
830 int res;
831 CleanupEntry cu;
832 ensure_valgrind("_pthread_cleanup_push");
833 cu.fn = cu.arg = NULL; /* paranoia */
834 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
835 VG_USERREQ__CLEANUP_POP,
836 &cu, 0, 0, 0);
837 if (res == 0) {
838 /* pop succeeded */
839 if (__execute) {
840 cu.fn ( cu.arg );
841 }
842 return;
843 }
844 if (res == -1) {
845 /* stack underflow */
846 return;
847 }
848 barf("_pthread_cleanup_pop");
849}
850
851
852void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
853 int __execute)
854{
855 int orig_ctype, fake_ctype;
856 /* As _pthread_cleanup_pop, but after popping/running the handler,
857 restore the thread's original cancellation type from the first
858 word of __buffer. */
859 _pthread_cleanup_pop(NULL, __execute);
860 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000861 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000862 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000863 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
864 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
865 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000866 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
867 VG_USERREQ__SET_CANCELTYPE,
868 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000869 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000870}
871
872
873/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000874 MUTEX ATTRIBUTES
875 ------------------------------------------------ */
876
sewardj5905fae2002-04-26 13:25:00 +0000877int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000878{
sewardjf8f819e2002-04-17 23:21:37 +0000879 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000880 return 0;
sewardje663cb92002-04-12 10:26:32 +0000881}
882
sewardj5905fae2002-04-26 13:25:00 +0000883int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000884{
885 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000886# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000887 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000888 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000889# endif
sewardja1679dd2002-05-10 22:31:40 +0000890# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000891 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000892# endif
sewardjf8f819e2002-04-17 23:21:37 +0000893 case PTHREAD_MUTEX_RECURSIVE_NP:
894 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000895 attr->__mutexkind = type;
896 return 0;
897 default:
sewardj4dced352002-06-04 22:54:20 +0000898 pthread_error("pthread_mutexattr_settype: "
899 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000900 return EINVAL;
901 }
902}
903
sewardj5905fae2002-04-26 13:25:00 +0000904int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000905{
906 return 0;
907}
908
sewardj7685cae2003-07-06 01:23:11 +0000909int pthread_mutexattr_setpshared ( pthread_mutexattr_t* attr, int pshared)
910{
911 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
912 return EINVAL;
913
914 /* For now it is not possible to shared a conditional variable. */
915 if (pshared != PTHREAD_PROCESS_PRIVATE)
916 return ENOSYS;
917
918 return 0;
919}
920
sewardjf8f819e2002-04-17 23:21:37 +0000921
922/* ---------------------------------------------------
923 MUTEXes
924 ------------------------------------------------ */
925
sewardj5905fae2002-04-26 13:25:00 +0000926int __pthread_mutex_init(pthread_mutex_t *mutex,
927 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000928{
sewardj604ec3c2002-04-18 22:38:41 +0000929 mutex->__m_count = 0;
930 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
931 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
932 if (mutexattr)
933 mutex->__m_kind = mutexattr->__mutexkind;
934 return 0;
sewardje663cb92002-04-12 10:26:32 +0000935}
936
sewardj439d45e2002-05-03 20:43:10 +0000937
sewardj5905fae2002-04-26 13:25:00 +0000938int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000939{
940 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000941
sewardj439d45e2002-05-03 20:43:10 +0000942 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000943 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
944 VG_USERREQ__PTHREAD_MUTEX_LOCK,
945 mutex, 0, 0, 0);
946 return res;
sewardj439d45e2002-05-03 20:43:10 +0000947 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000948 /* Play at locking */
949 if (0)
950 kludged("prehistoric lock");
951 mutex->__m_owner = (_pthread_descr)1;
952 mutex->__m_count = 1;
953 mutex->__m_kind |= VG_PTHREAD_PREHISTORY;
sewardj439d45e2002-05-03 20:43:10 +0000954 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000955 }
956}
957
sewardj439d45e2002-05-03 20:43:10 +0000958
sewardj5905fae2002-04-26 13:25:00 +0000959int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000960{
961 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000962
sewardj439d45e2002-05-03 20:43:10 +0000963 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000964 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
965 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
966 mutex, 0, 0, 0);
967 return res;
sewardj439d45e2002-05-03 20:43:10 +0000968 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000969 /* Play at locking */
970 if (0)
971 kludged("prehistoric trylock");
972 mutex->__m_owner = (_pthread_descr)1;
973 mutex->__m_count = 1;
974 mutex->__m_kind |= VG_PTHREAD_PREHISTORY;
975 return 0; /* success */
sewardj30671ff2002-04-21 00:13:57 +0000976 }
977}
978
sewardj439d45e2002-05-03 20:43:10 +0000979
sewardj5905fae2002-04-26 13:25:00 +0000980int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000981{
982 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000983
sewardj439d45e2002-05-03 20:43:10 +0000984 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000985 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
986 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
987 mutex, 0, 0, 0);
988 return res;
sewardj439d45e2002-05-03 20:43:10 +0000989 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000990 /* Play at locking */
991 if (0)
992 kludged("prehistoric unlock");
993 mutex->__m_owner = 0;
994 mutex->__m_count = 0;
995 mutex->__m_kind &= ~VG_PTHREAD_PREHISTORY;
996 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000997 }
998}
999
sewardj439d45e2002-05-03 20:43:10 +00001000
sewardj5905fae2002-04-26 13:25:00 +00001001int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +00001002{
sewardj604ec3c2002-04-18 22:38:41 +00001003 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
1004 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +00001005 if (mutex->__m_count > 0) {
sewardjd8acdf22002-11-13 21:57:52 +00001006 /* Oh, the horror. glibc's internal use of pthreads "knows"
1007 that destroying a lock does an implicit unlock. Make it
1008 explicit. */
1009 __pthread_mutex_unlock(mutex);
1010 pthread_error("pthread_mutex_destroy: "
1011 "mutex is still in use");
1012 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +00001013 }
1014 mutex->__m_count = 0;
1015 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
1016 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
1017 return 0;
sewardje663cb92002-04-12 10:26:32 +00001018}
1019
1020
sewardjf8f819e2002-04-17 23:21:37 +00001021/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +00001022 CONDITION VARIABLES
1023 ------------------------------------------------ */
1024
1025/* LinuxThreads supports no attributes for conditions. Hence ... */
1026
1027int pthread_condattr_init(pthread_condattr_t *attr)
1028{
1029 return 0;
1030}
1031
sewardj0738a592002-04-20 13:59:33 +00001032int pthread_condattr_destroy(pthread_condattr_t *attr)
1033{
1034 return 0;
1035}
sewardj6072c362002-04-19 14:40:57 +00001036
1037int pthread_cond_init( pthread_cond_t *cond,
1038 const pthread_condattr_t *cond_attr)
1039{
1040 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
1041 return 0;
1042}
1043
sewardjf854f472002-04-21 12:19:41 +00001044int pthread_cond_destroy(pthread_cond_t *cond)
1045{
1046 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +00001047 static int moans = N_MOANS;
1048 if (moans-- > 0)
1049 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +00001050 return 0;
1051}
sewardj6072c362002-04-19 14:40:57 +00001052
1053/* ---------------------------------------------------
1054 SCHEDULING
1055 ------------------------------------------------ */
1056
1057/* This is completely bogus. */
1058int pthread_getschedparam(pthread_t target_thread,
1059 int *policy,
1060 struct sched_param *param)
1061{
sewardj436e0582002-04-26 14:31:40 +00001062 static int moans = N_MOANS;
1063 if (moans-- > 0)
1064 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +00001065 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +00001066# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +00001067 if (param) param->sched_priority = 0; /* who knows */
1068# else
sewardj6072c362002-04-19 14:40:57 +00001069 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +00001070# endif
sewardj6072c362002-04-19 14:40:57 +00001071 return 0;
1072}
1073
1074int pthread_setschedparam(pthread_t target_thread,
1075 int policy,
1076 const struct sched_param *param)
1077{
sewardj436e0582002-04-26 14:31:40 +00001078 static int moans = N_MOANS;
1079 if (moans-- > 0)
1080 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +00001081 return 0;
1082}
1083
sewardj3b5d8862002-04-20 13:53:23 +00001084int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
1085{
1086 int res;
1087 ensure_valgrind("pthread_cond_wait");
1088 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1089 VG_USERREQ__PTHREAD_COND_WAIT,
1090 cond, mutex, 0, 0);
1091 return res;
1092}
1093
sewardj5f07b662002-04-23 16:52:51 +00001094int pthread_cond_timedwait ( pthread_cond_t *cond,
1095 pthread_mutex_t *mutex,
1096 const struct timespec *abstime )
1097{
1098 int res;
1099 unsigned int ms_now, ms_end;
1100 struct timeval timeval_now;
1101 unsigned long long int ull_ms_now_after_1970;
1102 unsigned long long int ull_ms_end_after_1970;
1103
1104 ensure_valgrind("pthread_cond_timedwait");
1105 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1106 VG_USERREQ__READ_MILLISECOND_TIMER,
1107 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001108 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001109 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +00001110 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001111
1112 ull_ms_now_after_1970
1113 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
1114 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
1115 ull_ms_end_after_1970
1116 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
1117 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +00001118 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
1119 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +00001120 ms_end
1121 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
1122 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1123 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
1124 cond, mutex, ms_end, 0);
1125 return res;
1126}
1127
1128
sewardj3b5d8862002-04-20 13:53:23 +00001129int pthread_cond_signal(pthread_cond_t *cond)
1130{
1131 int res;
1132 ensure_valgrind("pthread_cond_signal");
1133 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1134 VG_USERREQ__PTHREAD_COND_SIGNAL,
1135 cond, 0, 0, 0);
1136 return res;
1137}
1138
1139int pthread_cond_broadcast(pthread_cond_t *cond)
1140{
1141 int res;
1142 ensure_valgrind("pthread_cond_broadcast");
1143 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1144 VG_USERREQ__PTHREAD_COND_BROADCAST,
1145 cond, 0, 0, 0);
1146 return res;
1147}
1148
sewardj6072c362002-04-19 14:40:57 +00001149
1150/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001151 CANCELLATION
1152 ------------------------------------------------ */
1153
sewardj853f55d2002-04-26 00:27:53 +00001154int pthread_setcancelstate(int state, int *oldstate)
1155{
sewardj20917d82002-05-28 01:36:45 +00001156 int res;
1157 ensure_valgrind("pthread_setcancelstate");
1158 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +00001159 && state != PTHREAD_CANCEL_DISABLE) {
1160 pthread_error("pthread_setcancelstate: "
1161 "invalid state");
sewardj20917d82002-05-28 01:36:45 +00001162 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001163 }
sewardj2d94c112002-06-03 01:25:54 +00001164 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1165 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001166 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1167 VG_USERREQ__SET_CANCELSTATE,
1168 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001169 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001170 if (oldstate)
1171 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001172 return 0;
1173}
1174
sewardje663cb92002-04-12 10:26:32 +00001175int pthread_setcanceltype(int type, int *oldtype)
1176{
sewardj20917d82002-05-28 01:36:45 +00001177 int res;
1178 ensure_valgrind("pthread_setcanceltype");
1179 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001180 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1181 pthread_error("pthread_setcanceltype: "
1182 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001183 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001184 }
sewardj2d94c112002-06-03 01:25:54 +00001185 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1186 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001187 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1188 VG_USERREQ__SET_CANCELTYPE,
1189 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001190 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001191 if (oldtype)
1192 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001193 return 0;
1194}
1195
sewardje663cb92002-04-12 10:26:32 +00001196int pthread_cancel(pthread_t thread)
1197{
1198 int res;
1199 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001200 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1201 VG_USERREQ__SET_CANCELPEND,
1202 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001203 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001204 return res;
1205}
1206
sewardjd140e442002-05-29 01:21:19 +00001207static __inline__
1208void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001209{
sewardj20917d82002-05-28 01:36:45 +00001210 int res;
njn25e49d8e72002-09-23 09:36:25 +00001211 ensure_valgrind("__my_pthread_testcancel");
sewardj20917d82002-05-28 01:36:45 +00001212 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1213 VG_USERREQ__TESTCANCEL,
1214 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001215 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001216}
1217
sewardjd140e442002-05-29 01:21:19 +00001218void pthread_testcancel ( void )
1219{
1220 __my_pthread_testcancel();
1221}
1222
sewardj20917d82002-05-28 01:36:45 +00001223
sewardjef037c72002-05-30 00:40:03 +00001224/* Not really sure what this is for. I suspect for doing the POSIX
1225 requirements for fork() and exec(). We do this internally anyway
1226 whenever those syscalls are observed, so this could be superfluous,
1227 but hey ...
1228*/
sewardj853f55d2002-04-26 00:27:53 +00001229void __pthread_kill_other_threads_np ( void )
1230{
sewardjef037c72002-05-30 00:40:03 +00001231 int res;
1232 ensure_valgrind("__pthread_kill_other_threads_np");
1233 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1234 VG_USERREQ__NUKE_OTHER_THREADS,
1235 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001236 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001237}
1238
sewardje663cb92002-04-12 10:26:32 +00001239
sewardjf8f819e2002-04-17 23:21:37 +00001240/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001241 SIGNALS
1242 ------------------------------------------------ */
1243
1244#include <signal.h>
1245
1246int pthread_sigmask(int how, const sigset_t *newmask,
1247 sigset_t *oldmask)
1248{
1249 int res;
1250
1251 /* A bit subtle, because the scheduler expects newmask and oldmask
1252 to be vki_sigset_t* rather than sigset_t*, and the two are
1253 different. Fortunately the first 64 bits of a sigset_t are
1254 exactly a vki_sigset_t, so we just pass the pointers through
1255 unmodified. Haaaack!
1256
1257 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001258 constants to VKI_ constants, so that the former do not have to
1259 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001260
1261 ensure_valgrind("pthread_sigmask");
1262
1263 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001264 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1265 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1266 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001267 default: pthread_error("pthread_sigmask: invalid how");
1268 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001269 }
1270
1271 /* Crude check */
1272 if (newmask == NULL)
1273 return EFAULT;
1274
1275 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1276 VG_USERREQ__PTHREAD_SIGMASK,
1277 how, newmask, oldmask, 0);
1278
1279 /* The scheduler tells us of any memory violations. */
1280 return res == 0 ? 0 : EFAULT;
1281}
1282
1283
1284int sigwait ( const sigset_t* set, int* sig )
1285{
1286 int res;
1287 ensure_valgrind("sigwait");
1288 /* As with pthread_sigmask we deliberately confuse sigset_t with
1289 vki_ksigset_t. */
1290 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1291 VG_USERREQ__SIGWAIT,
1292 set, sig, 0, 0);
1293 return res;
1294}
1295
1296
sewardj018f7622002-05-15 21:13:39 +00001297int pthread_kill(pthread_t thread, int signo)
1298{
1299 int res;
1300 ensure_valgrind("pthread_kill");
1301 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1302 VG_USERREQ__PTHREAD_KILL,
1303 thread, signo, 0, 0);
1304 return res;
1305}
1306
1307
sewardj3665ded2002-05-16 16:57:25 +00001308/* Copied verbatim from Linuxthreads */
1309/* Redefine raise() to send signal to calling thread only,
1310 as per POSIX 1003.1c */
1311int raise (int sig)
1312{
1313 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001314 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001315 return 0;
sewardj4dced352002-06-04 22:54:20 +00001316 } else {
sewardj25418ae2003-05-09 23:40:34 +00001317 *(__errno_location()) = retcode;
sewardj3665ded2002-05-16 16:57:25 +00001318 return -1;
1319 }
1320}
1321
1322
sewardj9a2224b2002-06-19 10:17:40 +00001323int pause ( void )
1324{
1325 unsigned int n_orig, n_now;
1326 struct vki_timespec nanosleep_interval;
1327 ensure_valgrind("pause");
1328
1329 /* This is surely a cancellation point. */
1330 __my_pthread_testcancel();
1331
1332 VALGRIND_MAGIC_SEQUENCE(n_orig, 0xFFFFFFFF /* default */,
1333 VG_USERREQ__GET_N_SIGS_RETURNED,
1334 0, 0, 0, 0);
1335 my_assert(n_orig != 0xFFFFFFFF);
1336
1337 while (1) {
1338 VALGRIND_MAGIC_SEQUENCE(n_now, 0xFFFFFFFF /* default */,
1339 VG_USERREQ__GET_N_SIGS_RETURNED,
1340 0, 0, 0, 0);
1341 my_assert(n_now != 0xFFFFFFFF);
1342 my_assert(n_now >= n_orig);
1343 if (n_now != n_orig) break;
1344
1345 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001346 nanosleep_interval.tv_nsec = 12 * 1000 * 1000; /* 12 milliseconds */
sewardj9a2224b2002-06-19 10:17:40 +00001347 /* It's critical here that valgrind's nanosleep implementation
1348 is nonblocking. */
1349 (void)my_do_syscall2(__NR_nanosleep,
1350 (int)(&nanosleep_interval), (int)NULL);
1351 }
1352
sewardj25418ae2003-05-09 23:40:34 +00001353 *(__errno_location()) = EINTR;
sewardj9a2224b2002-06-19 10:17:40 +00001354 return -1;
1355}
1356
1357
sewardjb48e5002002-05-13 00:16:03 +00001358/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001359 THREAD-SPECIFICs
1360 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001361
sewardj00a66b12002-10-12 16:42:35 +00001362static
1363int key_is_valid (pthread_key_t key)
1364{
1365 int res;
1366 VALGRIND_MAGIC_SEQUENCE(res, 2 /* default */,
1367 VG_USERREQ__PTHREAD_KEY_VALIDATE,
1368 key, 0, 0, 0);
1369 my_assert(res != 2);
1370 return res;
1371}
1372
1373
1374/* Returns NULL if thread is invalid. Otherwise, if the thread
1375 already has a specifics area, return that. Otherwise allocate it
1376 one. */
1377static
1378void** get_or_allocate_specifics_ptr ( pthread_t thread )
1379{
1380 int res, i;
1381 void** specifics_ptr;
1382 ensure_valgrind("get_or_allocate_specifics_ptr");
1383
1384 /* Returns zero if the thread has no specific_ptr. One if thread
1385 is invalid. Otherwise, the specific_ptr value. This is
1386 allocated with my_malloc and so is aligned and cannot be
1387 confused with 1 or 3. */
1388 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
1389 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
1390 thread, 0, 0, 0);
1391 my_assert(specifics_ptr != (void**)3);
1392
1393 if (specifics_ptr == (void**)1)
1394 return NULL; /* invalid thread */
1395
1396 if (specifics_ptr != NULL)
1397 return specifics_ptr; /* already has a specifics ptr. */
1398
1399 /* None yet ... allocate a new one. Should never fail. */
1400 specifics_ptr = my_malloc( VG_N_THREAD_KEYS * sizeof(void*) );
1401 my_assert(specifics_ptr != NULL);
1402
1403 VALGRIND_MAGIC_SEQUENCE(res, -1 /* default */,
1404 VG_USERREQ__PTHREAD_SETSPECIFIC_PTR,
1405 specifics_ptr, 0, 0, 0);
1406 my_assert(res == 0);
1407
1408 /* POSIX sez: "Upon thread creation, the value NULL shall be
1409 associated with all defined keys in the new thread." This
1410 allocation is in effect a delayed allocation of the specific
1411 data for a thread, at its first-use. Hence we initialise it
1412 here. */
1413 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
1414 specifics_ptr[i] = NULL;
1415 }
1416
1417 return specifics_ptr;
1418}
1419
1420
sewardj5905fae2002-04-26 13:25:00 +00001421int __pthread_key_create(pthread_key_t *key,
1422 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001423{
sewardj00a66b12002-10-12 16:42:35 +00001424 void** specifics_ptr;
1425 int res, i;
sewardj5f07b662002-04-23 16:52:51 +00001426 ensure_valgrind("pthread_key_create");
sewardj00a66b12002-10-12 16:42:35 +00001427
1428 /* This writes *key if successful. It should never fail. */
1429 VALGRIND_MAGIC_SEQUENCE(res, 1 /* default */,
sewardj5f07b662002-04-23 16:52:51 +00001430 VG_USERREQ__PTHREAD_KEY_CREATE,
1431 key, destr_function, 0, 0);
sewardj00a66b12002-10-12 16:42:35 +00001432 my_assert(res == 0);
1433
1434 /* POSIX sez: "Upon key creation, the value NULL shall be
1435 associated with the new key in all active threads." */
1436 for (i = 0; i < VG_N_THREADS; i++) {
1437 specifics_ptr = get_or_allocate_specifics_ptr(i);
1438 /* we get NULL if i is an invalid thread. */
1439 if (specifics_ptr != NULL)
1440 specifics_ptr[*key] = NULL;
1441 }
1442
sewardj5f07b662002-04-23 16:52:51 +00001443 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001444}
1445
1446int pthread_key_delete(pthread_key_t key)
1447{
sewardj00a66b12002-10-12 16:42:35 +00001448 int res;
1449 ensure_valgrind("pthread_key_create");
1450 if (!key_is_valid(key))
1451 return EINVAL;
1452 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1453 VG_USERREQ__PTHREAD_KEY_DELETE,
1454 key, 0, 0, 0);
1455 my_assert(res == 0);
sewardj5e5fa512002-04-14 13:13:05 +00001456 return 0;
1457}
1458
sewardj5905fae2002-04-26 13:25:00 +00001459int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001460{
sewardj00a66b12002-10-12 16:42:35 +00001461 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001462 ensure_valgrind("pthread_setspecific");
sewardj00a66b12002-10-12 16:42:35 +00001463
1464 if (!key_is_valid(key))
1465 return EINVAL;
1466
1467 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1468 specifics_ptr[key] = (void*)pointer;
1469 return 0;
sewardj5e5fa512002-04-14 13:13:05 +00001470}
1471
sewardj5905fae2002-04-26 13:25:00 +00001472void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001473{
sewardj00a66b12002-10-12 16:42:35 +00001474 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001475 ensure_valgrind("pthread_getspecific");
sewardj00a66b12002-10-12 16:42:35 +00001476
1477 if (!key_is_valid(key))
1478 return NULL;
1479
1480 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1481 return specifics_ptr[key];
1482}
1483
1484
sewardj9aa918d2002-10-20 16:25:55 +00001485#ifdef GLIBC_2_3
sewardj00a66b12002-10-12 16:42:35 +00001486static
1487void ** __pthread_getspecific_addr(pthread_key_t key)
1488{
1489 void** specifics_ptr;
1490 ensure_valgrind("pthread_getspecific_addr");
1491
1492 if (!key_is_valid(key))
1493 return NULL;
1494
1495 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1496 return &(specifics_ptr[key]);
sewardj5e5fa512002-04-14 13:13:05 +00001497}
sewardj9aa918d2002-10-20 16:25:55 +00001498#endif
sewardjf8f819e2002-04-17 23:21:37 +00001499
1500/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001501 ONCEry
1502 ------------------------------------------------ */
1503
1504static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1505
1506
sewardj5905fae2002-04-26 13:25:00 +00001507int __pthread_once ( pthread_once_t *once_control,
1508 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001509{
1510 int res;
1511 ensure_valgrind("pthread_once");
1512
sewardj68b2dd92002-05-10 21:03:56 +00001513 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001514
daywalkerfd7c2312003-06-13 12:24:41 +00001515 /* init routine called us again ? */
1516 if (res != 0)
1517 return 0;
sewardj89d3d852002-04-24 19:21:39 +00001518
1519 if (*once_control == 0) {
1520 *once_control = 1;
1521 init_routine();
1522 }
1523
sewardj68b2dd92002-05-10 21:03:56 +00001524 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001525
1526 return 0;
1527}
1528
1529
1530/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001531 MISC
1532 ------------------------------------------------ */
1533
sewardj2cb00342002-06-28 01:46:26 +00001534static pthread_mutex_t pthread_atfork_lock
1535 = PTHREAD_MUTEX_INITIALIZER;
1536
sewardj5905fae2002-04-26 13:25:00 +00001537int __pthread_atfork ( void (*prepare)(void),
1538 void (*parent)(void),
1539 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001540{
sewardj2cb00342002-06-28 01:46:26 +00001541 int n, res;
1542 ForkHandlerEntry entry;
1543
1544 ensure_valgrind("pthread_atfork");
1545 __pthread_mutex_lock(&pthread_atfork_lock);
1546
1547 /* Fetch old counter */
1548 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1549 VG_USERREQ__GET_FHSTACK_USED,
1550 0, 0, 0, 0);
1551 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1552 if (n == VG_N_FORKHANDLERSTACK-1)
1553 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1554 "increase and recompile");
1555
1556 /* Add entry */
1557 entry.prepare = *prepare;
1558 entry.parent = *parent;
1559 entry.child = *child;
1560 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1561 VG_USERREQ__SET_FHSTACK_ENTRY,
1562 n, &entry, 0, 0);
1563 my_assert(res == 0);
1564
1565 /* Bump counter */
1566 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1567 VG_USERREQ__SET_FHSTACK_USED,
1568 n+1, 0, 0, 0);
1569 my_assert(res == 0);
1570
1571 __pthread_mutex_unlock(&pthread_atfork_lock);
1572 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001573}
1574
1575
sewardj9df78832003-05-04 12:35:54 +00001576#ifdef GLIBC_2_3
1577/* This seems to be a hook which appeared in glibc-2.3.2. */
1578int __register_atfork ( void (*prepare)(void),
1579 void (*parent)(void),
1580 void (*child)(void) )
1581{
1582 return __pthread_atfork(prepare,parent,child);
1583}
1584#endif
1585
sewardj11f0bb42003-04-26 20:11:15 +00001586WEAK
sewardjbb990782002-05-08 02:01:14 +00001587void __pthread_initialize ( void )
1588{
sewardjbea1caa2002-05-10 23:20:58 +00001589 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001590}
1591
1592
sewardj853f55d2002-04-26 00:27:53 +00001593/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001594 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001595 ------------------------------------------------ */
1596
sewardj3b13f0e2002-04-25 20:17:29 +00001597#include <resolv.h>
1598static int thread_specific_errno[VG_N_THREADS];
1599static int thread_specific_h_errno[VG_N_THREADS];
1600static struct __res_state
1601 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001602
sewardj25418ae2003-05-09 23:40:34 +00001603#undef errno
1604extern int errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001605int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001606{
1607 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001608 /* ensure_valgrind("__errno_location"); */
1609 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001610 VG_USERREQ__PTHREAD_GET_THREADID,
1611 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001612 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001613 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001614 barf("__errno_location: invalid ThreadId");
sewardj25418ae2003-05-09 23:40:34 +00001615 if (tid == 1)
1616 return &errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001617 return & thread_specific_errno[tid];
1618}
1619
sewardj25418ae2003-05-09 23:40:34 +00001620#undef h_errno
1621extern int h_errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001622int* __h_errno_location ( void )
1623{
1624 int tid;
1625 /* ensure_valgrind("__h_errno_location"); */
1626 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1627 VG_USERREQ__PTHREAD_GET_THREADID,
1628 0, 0, 0, 0);
1629 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001630 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001631 barf("__h_errno_location: invalid ThreadId");
sewardj25418ae2003-05-09 23:40:34 +00001632 if (tid == 1)
1633 return &h_errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001634 return & thread_specific_h_errno[tid];
1635}
1636
sewardjb0ff1032002-08-06 09:02:53 +00001637
1638#undef _res
1639extern struct __res_state _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001640struct __res_state* __res_state ( void )
1641{
1642 int tid;
1643 /* ensure_valgrind("__res_state"); */
1644 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1645 VG_USERREQ__PTHREAD_GET_THREADID,
1646 0, 0, 0, 0);
1647 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001648 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001649 barf("__res_state: invalid ThreadId");
sewardjb0ff1032002-08-06 09:02:53 +00001650 if (tid == 1)
1651 return & _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001652 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001653}
1654
1655
sewardj5716dbb2002-04-26 03:28:18 +00001656/* ---------------------------------------------------
1657 LIBC-PRIVATE SPECIFIC DATA
1658 ------------------------------------------------ */
1659
1660/* Relies on assumption that initial private data is NULL. This
1661 should be fixed somehow. */
1662
njn25e49d8e72002-09-23 09:36:25 +00001663/* The allowable keys (indices) (all 3 of them).
sewardj5716dbb2002-04-26 03:28:18 +00001664 From sysdeps/pthread/bits/libc-tsd.h
1665*/
sewardjcb7f08a2002-10-02 09:41:49 +00001666/* as per glibc anoncvs HEAD of 20021001. */
sewardj5716dbb2002-04-26 03:28:18 +00001667enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1668 _LIBC_TSD_KEY_DL_ERROR,
njn25e49d8e72002-09-23 09:36:25 +00001669 _LIBC_TSD_KEY_RPC_VARS,
sewardjcb7f08a2002-10-02 09:41:49 +00001670 _LIBC_TSD_KEY_LOCALE,
1671 _LIBC_TSD_KEY_CTYPE_B,
1672 _LIBC_TSD_KEY_CTYPE_TOLOWER,
1673 _LIBC_TSD_KEY_CTYPE_TOUPPER,
sewardj5716dbb2002-04-26 03:28:18 +00001674 _LIBC_TSD_KEY_N };
1675
1676/* Auto-initialising subsystem. libc_specifics_inited is set
1677 after initialisation. libc_specifics_inited_mx guards it. */
1678static int libc_specifics_inited = 0;
1679static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1680
sewardj00a66b12002-10-12 16:42:35 +00001681
sewardj5716dbb2002-04-26 03:28:18 +00001682/* These are the keys we must initialise the first time. */
sewardjcb7f08a2002-10-02 09:41:49 +00001683static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N];
sewardj5716dbb2002-04-26 03:28:18 +00001684
sewardj00a66b12002-10-12 16:42:35 +00001685
sewardjcb7f08a2002-10-02 09:41:49 +00001686/* Initialise the keys, if they are not already initialised. */
sewardj5716dbb2002-04-26 03:28:18 +00001687static
1688void init_libc_tsd_keys ( void )
1689{
1690 int res, i;
1691 pthread_key_t k;
1692
sewardj08c7f012002-10-07 23:56:55 +00001693 /* Don't fall into deadlock if we get called again whilst we still
1694 hold the lock, via the __uselocale() call herein. */
1695 if (libc_specifics_inited != 0)
1696 return;
1697
1698 /* Take the lock. */
sewardj00a66b12002-10-12 16:42:35 +00001699 res = __pthread_mutex_lock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001700 if (res != 0) barf("init_libc_tsd_keys: lock");
1701
sewardj08c7f012002-10-07 23:56:55 +00001702 /* Now test again, to be sure there is no mistake. */
1703 if (libc_specifics_inited != 0) {
sewardj00a66b12002-10-12 16:42:35 +00001704 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj08c7f012002-10-07 23:56:55 +00001705 if (res != 0) barf("init_libc_tsd_keys: unlock(1)");
1706 return;
sewardj5716dbb2002-04-26 03:28:18 +00001707 }
1708
sewardj08c7f012002-10-07 23:56:55 +00001709 /* Actually do the initialisation. */
1710 /* printf("INIT libc specifics\n"); */
1711 for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
sewardj00a66b12002-10-12 16:42:35 +00001712 res = __pthread_key_create(&k, NULL);
sewardj08c7f012002-10-07 23:56:55 +00001713 if (res != 0) barf("init_libc_tsd_keys: create");
1714 libc_specifics_keys[i] = k;
1715 }
1716
1717 /* Signify init done. */
1718 libc_specifics_inited = 1;
1719
1720# ifdef GLIBC_2_3
1721 /* Set the initialising thread's locale to the global (default)
sewardj00a66b12002-10-12 16:42:35 +00001722 locale. A hack in support of glibc-2.3. This does the biz for
1723 the root thread. For all other threads we run this in
1724 thread_wrapper(), which does the real work of
1725 pthread_create(). */
1726 /* assert that we are the root thread. I don't know if this is
1727 really a valid assertion to make; if it breaks I'll reconsider
1728 it. */
1729 my_assert(pthread_self() == 1);
sewardj08c7f012002-10-07 23:56:55 +00001730 __uselocale(LC_GLOBAL_LOCALE);
1731# endif
1732
1733 /* Unlock and return. */
sewardj00a66b12002-10-12 16:42:35 +00001734 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001735 if (res != 0) barf("init_libc_tsd_keys: unlock");
1736}
1737
1738
1739static int
1740libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1741 const void * pointer )
1742{
sewardjcb7f08a2002-10-02 09:41:49 +00001743 int res;
sewardj5716dbb2002-04-26 03:28:18 +00001744 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardjcb7f08a2002-10-02 09:41:49 +00001745 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001746 barf("libc_internal_tsd_set: invalid key");
1747 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001748 res = __pthread_setspecific(libc_specifics_keys[key], pointer);
sewardj5716dbb2002-04-26 03:28:18 +00001749 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1750 return 0;
1751}
1752
1753static void *
1754libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1755{
sewardjcb7f08a2002-10-02 09:41:49 +00001756 void* v;
sewardj5716dbb2002-04-26 03:28:18 +00001757 /* printf("GET GET GET key %d\n", key); */
sewardjcb7f08a2002-10-02 09:41:49 +00001758 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001759 barf("libc_internal_tsd_get: invalid key");
1760 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001761 v = __pthread_getspecific(libc_specifics_keys[key]);
sewardj5716dbb2002-04-26 03:28:18 +00001762 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1763 return v;
1764}
1765
1766
sewardj70adeb22002-04-27 01:35:38 +00001767int (*__libc_internal_tsd_set)
1768 (enum __libc_tsd_key_t key, const void * pointer)
1769 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001770
sewardj70adeb22002-04-27 01:35:38 +00001771void* (*__libc_internal_tsd_get)
1772 (enum __libc_tsd_key_t key)
1773 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001774
1775
sewardj00a66b12002-10-12 16:42:35 +00001776#ifdef GLIBC_2_3
1777/* This one was first spotted be me in the glibc-2.2.93 sources. */
1778static void**
1779libc_internal_tsd_address ( enum __libc_tsd_key_t key )
1780{
1781 void** v;
1782 /* printf("ADDR ADDR ADDR key %d\n", key); */
1783 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
1784 barf("libc_internal_tsd_address: invalid key");
1785 init_libc_tsd_keys();
1786 v = __pthread_getspecific_addr(libc_specifics_keys[key]);
1787 return v;
1788}
1789
1790void ** (*__libc_internal_tsd_address)
1791 (enum __libc_tsd_key_t key)
1792 = libc_internal_tsd_address;
1793#endif
1794
1795
sewardje663cb92002-04-12 10:26:32 +00001796/* ---------------------------------------------------------------------
1797 These are here (I think) because they are deemed cancellation
1798 points by POSIX. For the moment we'll simply pass the call along
1799 to the corresponding thread-unaware (?) libc routine.
1800 ------------------------------------------------------------------ */
1801
sewardjd529a442002-05-04 19:49:21 +00001802#ifdef GLIBC_2_1
1803extern
1804int __sigaction
1805 (int signum,
1806 const struct sigaction *act,
1807 struct sigaction *oldact);
1808#else
sewardje663cb92002-04-12 10:26:32 +00001809extern
1810int __libc_sigaction
1811 (int signum,
1812 const struct sigaction *act,
1813 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001814#endif
sewardje663cb92002-04-12 10:26:32 +00001815int sigaction(int signum,
1816 const struct sigaction *act,
1817 struct sigaction *oldact)
1818{
sewardjd140e442002-05-29 01:21:19 +00001819 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001820# ifdef GLIBC_2_1
1821 return __sigaction(signum, act, oldact);
1822# else
sewardj45b4b372002-04-16 22:50:32 +00001823 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001824# endif
sewardje663cb92002-04-12 10:26:32 +00001825}
1826
1827
1828extern
1829int __libc_connect(int sockfd,
1830 const struct sockaddr *serv_addr,
1831 socklen_t addrlen);
sewardj11f0bb42003-04-26 20:11:15 +00001832WEAK
sewardje663cb92002-04-12 10:26:32 +00001833int connect(int sockfd,
1834 const struct sockaddr *serv_addr,
1835 socklen_t addrlen)
1836{
sewardjd140e442002-05-29 01:21:19 +00001837 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001838 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001839}
1840
1841
1842extern
1843int __libc_fcntl(int fd, int cmd, long arg);
sewardj11f0bb42003-04-26 20:11:15 +00001844WEAK
sewardje663cb92002-04-12 10:26:32 +00001845int fcntl(int fd, int cmd, long arg)
1846{
sewardjd140e442002-05-29 01:21:19 +00001847 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001848 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001849}
1850
1851
1852extern
1853ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj11f0bb42003-04-26 20:11:15 +00001854WEAK
sewardje663cb92002-04-12 10:26:32 +00001855ssize_t write(int fd, const void *buf, size_t count)
1856{
sewardjd140e442002-05-29 01:21:19 +00001857 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001858 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001859}
1860
1861
1862extern
1863ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj11f0bb42003-04-26 20:11:15 +00001864WEAK
sewardje663cb92002-04-12 10:26:32 +00001865ssize_t read(int fd, void *buf, size_t count)
1866{
sewardjd140e442002-05-29 01:21:19 +00001867 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001868 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001869}
1870
sewardjf912dfc2002-11-13 21:51:10 +00001871/*
1872 * Ugh, this is horrible but here goes:
1873 *
1874 * Open of a named pipe (fifo file) can block. In a threaded program,
1875 * this means that the whole thing can block. We therefore need to
1876 * make the open appear to block to the caller, but still keep polling
1877 * for everyone else.
1878 *
1879 * There are four cases:
1880 *
1881 * - the caller asked for O_NONBLOCK. The easy one: we just do it.
1882 *
1883 * - the caller asked for a blocking O_RDONLY open. We open it with
1884 * O_NONBLOCK and then use poll to wait for it to become ready.
1885 *
1886 * - the caller asked for a blocking O_WRONLY open. Unfortunately, this
1887 * will fail with ENXIO when we make it non-blocking. Doubly
1888 * unfortunate is that we can only rely on these semantics if it is
1889 * actually a fifo file; the hack is that if we see that it is a
1890 * O_WRONLY open and we get ENXIO, then stat the path and see if it
1891 * actually is a fifo. This is racy, but it is the best we can do.
1892 * If it is a fifo, then keep trying the open until it works; if not
1893 * just return the error.
1894 *
1895 * - the caller asked for a blocking O_RDWR open. Well, under Linux,
1896 * this never blocks, so we just clear the non-blocking flag and
1897 * return.
1898 *
1899 * This code assumes that for whatever we open, O_NONBLOCK followed by
1900 * a fcntl clearing O_NONBLOCK is the same as opening without
1901 * O_NONBLOCK. Also assumes that stat and fstat have no side-effects.
1902 *
1903 * XXX Should probably put in special cases for some devices as well,
1904 * like serial ports. Unfortunately they don't work like fifos, so
1905 * this logic will become even more tortured. Wait until we really
1906 * need it.
1907 */
1908static inline int _open(const char *pathname, int flags, mode_t mode,
1909 int (*openp)(const char *, int, mode_t))
sewardjbe32e452002-04-24 20:29:58 +00001910{
sewardjf912dfc2002-11-13 21:51:10 +00001911 int fd;
1912 struct stat st;
1913 struct vki_timespec nanosleep_interval;
1914 int saved_errno;
1915
sewardjd140e442002-05-29 01:21:19 +00001916 __my_pthread_testcancel();
sewardjf912dfc2002-11-13 21:51:10 +00001917
1918 /* Assume we can only get O_RDONLY, O_WRONLY or O_RDWR */
1919 my_assert((flags & VKI_O_ACCMODE) != VKI_O_ACCMODE);
1920
1921 for(;;) {
1922 fd = (*openp)(pathname, flags | VKI_O_NONBLOCK, mode);
1923
1924 /* return immediately if caller wanted nonblocking anyway */
1925 if (flags & VKI_O_NONBLOCK)
1926 return fd;
1927
sewardj25418ae2003-05-09 23:40:34 +00001928 saved_errno = *(__errno_location());
sewardjf912dfc2002-11-13 21:51:10 +00001929
1930 if (fd != -1)
1931 break; /* open worked */
1932
1933 /* If we got ENXIO and we're opening WRONLY, and it turns out
1934 to really be a FIFO, then poll waiting for open to succeed */
sewardj25418ae2003-05-09 23:40:34 +00001935 if (*(__errno_location()) == ENXIO &&
sewardjf912dfc2002-11-13 21:51:10 +00001936 (flags & VKI_O_ACCMODE) == VKI_O_WRONLY &&
1937 (stat(pathname, &st) == 0 && S_ISFIFO(st.st_mode))) {
1938
1939 /* OK, we're opening a FIFO for writing; sleep and spin */
1940 nanosleep_interval.tv_sec = 0;
1941 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
1942 /* It's critical here that valgrind's nanosleep implementation
1943 is nonblocking. */
1944 (void)my_do_syscall2(__NR_nanosleep,
1945 (int)(&nanosleep_interval), (int)NULL);
1946 } else {
1947 /* it was just an error */
sewardj25418ae2003-05-09 23:40:34 +00001948 *(__errno_location()) = saved_errno;
sewardjf912dfc2002-11-13 21:51:10 +00001949 return -1;
1950 }
1951 }
1952
1953 /* OK, we've got a nonblocking FD for a caller who wants blocking;
1954 reset the flags to what they asked for */
1955 fcntl(fd, VKI_F_SETFL, flags);
1956
1957 /* Return now if one of:
1958 - we were opening O_RDWR (never blocks)
1959 - we opened with O_WRONLY (polling already done)
1960 - the thing we opened wasn't a FIFO after all (or fstat failed)
1961 */
1962 if ((flags & VKI_O_ACCMODE) != VKI_O_RDONLY ||
1963 (fstat(fd, &st) == -1 || !S_ISFIFO(st.st_mode))) {
sewardj25418ae2003-05-09 23:40:34 +00001964 *(__errno_location()) = saved_errno;
sewardjf912dfc2002-11-13 21:51:10 +00001965 return fd;
1966 }
1967
1968 /* OK, drop into the poll loop looking for something to read on the fd */
1969 my_assert((flags & VKI_O_ACCMODE) == VKI_O_RDONLY);
1970 for(;;) {
1971 struct pollfd pollfd;
1972 int res;
1973
1974 pollfd.fd = fd;
1975 pollfd.events = POLLIN;
1976 pollfd.revents = 0;
1977
1978 res = my_do_syscall3(__NR_poll, (int)&pollfd, 1, 0);
1979
1980 my_assert(res == 0 || res == 1);
1981
1982 if (res == 1) {
1983 /* OK, got it.
1984
1985 XXX This is wrong: we're waiting for either something to
1986 read or a HUP on the file descriptor, but the semantics of
1987 fifo open are that we should unblock as soon as someone
1988 simply opens the other end, not that they write something.
1989 With luck this won't matter in practice.
1990 */
1991 my_assert(pollfd.revents & (POLLIN|POLLHUP));
1992 break;
1993 }
1994
1995 /* Still nobody home; sleep and spin */
1996 nanosleep_interval.tv_sec = 0;
1997 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
1998 /* It's critical here that valgrind's nanosleep implementation
1999 is nonblocking. */
2000 (void)my_do_syscall2(__NR_nanosleep,
2001 (int)(&nanosleep_interval), (int)NULL);
2002 }
2003
sewardj25418ae2003-05-09 23:40:34 +00002004 *(__errno_location()) = saved_errno;
sewardjf912dfc2002-11-13 21:51:10 +00002005 return fd;
sewardjbe32e452002-04-24 20:29:58 +00002006}
2007
sewardjf912dfc2002-11-13 21:51:10 +00002008extern
2009int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj11f0bb42003-04-26 20:11:15 +00002010/* WEAK */
sewardjf912dfc2002-11-13 21:51:10 +00002011int open64(const char *pathname, int flags, mode_t mode)
2012{
2013 return _open(pathname, flags, mode, __libc_open64);
2014}
sewardje663cb92002-04-12 10:26:32 +00002015
2016extern
sewardj853f55d2002-04-26 00:27:53 +00002017int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj11f0bb42003-04-26 20:11:15 +00002018/* WEAK */
sewardj853f55d2002-04-26 00:27:53 +00002019int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00002020{
sewardjf912dfc2002-11-13 21:51:10 +00002021 return _open(pathname, flags, mode, __libc_open);
sewardje663cb92002-04-12 10:26:32 +00002022}
2023
sewardje663cb92002-04-12 10:26:32 +00002024extern
2025int __libc_close(int fd);
sewardj11f0bb42003-04-26 20:11:15 +00002026WEAK
sewardje663cb92002-04-12 10:26:32 +00002027int close(int fd)
2028{
sewardjd140e442002-05-29 01:21:19 +00002029 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002030 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00002031}
2032
2033
sewardj11f0bb42003-04-26 20:11:15 +00002034WEAK
2035int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
sewardje663cb92002-04-12 10:26:32 +00002036{
sewardj11f0bb42003-04-26 20:11:15 +00002037 return VGR_(accept)(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00002038}
2039
sewardj11f0bb42003-04-26 20:11:15 +00002040WEAK
2041int recv(int s, void *buf, size_t len, int flags)
sewardj0c573af92002-10-23 21:55:01 +00002042{
sewardj11f0bb42003-04-26 20:11:15 +00002043 return VGR_(recv)(s, buf, len, flags);
sewardj0c573af92002-10-23 21:55:01 +00002044}
2045
sewardj11f0bb42003-04-26 20:11:15 +00002046WEAK
2047int readv(int fd, const struct iovec *iov, int count)
sewardj2a68e7e2002-11-16 11:04:18 +00002048{
sewardj11f0bb42003-04-26 20:11:15 +00002049 return VGR_(readv)(fd, iov, count);
sewardj2a68e7e2002-11-16 11:04:18 +00002050}
2051
sewardj11f0bb42003-04-26 20:11:15 +00002052WEAK
2053int writev(int fd, const struct iovec *iov, int count)
sewardj2a68e7e2002-11-16 11:04:18 +00002054{
sewardj11f0bb42003-04-26 20:11:15 +00002055 return VGR_(writev)(fd, iov, count);
sewardj2a68e7e2002-11-16 11:04:18 +00002056}
sewardje663cb92002-04-12 10:26:32 +00002057
2058extern
sewardje663cb92002-04-12 10:26:32 +00002059pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj11f0bb42003-04-26 20:11:15 +00002060WEAK
sewardje663cb92002-04-12 10:26:32 +00002061pid_t waitpid(pid_t pid, int *status, int options)
2062{
sewardjd140e442002-05-29 01:21:19 +00002063 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002064 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00002065}
2066
2067
2068extern
2069int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj11f0bb42003-04-26 20:11:15 +00002070WEAK
sewardje663cb92002-04-12 10:26:32 +00002071int nanosleep(const struct timespec *req, struct timespec *rem)
2072{
sewardjd140e442002-05-29 01:21:19 +00002073 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00002074 return __libc_nanosleep(req, rem);
2075}
2076
sewardjbe32e452002-04-24 20:29:58 +00002077
sewardje663cb92002-04-12 10:26:32 +00002078extern
2079int __libc_fsync(int fd);
sewardj11f0bb42003-04-26 20:11:15 +00002080WEAK
sewardje663cb92002-04-12 10:26:32 +00002081int fsync(int fd)
2082{
sewardjd140e442002-05-29 01:21:19 +00002083 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002084 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00002085}
2086
sewardjbe32e452002-04-24 20:29:58 +00002087
sewardj70c75362002-04-13 04:18:32 +00002088extern
2089off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj11f0bb42003-04-26 20:11:15 +00002090WEAK
sewardj70c75362002-04-13 04:18:32 +00002091off_t lseek(int fildes, off_t offset, int whence)
2092{
sewardjd140e442002-05-29 01:21:19 +00002093 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002094 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00002095}
2096
sewardjbe32e452002-04-24 20:29:58 +00002097
2098extern
2099__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj11f0bb42003-04-26 20:11:15 +00002100WEAK
sewardjbe32e452002-04-24 20:29:58 +00002101__off64_t lseek64(int fildes, __off64_t offset, int whence)
2102{
sewardjd140e442002-05-29 01:21:19 +00002103 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00002104 return __libc_lseek64(fildes, offset, whence);
2105}
2106
2107
sewardj726c4122002-05-16 23:39:10 +00002108extern
2109ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
2110 __off64_t __offset);
2111ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
2112 __off64_t __offset)
2113{
sewardjd140e442002-05-29 01:21:19 +00002114 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00002115 return __libc_pread64(__fd, __buf, __nbytes, __offset);
2116}
2117
2118
sewardja18e2102002-05-18 10:43:22 +00002119extern
2120ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
2121 __off64_t __offset);
2122ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
2123 __off64_t __offset)
2124{
sewardjd140e442002-05-29 01:21:19 +00002125 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00002126 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
2127}
2128
sewardj726c4122002-05-16 23:39:10 +00002129
sewardj39b93b12002-05-18 10:56:27 +00002130extern
2131ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
sewardj11f0bb42003-04-26 20:11:15 +00002132WEAK
sewardj39b93b12002-05-18 10:56:27 +00002133ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
2134{
sewardjd140e442002-05-29 01:21:19 +00002135 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00002136 return __libc_pwrite(fd, buf, count, offset);
2137}
2138
2139
2140extern
2141ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
sewardj11f0bb42003-04-26 20:11:15 +00002142WEAK
sewardj39b93b12002-05-18 10:56:27 +00002143ssize_t pread(int fd, void *buf, size_t count, off_t offset)
2144{
sewardjd140e442002-05-29 01:21:19 +00002145 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00002146 return __libc_pread(fd, buf, count, offset);
2147}
2148
2149
sewardj6af4b5d2002-04-16 04:40:49 +00002150extern
2151void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj11f0bb42003-04-26 20:11:15 +00002152/* not weak: WEAK */
sewardj6af4b5d2002-04-16 04:40:49 +00002153void longjmp(jmp_buf env, int val)
2154{
2155 __libc_longjmp(env, val);
2156}
2157
sewardjbe32e452002-04-24 20:29:58 +00002158
sewardj436c2db2002-06-18 09:07:54 +00002159extern void __libc_siglongjmp (sigjmp_buf env, int val)
2160 __attribute__ ((noreturn));
2161void siglongjmp(sigjmp_buf env, int val)
2162{
2163 kludged("siglongjmp (cleanup handlers are ignored)");
2164 __libc_siglongjmp(env, val);
2165}
2166
2167
sewardj6af4b5d2002-04-16 04:40:49 +00002168extern
2169int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002170WEAK
sewardj6af4b5d2002-04-16 04:40:49 +00002171int send(int s, const void *msg, size_t len, int flags)
2172{
sewardjd140e442002-05-29 01:21:19 +00002173 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00002174 return __libc_send(s, msg, len, flags);
2175}
2176
sewardjbe32e452002-04-24 20:29:58 +00002177
sewardj3665ded2002-05-16 16:57:25 +00002178extern
2179int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002180WEAK
sewardj3665ded2002-05-16 16:57:25 +00002181int sendmsg(int s, const struct msghdr *msg, int flags)
2182{
sewardjd140e442002-05-29 01:21:19 +00002183 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00002184 return __libc_sendmsg(s, msg, flags);
2185}
2186
2187
sewardj796d6a22002-04-24 02:28:34 +00002188extern
sewardj59da27a2002-06-06 08:33:54 +00002189int __libc_recvmsg(int s, struct msghdr *msg, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002190WEAK
sewardj59da27a2002-06-06 08:33:54 +00002191int recvmsg(int s, struct msghdr *msg, int flags)
2192{
2193 __my_pthread_testcancel();
2194 return __libc_recvmsg(s, msg, flags);
2195}
2196
2197
2198extern
sewardj436e0582002-04-26 14:31:40 +00002199int __libc_recvfrom(int s, void *buf, size_t len, int flags,
2200 struct sockaddr *from, socklen_t *fromlen);
sewardj11f0bb42003-04-26 20:11:15 +00002201WEAK
sewardj436e0582002-04-26 14:31:40 +00002202int recvfrom(int s, void *buf, size_t len, int flags,
2203 struct sockaddr *from, socklen_t *fromlen)
2204{
sewardjd140e442002-05-29 01:21:19 +00002205 __my_pthread_testcancel();
sewardj11f0bb42003-04-26 20:11:15 +00002206 VGR_(wait_for_fd_to_be_readable_or_erring)(s);
sewardj2e207632002-06-13 17:29:53 +00002207 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00002208 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
2209}
2210
2211
2212extern
sewardj796d6a22002-04-24 02:28:34 +00002213int __libc_sendto(int s, const void *msg, size_t len, int flags,
2214 const struct sockaddr *to, socklen_t tolen);
sewardj11f0bb42003-04-26 20:11:15 +00002215WEAK
sewardj796d6a22002-04-24 02:28:34 +00002216int sendto(int s, const void *msg, size_t len, int flags,
2217 const struct sockaddr *to, socklen_t tolen)
2218{
sewardjd140e442002-05-29 01:21:19 +00002219 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00002220 return __libc_sendto(s, msg, len, flags, to, tolen);
2221}
2222
sewardjbe32e452002-04-24 20:29:58 +00002223
sewardj369b1702002-04-24 13:28:15 +00002224extern
2225int __libc_system(const char* str);
sewardj11f0bb42003-04-26 20:11:15 +00002226WEAK
sewardj369b1702002-04-24 13:28:15 +00002227int system(const char* str)
2228{
sewardjd140e442002-05-29 01:21:19 +00002229 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00002230 return __libc_system(str);
2231}
2232
sewardjbe32e452002-04-24 20:29:58 +00002233
sewardjab0b1c32002-04-24 19:26:47 +00002234extern
2235pid_t __libc_wait(int *status);
sewardj11f0bb42003-04-26 20:11:15 +00002236WEAK
sewardjab0b1c32002-04-24 19:26:47 +00002237pid_t wait(int *status)
2238{
sewardjd140e442002-05-29 01:21:19 +00002239 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00002240 return __libc_wait(status);
2241}
2242
sewardj45b4b372002-04-16 22:50:32 +00002243
sewardj67f1d582002-05-24 02:11:32 +00002244extern
2245int __libc_msync(const void *start, size_t length, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002246WEAK
sewardj67f1d582002-05-24 02:11:32 +00002247int msync(const void *start, size_t length, int flags)
2248{
sewardjd140e442002-05-29 01:21:19 +00002249 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00002250 return __libc_msync(start, length, flags);
2251}
2252
sewardj5905fae2002-04-26 13:25:00 +00002253
sewardj2cb00342002-06-28 01:46:26 +00002254/*--- fork and its helper ---*/
2255
2256static
2257void run_fork_handlers ( int what )
2258{
2259 ForkHandlerEntry entry;
2260 int n_h, n_handlers, i, res;
2261
2262 my_assert(what == 0 || what == 1 || what == 2);
2263
2264 /* Fetch old counter */
2265 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2266 VG_USERREQ__GET_FHSTACK_USED,
2267 0, 0, 0, 0);
2268 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2269
2270 /* Prepare handlers (what == 0) are called in opposite order of
2271 calls to pthread_atfork. Parent and child handlers are called
2272 in the same order as calls to pthread_atfork. */
2273 if (what == 0)
2274 n_h = n_handlers - 1;
2275 else
2276 n_h = 0;
2277
2278 for (i = 0; i < n_handlers; i++) {
2279 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2280 VG_USERREQ__GET_FHSTACK_ENTRY,
2281 n_h, &entry, 0, 0);
2282 my_assert(res == 0);
2283 switch (what) {
2284 case 0: if (entry.prepare) entry.prepare();
2285 n_h--; break;
2286 case 1: if (entry.parent) entry.parent();
2287 n_h++; break;
2288 case 2: if (entry.child) entry.child();
2289 n_h++; break;
2290 default: barf("run_fork_handlers: invalid what");
2291 }
2292 }
2293
2294 if (what != 0 /* prepare */) {
2295 /* Empty out the stack. */
2296 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2297 VG_USERREQ__SET_FHSTACK_USED,
2298 0, 0, 0, 0);
2299 my_assert(res == 0);
2300 }
2301}
2302
2303extern
2304pid_t __libc_fork(void);
2305pid_t __fork(void)
2306{
2307 pid_t pid;
2308 __my_pthread_testcancel();
2309 __pthread_mutex_lock(&pthread_atfork_lock);
2310
2311 run_fork_handlers(0 /* prepare */);
2312 pid = __libc_fork();
2313 if (pid == 0) {
2314 /* I am the child */
2315 run_fork_handlers(2 /* child */);
sewardjd8acdf22002-11-13 21:57:52 +00002316 __pthread_mutex_unlock(&pthread_atfork_lock);
sewardj2cb00342002-06-28 01:46:26 +00002317 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2318 } else {
2319 /* I am the parent */
2320 run_fork_handlers(1 /* parent */);
2321 __pthread_mutex_unlock(&pthread_atfork_lock);
2322 }
2323 return pid;
2324}
2325
2326
njn25e49d8e72002-09-23 09:36:25 +00002327pid_t __vfork(void)
2328{
2329 return __fork();
2330}
sewardj2cb00342002-06-28 01:46:26 +00002331
2332
sewardj08a4c3f2002-04-13 03:45:44 +00002333static
sewardj08a4c3f2002-04-13 03:45:44 +00002334int my_do_syscall1 ( int syscallno, int arg1 )
2335{
2336 int __res;
2337 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2338 : "=a" (__res)
2339 : "0" (syscallno),
2340 "d" (arg1) );
2341 return __res;
2342}
2343
2344static
2345int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00002346 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00002347{
2348 int __res;
2349 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2350 : "=a" (__res)
2351 : "0" (syscallno),
2352 "d" (arg1),
2353 "c" (arg2) );
2354 return __res;
2355}
2356
2357static
sewardjf854f472002-04-21 12:19:41 +00002358int my_do_syscall3 ( int syscallno,
2359 int arg1, int arg2, int arg3 )
2360{
2361 int __res;
2362 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
2363 : "=a" (__res)
2364 : "0" (syscallno),
2365 "S" (arg1),
2366 "c" (arg2),
2367 "d" (arg3) );
2368 return __res;
2369}
2370
sewardjd5bef572002-10-23 21:49:33 +00002371static inline
2372int my_do_syscall5 ( int syscallno,
2373 int arg1, int arg2, int arg3, int arg4, int arg5 )
2374{
2375 int __res;
2376 __asm__ volatile ("int $0x80"
2377 : "=a" (__res)
2378 : "0" (syscallno),
2379 "b" (arg1),
2380 "c" (arg2),
2381 "d" (arg3),
2382 "S" (arg4),
2383 "D" (arg5));
2384 return __res;
2385}
2386
sewardj11f0bb42003-04-26 20:11:15 +00002387
2388WEAK
2389int select ( int n,
2390 fd_set *rfds,
2391 fd_set *wfds,
2392 fd_set *xfds,
2393 struct timeval *timeout )
sewardj08a4c3f2002-04-13 03:45:44 +00002394{
sewardj11f0bb42003-04-26 20:11:15 +00002395 return VGR_(select)(n, rfds, wfds, xfds, timeout);
sewardj08a4c3f2002-04-13 03:45:44 +00002396}
2397
2398
sewardj3b13f0e2002-04-25 20:17:29 +00002399/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002400 Hacky implementation of semaphores.
2401 ------------------------------------------------------------------ */
2402
2403#include <semaphore.h>
2404
2405/* This is a terrible way to do the remapping. Plan is to import an
2406 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002407
2408typedef
2409 struct {
2410 pthread_mutex_t se_mx;
2411 pthread_cond_t se_cv;
2412 int count;
2413 }
2414 vg_sem_t;
2415
2416static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2417
2418static int se_remap_used = 0;
2419static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2420static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2421
2422static vg_sem_t* se_remap ( sem_t* orig )
2423{
2424 int res, i;
2425 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002426 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002427
2428 for (i = 0; i < se_remap_used; i++) {
2429 if (se_remap_orig[i] == orig)
2430 break;
2431 }
2432 if (i == se_remap_used) {
2433 if (se_remap_used == VG_N_SEMAPHORES) {
2434 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002435 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002436 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002437 }
2438 se_remap_used++;
2439 se_remap_orig[i] = orig;
2440 /* printf("allocated semaphore %d\n", i); */
2441 }
2442 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002443 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002444 return &se_remap_new[i];
2445}
2446
2447
2448int sem_init(sem_t *sem, int pshared, unsigned int value)
2449{
2450 int res;
2451 vg_sem_t* vg_sem;
2452 ensure_valgrind("sem_init");
2453 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002454 pthread_error("sem_init: unsupported pshared value");
sewardj25418ae2003-05-09 23:40:34 +00002455 *(__errno_location()) = ENOSYS;
sewardj8f253ff2002-05-19 00:13:34 +00002456 return -1;
2457 }
2458 vg_sem = se_remap(sem);
2459 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002460 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002461 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002462 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002463 vg_sem->count = value;
2464 return 0;
2465}
2466
2467
2468int sem_wait ( sem_t* sem )
2469{
2470 int res;
2471 vg_sem_t* vg_sem;
2472 ensure_valgrind("sem_wait");
2473 vg_sem = se_remap(sem);
2474 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002475 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002476 while (vg_sem->count == 0) {
2477 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002478 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002479 }
2480 vg_sem->count--;
2481 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002482 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002483 return 0;
2484}
2485
2486int sem_post ( sem_t* sem )
2487{
2488 int res;
2489 vg_sem_t* vg_sem;
2490 ensure_valgrind("sem_post");
2491 vg_sem = se_remap(sem);
2492 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002493 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002494 if (vg_sem->count == 0) {
2495 vg_sem->count++;
2496 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002497 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002498 } else {
2499 vg_sem->count++;
2500 }
2501 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002502 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002503 return 0;
2504}
2505
2506
2507int sem_trywait ( sem_t* sem )
2508{
2509 int ret, res;
2510 vg_sem_t* vg_sem;
2511 ensure_valgrind("sem_trywait");
2512 vg_sem = se_remap(sem);
2513 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002514 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002515 if (vg_sem->count > 0) {
2516 vg_sem->count--;
2517 ret = 0;
2518 } else {
2519 ret = -1;
sewardj25418ae2003-05-09 23:40:34 +00002520 *(__errno_location()) = EAGAIN;
sewardj8f253ff2002-05-19 00:13:34 +00002521 }
2522 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002523 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002524 return ret;
2525}
2526
2527
2528int sem_getvalue(sem_t* sem, int * sval)
2529{
2530 vg_sem_t* vg_sem;
2531 ensure_valgrind("sem_trywait");
2532 vg_sem = se_remap(sem);
2533 *sval = vg_sem->count;
2534 return 0;
2535}
2536
2537
2538int sem_destroy(sem_t * sem)
2539{
2540 kludged("sem_destroy");
2541 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2542 return 0;
2543}
2544
sewardj9ad92d92002-10-16 19:45:06 +00002545
2546int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2547{
2548 int res;
2549 vg_sem_t* vg_sem;
2550 ensure_valgrind("sem_timedwait");
2551 vg_sem = se_remap(sem);
2552 res = __pthread_mutex_lock(&vg_sem->se_mx);
2553 my_assert(res == 0);
2554 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
2555 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
2556 }
2557 if ( vg_sem->count > 0 ) {
2558 vg_sem->count--;
2559 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2560 my_assert(res == 0 );
2561 return 0;
2562 } else {
2563 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2564 my_assert(res == 0 );
2565 *(__errno_location()) = ETIMEDOUT;
2566 return -1;
2567 }
2568}
2569
sewardj8f253ff2002-05-19 00:13:34 +00002570
2571/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002572 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002573 ------------------------------------------------------------------ */
2574
sewardj2d8b3f02002-06-01 14:14:19 +00002575typedef
2576 struct {
2577 int initted; /* != 0 --> in use; sanity check only */
2578 int prefer_w; /* != 0 --> prefer writer */
2579 int nwait_r; /* # of waiting readers */
2580 int nwait_w; /* # of waiting writers */
2581 pthread_cond_t cv_r; /* for signalling readers */
2582 pthread_cond_t cv_w; /* for signalling writers */
2583 pthread_mutex_t mx;
2584 int status;
2585 /* allowed range for status: >= -1. -1 means 1 writer currently
2586 active, >= 0 means N readers currently active. */
2587 }
2588 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002589
2590
2591static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2592
2593static int rw_remap_used = 0;
2594static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2595static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2596
sewardj2d8b3f02002-06-01 14:14:19 +00002597
2598static
2599void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2600{
2601 int res = 0;
2602 vg_rwl->initted = 1;
2603 vg_rwl->prefer_w = 1;
2604 vg_rwl->nwait_r = 0;
2605 vg_rwl->nwait_w = 0;
2606 vg_rwl->status = 0;
2607 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2608 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2609 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002610 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002611}
2612
2613
sewardja1ac5cb2002-05-27 13:00:05 +00002614/* Take the address of a LinuxThreads rwlock_t and return the shadow
2615 address of our version. Further, if the LinuxThreads version
2616 appears to have been statically initialised, do the same to the one
2617 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2618 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2619 uninitialised and non-zero meaning initialised.
2620*/
2621static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2622{
2623 int res, i;
2624 vg_rwlock_t* vg_rwl;
2625 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002626 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002627
2628 for (i = 0; i < rw_remap_used; i++) {
2629 if (rw_remap_orig[i] == orig)
2630 break;
2631 }
2632 if (i == rw_remap_used) {
2633 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002634 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002635 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002636 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2637 }
2638 rw_remap_used++;
2639 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002640 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002641 if (0) printf("allocated rwlock %d\n", i);
2642 }
2643 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002644 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002645 vg_rwl = &rw_remap_new[i];
2646
sewardj2d8b3f02002-06-01 14:14:19 +00002647 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002648 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002649 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002650 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002651 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002652 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002653 }
2654
2655 return vg_rwl;
2656}
2657
2658
sewardja1ac5cb2002-05-27 13:00:05 +00002659int pthread_rwlock_init ( pthread_rwlock_t* orig,
2660 const pthread_rwlockattr_t* attr )
2661{
sewardja1ac5cb2002-05-27 13:00:05 +00002662 vg_rwlock_t* rwl;
2663 if (0) printf ("pthread_rwlock_init\n");
2664 /* Force the remapper to initialise the shadow. */
2665 orig->__rw_readers = 0;
2666 /* Install the lock preference; the remapper needs to know it. */
2667 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2668 if (attr)
2669 orig->__rw_kind = attr->__lockkind;
2670 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002671 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002672}
2673
sewardj2d8b3f02002-06-01 14:14:19 +00002674
2675static
2676void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002677{
sewardj2d8b3f02002-06-01 14:14:19 +00002678 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2679 rwl->nwait_r--;
2680 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002681}
2682
sewardj2d8b3f02002-06-01 14:14:19 +00002683
sewardja1ac5cb2002-05-27 13:00:05 +00002684int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2685{
2686 int res;
2687 vg_rwlock_t* rwl;
2688 if (0) printf ("pthread_rwlock_rdlock\n");
2689 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002690 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002691 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002692 if (!rwl->initted) {
2693 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002694 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002695 return EINVAL;
2696 }
2697 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002698 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002699 rwl->nwait_r++;
2700 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2701 while (1) {
2702 if (rwl->status == 0) break;
2703 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002704 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002705 }
2706 pthread_cleanup_pop(0);
2707 rwl->nwait_r--;
2708 }
sewardj2d94c112002-06-03 01:25:54 +00002709 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002710 rwl->status++;
2711 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002712 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002713 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002714}
2715
sewardj2d8b3f02002-06-01 14:14:19 +00002716
sewardja1ac5cb2002-05-27 13:00:05 +00002717int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2718{
2719 int res;
2720 vg_rwlock_t* rwl;
2721 if (0) printf ("pthread_rwlock_tryrdlock\n");
2722 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002723 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002724 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002725 if (!rwl->initted) {
2726 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002727 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002728 return EINVAL;
2729 }
2730 if (rwl->status == -1) {
2731 /* Writer active; we have to give up. */
2732 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002733 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002734 return EBUSY;
2735 }
2736 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002737 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002738 rwl->status++;
2739 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002740 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002741 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002742}
2743
sewardj2d8b3f02002-06-01 14:14:19 +00002744
2745static
2746void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2747{
2748 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2749 rwl->nwait_w--;
2750 pthread_mutex_unlock (&rwl->mx);
2751}
2752
2753
sewardja1ac5cb2002-05-27 13:00:05 +00002754int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2755{
2756 int res;
2757 vg_rwlock_t* rwl;
2758 if (0) printf ("pthread_rwlock_wrlock\n");
2759 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002760 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002761 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002762 if (!rwl->initted) {
2763 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002764 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002765 return EINVAL;
2766 }
2767 if (rwl->status != 0) {
2768 rwl->nwait_w++;
2769 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2770 while (1) {
2771 if (rwl->status == 0) break;
2772 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002773 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002774 }
2775 pthread_cleanup_pop(0);
2776 rwl->nwait_w--;
2777 }
sewardj2d94c112002-06-03 01:25:54 +00002778 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002779 rwl->status = -1;
2780 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002781 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002782 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002783}
2784
sewardj2d8b3f02002-06-01 14:14:19 +00002785
sewardja1ac5cb2002-05-27 13:00:05 +00002786int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2787{
2788 int res;
2789 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002790 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002791 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002792 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002793 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002794 if (!rwl->initted) {
2795 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002796 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002797 return EINVAL;
2798 }
2799 if (rwl->status != 0) {
2800 /* Reader(s) or a writer active; we have to give up. */
2801 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002802 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002803 return EBUSY;
2804 }
2805 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002806 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002807 rwl->status = -1;
2808 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002809 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002810 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002811}
2812
sewardj2d8b3f02002-06-01 14:14:19 +00002813
sewardja1ac5cb2002-05-27 13:00:05 +00002814int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2815{
2816 int res;
2817 vg_rwlock_t* rwl;
2818 if (0) printf ("pthread_rwlock_unlock\n");
2819 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002820 rwl = rw_remap ( orig );
2821 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002822 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002823 if (!rwl->initted) {
2824 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002825 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002826 return EINVAL;
2827 }
2828 if (rwl->status == 0) {
2829 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002830 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002831 return EPERM;
2832 }
sewardj2d94c112002-06-03 01:25:54 +00002833 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002834 if (rwl->status == -1) {
2835 rwl->status = 0;
2836 } else {
sewardj2d94c112002-06-03 01:25:54 +00002837 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002838 rwl->status--;
2839 }
2840
sewardj2d94c112002-06-03 01:25:54 +00002841 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002842
2843 if (rwl->prefer_w) {
2844
2845 /* Favour waiting writers, if any. */
2846 if (rwl->nwait_w > 0) {
2847 /* Writer(s) are waiting. */
2848 if (rwl->status == 0) {
2849 /* We can let a writer in. */
2850 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002851 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002852 } else {
2853 /* There are still readers active. Do nothing; eventually
2854 they will disappear, at which point a writer will be
2855 admitted. */
2856 }
2857 }
2858 else
2859 /* No waiting writers. */
2860 if (rwl->nwait_r > 0) {
2861 /* Let in a waiting reader. */
2862 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002863 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002864 }
2865
2866 } else {
2867
2868 /* Favour waiting readers, if any. */
2869 if (rwl->nwait_r > 0) {
2870 /* Reader(s) are waiting; let one in. */
2871 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002872 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002873 }
2874 else
2875 /* No waiting readers. */
2876 if (rwl->nwait_w > 0 && rwl->status == 0) {
2877 /* We have waiting writers and no active readers; let a
2878 writer in. */
2879 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002880 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002881 }
2882 }
2883
2884 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002885 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002886 return 0;
2887}
2888
2889
2890int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2891{
2892 int res;
2893 vg_rwlock_t* rwl;
2894 if (0) printf ("pthread_rwlock_destroy\n");
2895 rwl = rw_remap ( orig );
2896 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002897 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002898 if (!rwl->initted) {
2899 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002900 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002901 return EINVAL;
2902 }
2903 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2904 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002905 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002906 return EBUSY;
2907 }
2908 rwl->initted = 0;
2909 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002910 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002911 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002912}
2913
2914
sewardj47e4e312002-06-18 09:24:34 +00002915/* Copied directly from LinuxThreads. */
2916int
2917pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
2918{
2919 attr->__lockkind = 0;
2920 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
2921
2922 return 0;
2923}
2924
sewardjfe18eb82002-07-13 12:58:44 +00002925/* Copied directly from LinuxThreads. */
2926int
sewardj5706bfa2002-12-08 23:42:17 +00002927pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
2928{
2929 return 0;
2930}
2931
2932/* Copied directly from LinuxThreads. */
2933int
sewardjfe18eb82002-07-13 12:58:44 +00002934pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
2935{
2936 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
2937 return EINVAL;
2938
2939 /* For now it is not possible to shared a conditional variable. */
2940 if (pshared != PTHREAD_PROCESS_PRIVATE)
2941 return ENOSYS;
2942
2943 attr->__pshared = pshared;
2944
2945 return 0;
2946}
2947
sewardj47e4e312002-06-18 09:24:34 +00002948
sewardja1ac5cb2002-05-27 13:00:05 +00002949/* ---------------------------------------------------------------------
sewardj11f0bb42003-04-26 20:11:15 +00002950 Make SYSV IPC not block everything -- pass to vg_intercept.c.
sewardjd5bef572002-10-23 21:49:33 +00002951 ------------------------------------------------------------------ */
2952
sewardj11f0bb42003-04-26 20:11:15 +00002953WEAK
2954int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
sewardjd5bef572002-10-23 21:49:33 +00002955{
sewardj11f0bb42003-04-26 20:11:15 +00002956 return VGR_(msgsnd)(msgid, msgp, msgsz, msgflg);
sewardjd5bef572002-10-23 21:49:33 +00002957}
2958
sewardj11f0bb42003-04-26 20:11:15 +00002959WEAK
2960int msgrcv(int msqid, void* msgp, size_t msgsz,
2961 long msgtyp, int msgflg )
sewardjd5bef572002-10-23 21:49:33 +00002962{
sewardj11f0bb42003-04-26 20:11:15 +00002963 return VGR_(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg );
sewardjd5bef572002-10-23 21:49:33 +00002964}
2965
sewardj262b5be2003-04-26 21:19:53 +00002966
2967/* ---------------------------------------------------------------------
2968 The glibc sources say that returning -1 in these 3 functions
2969 causes real time signals not to be used.
2970 ------------------------------------------------------------------ */
2971
2972int __libc_current_sigrtmin (void)
2973{
2974 static int moans = N_MOANS;
2975 if (moans-- > 0)
2976 kludged("__libc_current_sigrtmin");
2977 return -1;
2978}
2979
2980int __libc_current_sigrtmax (void)
2981{
2982 static int moans = N_MOANS;
2983 if (moans-- > 0)
2984 kludged("__libc_current_sigrtmax");
2985 return -1;
2986}
2987
2988int __libc_allocate_rtsig (int high)
2989{
2990 static int moans = N_MOANS;
2991 if (moans-- > 0)
2992 kludged("__libc_allocate_rtsig");
2993 return -1;
2994}
2995
2996
sewardjd5bef572002-10-23 21:49:33 +00002997/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002998 B'stard.
2999 ------------------------------------------------------------------ */
3000
3001# define strong_alias(name, aliasname) \
3002 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
3003
sewardj5905fae2002-04-26 13:25:00 +00003004# define weak_alias(name, aliasname) \
3005 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00003006
sewardj5905fae2002-04-26 13:25:00 +00003007strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
3008strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
3009strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
3010strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
3011 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
3012strong_alias(__pthread_mutex_init, pthread_mutex_init)
3013strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
3014strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
3015strong_alias(__pthread_once, pthread_once)
3016strong_alias(__pthread_atfork, pthread_atfork)
3017strong_alias(__pthread_key_create, pthread_key_create)
3018strong_alias(__pthread_getspecific, pthread_getspecific)
3019strong_alias(__pthread_setspecific, pthread_setspecific)
3020
sewardjd529a442002-05-04 19:49:21 +00003021#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00003022strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00003023#endif
3024
sewardj5905fae2002-04-26 13:25:00 +00003025strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00003026strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00003027strong_alias(lseek, __lseek)
3028strong_alias(open, __open)
3029strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00003030strong_alias(read, __read)
3031strong_alias(wait, __wait)
3032strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00003033strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00003034strong_alias(send, __send)
3035
sewardj726c4122002-05-16 23:39:10 +00003036weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00003037weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00003038weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00003039weak_alias(__vfork, vfork)
sewardj7f6456d2002-05-21 00:51:21 +00003040
sewardjf0b06452002-06-04 08:38:04 +00003041weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00003042
3043/*--------------------------------------------------*/
3044
sewardj5905fae2002-04-26 13:25:00 +00003045weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00003046weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00003047weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00003048
sewardja1ac5cb2002-05-27 13:00:05 +00003049weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
3050weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
3051weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
3052weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
3053
sewardj060b04f2002-04-26 21:01:13 +00003054
sewardj3b13f0e2002-04-25 20:17:29 +00003055/* I've no idea what these are, but they get called quite a lot.
3056 Anybody know? */
3057
3058#undef _IO_flockfile
3059void _IO_flockfile ( _IO_FILE * file )
3060{
sewardj853f55d2002-04-26 00:27:53 +00003061 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003062}
sewardj5905fae2002-04-26 13:25:00 +00003063weak_alias(_IO_flockfile, flockfile);
3064
sewardj3b13f0e2002-04-25 20:17:29 +00003065
3066#undef _IO_funlockfile
3067void _IO_funlockfile ( _IO_FILE * file )
3068{
sewardj853f55d2002-04-26 00:27:53 +00003069 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003070}
sewardj5905fae2002-04-26 13:25:00 +00003071weak_alias(_IO_funlockfile, funlockfile);
3072
sewardj3b13f0e2002-04-25 20:17:29 +00003073
sewardjd4f2c712002-04-30 10:20:10 +00003074/* This doesn't seem to be needed to simulate libpthread.so's external
3075 interface, but many people complain about its absence. */
3076
3077strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
3078weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00003079
3080
3081/*--------------------------------------------------------------------*/
3082/*--- end vg_libpthread.c ---*/
3083/*--------------------------------------------------------------------*/