blob: 804c8bbac9f980528031f7929adfd64fc1c28027 [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
sewardjc91a4ff2003-07-11 00:12:58 +0000677static void __valgrind_pthread_yield ( void )
sewardjff42d1d2002-05-22 13:17:31 +0000678{
679 int res;
680 ensure_valgrind("pthread_yield");
681 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
682 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
sewardjc91a4ff2003-07-11 00:12:58 +0000683}
684
685WEAK
686int pthread_yield ( void )
687{
688 __valgrind_pthread_yield();
sewardjff42d1d2002-05-22 13:17:31 +0000689 return 0;
690}
691
692
sewardj6072c362002-04-19 14:40:57 +0000693int pthread_equal(pthread_t thread1, pthread_t thread2)
694{
695 return thread1 == thread2 ? 1 : 0;
696}
697
698
sewardj20917d82002-05-28 01:36:45 +0000699/* Bundle up the args into a malloc'd block and create a new thread
700 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000701int
sewardj1462c8b2002-07-24 09:41:52 +0000702pthread_create (pthread_t *__restrict __thredd,
sewardje663cb92002-04-12 10:26:32 +0000703 __const pthread_attr_t *__restrict __attr,
704 void *(*__start_routine) (void *),
705 void *__restrict __arg)
706{
sewardj20917d82002-05-28 01:36:45 +0000707 int tid_child;
708 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000709
sewardj20917d82002-05-28 01:36:45 +0000710 ensure_valgrind("pthread_create");
711
sewardj00a66b12002-10-12 16:42:35 +0000712 /* make sure the tsd keys, and hence locale info, are initialised
713 before we get into complications making new threads. */
714 init_libc_tsd_keys();
715
sewardj20917d82002-05-28 01:36:45 +0000716 /* Allocate space for the arg block. thread_wrapper will free
717 it. */
sewardj00a66b12002-10-12 16:42:35 +0000718 info = my_malloc(sizeof(NewThreadInfo));
sewardj2d94c112002-06-03 01:25:54 +0000719 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000720
sewardj728a5272002-06-20 10:25:37 +0000721 if (__attr)
722 info->attr__detachstate = __attr->__detachstate;
723 else
724 info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
725
sewardj20917d82002-05-28 01:36:45 +0000726 info->root_fn = __start_routine;
727 info->arg = __arg;
728 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
729 VG_USERREQ__APPLY_IN_NEW_THREAD,
730 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000731 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000732
sewardj1462c8b2002-07-24 09:41:52 +0000733 if (__thredd)
734 *__thredd = tid_child;
sewardj20917d82002-05-28 01:36:45 +0000735 return 0; /* success */
736}
sewardje663cb92002-04-12 10:26:32 +0000737
738
739int
740pthread_join (pthread_t __th, void **__thread_return)
741{
742 int res;
743 ensure_valgrind("pthread_join");
744 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
745 VG_USERREQ__PTHREAD_JOIN,
746 __th, __thread_return, 0, 0);
747 return res;
748}
749
750
sewardj3b5d8862002-04-20 13:53:23 +0000751void pthread_exit(void *retval)
752{
sewardj3b5d8862002-04-20 13:53:23 +0000753 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000754 /* Simple! */
755 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000756}
757
sewardje663cb92002-04-12 10:26:32 +0000758
sewardj853f55d2002-04-26 00:27:53 +0000759int pthread_detach(pthread_t th)
760{
sewardj20917d82002-05-28 01:36:45 +0000761 int res;
762 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000763 /* First we enquire as to the current detach state. */
764 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000765 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000766 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000767 if (res == -1) {
768 /* not found */
769 pthread_error("pthread_detach: "
770 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000771 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000772 }
773 if (res == 1) {
774 /* already detached */
775 pthread_error("pthread_detach: "
776 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000777 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000778 }
sewardj7989d0c2002-05-28 11:00:01 +0000779 if (res == 0) {
780 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
781 VG_USERREQ__SET_OR_GET_DETACH,
782 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000783 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000784 return 0;
785 }
786 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000787}
788
789
sewardjf8f819e2002-04-17 23:21:37 +0000790/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000791 CLEANUP STACKS
792 ------------------------------------------------ */
793
794void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
795 void (*__routine) (void *),
796 void *__arg)
797{
798 int res;
799 CleanupEntry cu;
800 ensure_valgrind("_pthread_cleanup_push");
801 cu.fn = __routine;
802 cu.arg = __arg;
803 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
804 VG_USERREQ__CLEANUP_PUSH,
805 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000806 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000807}
808
809
810void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
811 void (*__routine) (void *),
812 void *__arg)
813{
814 /* As _pthread_cleanup_push, but first save the thread's original
815 cancellation type in __buffer and set it to Deferred. */
816 int orig_ctype;
817 ensure_valgrind("_pthread_cleanup_push_defer");
818 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000819 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
820 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
821 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000822 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
823 VG_USERREQ__SET_CANCELTYPE,
824 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000825 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000826 *((int*)(__buffer)) = orig_ctype;
827 /* Now push the cleanup. */
828 _pthread_cleanup_push(NULL, __routine, __arg);
829}
830
831
832void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
833 int __execute)
834{
835 int res;
836 CleanupEntry cu;
837 ensure_valgrind("_pthread_cleanup_push");
838 cu.fn = cu.arg = NULL; /* paranoia */
839 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
840 VG_USERREQ__CLEANUP_POP,
841 &cu, 0, 0, 0);
842 if (res == 0) {
843 /* pop succeeded */
844 if (__execute) {
845 cu.fn ( cu.arg );
846 }
847 return;
848 }
849 if (res == -1) {
850 /* stack underflow */
851 return;
852 }
853 barf("_pthread_cleanup_pop");
854}
855
856
857void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
858 int __execute)
859{
860 int orig_ctype, fake_ctype;
861 /* As _pthread_cleanup_pop, but after popping/running the handler,
862 restore the thread's original cancellation type from the first
863 word of __buffer. */
864 _pthread_cleanup_pop(NULL, __execute);
865 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000866 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000867 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000868 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
869 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
870 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000871 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
872 VG_USERREQ__SET_CANCELTYPE,
873 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000874 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000875}
876
877
878/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000879 MUTEX ATTRIBUTES
880 ------------------------------------------------ */
881
sewardj5905fae2002-04-26 13:25:00 +0000882int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000883{
sewardjf8f819e2002-04-17 23:21:37 +0000884 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000885 return 0;
sewardje663cb92002-04-12 10:26:32 +0000886}
887
sewardj5905fae2002-04-26 13:25:00 +0000888int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000889{
890 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000891# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000892 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000893 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000894# endif
sewardja1679dd2002-05-10 22:31:40 +0000895# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000896 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000897# endif
sewardjf8f819e2002-04-17 23:21:37 +0000898 case PTHREAD_MUTEX_RECURSIVE_NP:
899 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000900 attr->__mutexkind = type;
901 return 0;
902 default:
sewardj4dced352002-06-04 22:54:20 +0000903 pthread_error("pthread_mutexattr_settype: "
904 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000905 return EINVAL;
906 }
907}
908
sewardj5905fae2002-04-26 13:25:00 +0000909int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000910{
911 return 0;
912}
913
sewardjf0995512003-07-06 01:29:49 +0000914int __pthread_mutexattr_setpshared ( pthread_mutexattr_t* attr, int pshared)
sewardj7685cae2003-07-06 01:23:11 +0000915{
916 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
917 return EINVAL;
918
919 /* For now it is not possible to shared a conditional variable. */
920 if (pshared != PTHREAD_PROCESS_PRIVATE)
921 return ENOSYS;
922
923 return 0;
924}
925
sewardjf8f819e2002-04-17 23:21:37 +0000926
927/* ---------------------------------------------------
928 MUTEXes
929 ------------------------------------------------ */
930
sewardj5905fae2002-04-26 13:25:00 +0000931int __pthread_mutex_init(pthread_mutex_t *mutex,
932 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000933{
sewardj604ec3c2002-04-18 22:38:41 +0000934 mutex->__m_count = 0;
935 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
936 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
937 if (mutexattr)
938 mutex->__m_kind = mutexattr->__mutexkind;
939 return 0;
sewardje663cb92002-04-12 10:26:32 +0000940}
941
sewardj439d45e2002-05-03 20:43:10 +0000942
sewardj5905fae2002-04-26 13:25:00 +0000943int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000944{
945 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000946
sewardj439d45e2002-05-03 20:43:10 +0000947 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000948 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
949 VG_USERREQ__PTHREAD_MUTEX_LOCK,
950 mutex, 0, 0, 0);
951 return res;
sewardj439d45e2002-05-03 20:43:10 +0000952 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000953 /* Play at locking */
954 if (0)
955 kludged("prehistoric lock");
956 mutex->__m_owner = (_pthread_descr)1;
957 mutex->__m_count = 1;
958 mutex->__m_kind |= VG_PTHREAD_PREHISTORY;
sewardj439d45e2002-05-03 20:43:10 +0000959 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000960 }
961}
962
sewardj439d45e2002-05-03 20:43:10 +0000963
sewardj5905fae2002-04-26 13:25:00 +0000964int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000965{
966 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000967
sewardj439d45e2002-05-03 20:43:10 +0000968 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000969 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
970 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
971 mutex, 0, 0, 0);
972 return res;
sewardj439d45e2002-05-03 20:43:10 +0000973 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000974 /* Play at locking */
975 if (0)
976 kludged("prehistoric trylock");
977 mutex->__m_owner = (_pthread_descr)1;
978 mutex->__m_count = 1;
979 mutex->__m_kind |= VG_PTHREAD_PREHISTORY;
980 return 0; /* success */
sewardj30671ff2002-04-21 00:13:57 +0000981 }
982}
983
sewardj439d45e2002-05-03 20:43:10 +0000984
sewardj5905fae2002-04-26 13:25:00 +0000985int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000986{
987 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000988
sewardj439d45e2002-05-03 20:43:10 +0000989 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000990 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
991 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
992 mutex, 0, 0, 0);
993 return res;
sewardj439d45e2002-05-03 20:43:10 +0000994 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000995 /* Play at locking */
996 if (0)
997 kludged("prehistoric unlock");
998 mutex->__m_owner = 0;
999 mutex->__m_count = 0;
1000 mutex->__m_kind &= ~VG_PTHREAD_PREHISTORY;
1001 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +00001002 }
1003}
1004
sewardj439d45e2002-05-03 20:43:10 +00001005
sewardj5905fae2002-04-26 13:25:00 +00001006int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +00001007{
sewardj604ec3c2002-04-18 22:38:41 +00001008 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
1009 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +00001010 if (mutex->__m_count > 0) {
sewardjd8acdf22002-11-13 21:57:52 +00001011 /* Oh, the horror. glibc's internal use of pthreads "knows"
1012 that destroying a lock does an implicit unlock. Make it
1013 explicit. */
1014 __pthread_mutex_unlock(mutex);
1015 pthread_error("pthread_mutex_destroy: "
1016 "mutex is still in use");
1017 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +00001018 }
1019 mutex->__m_count = 0;
1020 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
1021 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
1022 return 0;
sewardje663cb92002-04-12 10:26:32 +00001023}
1024
1025
sewardjf8f819e2002-04-17 23:21:37 +00001026/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +00001027 CONDITION VARIABLES
1028 ------------------------------------------------ */
1029
1030/* LinuxThreads supports no attributes for conditions. Hence ... */
1031
1032int pthread_condattr_init(pthread_condattr_t *attr)
1033{
1034 return 0;
1035}
1036
sewardj0738a592002-04-20 13:59:33 +00001037int pthread_condattr_destroy(pthread_condattr_t *attr)
1038{
1039 return 0;
1040}
sewardj6072c362002-04-19 14:40:57 +00001041
1042int pthread_cond_init( pthread_cond_t *cond,
1043 const pthread_condattr_t *cond_attr)
1044{
1045 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
1046 return 0;
1047}
1048
sewardjf854f472002-04-21 12:19:41 +00001049int pthread_cond_destroy(pthread_cond_t *cond)
1050{
1051 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +00001052 static int moans = N_MOANS;
1053 if (moans-- > 0)
1054 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +00001055 return 0;
1056}
sewardj6072c362002-04-19 14:40:57 +00001057
1058/* ---------------------------------------------------
1059 SCHEDULING
1060 ------------------------------------------------ */
1061
1062/* This is completely bogus. */
1063int pthread_getschedparam(pthread_t target_thread,
1064 int *policy,
1065 struct sched_param *param)
1066{
sewardj436e0582002-04-26 14:31:40 +00001067 static int moans = N_MOANS;
1068 if (moans-- > 0)
1069 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +00001070 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +00001071# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +00001072 if (param) param->sched_priority = 0; /* who knows */
1073# else
sewardj6072c362002-04-19 14:40:57 +00001074 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +00001075# endif
sewardj6072c362002-04-19 14:40:57 +00001076 return 0;
1077}
1078
1079int pthread_setschedparam(pthread_t target_thread,
1080 int policy,
1081 const struct sched_param *param)
1082{
sewardj436e0582002-04-26 14:31:40 +00001083 static int moans = N_MOANS;
1084 if (moans-- > 0)
1085 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +00001086 return 0;
1087}
1088
sewardj3b5d8862002-04-20 13:53:23 +00001089int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
1090{
1091 int res;
1092 ensure_valgrind("pthread_cond_wait");
1093 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1094 VG_USERREQ__PTHREAD_COND_WAIT,
1095 cond, mutex, 0, 0);
1096 return res;
1097}
1098
sewardj5f07b662002-04-23 16:52:51 +00001099int pthread_cond_timedwait ( pthread_cond_t *cond,
1100 pthread_mutex_t *mutex,
1101 const struct timespec *abstime )
1102{
1103 int res;
1104 unsigned int ms_now, ms_end;
1105 struct timeval timeval_now;
1106 unsigned long long int ull_ms_now_after_1970;
1107 unsigned long long int ull_ms_end_after_1970;
1108
1109 ensure_valgrind("pthread_cond_timedwait");
1110 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1111 VG_USERREQ__READ_MILLISECOND_TIMER,
1112 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001113 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001114 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +00001115 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001116
1117 ull_ms_now_after_1970
1118 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
1119 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
1120 ull_ms_end_after_1970
1121 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
1122 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +00001123 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
1124 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +00001125 ms_end
1126 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
1127 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1128 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
1129 cond, mutex, ms_end, 0);
1130 return res;
1131}
1132
1133
sewardj3b5d8862002-04-20 13:53:23 +00001134int pthread_cond_signal(pthread_cond_t *cond)
1135{
1136 int res;
1137 ensure_valgrind("pthread_cond_signal");
1138 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1139 VG_USERREQ__PTHREAD_COND_SIGNAL,
1140 cond, 0, 0, 0);
1141 return res;
1142}
1143
1144int pthread_cond_broadcast(pthread_cond_t *cond)
1145{
1146 int res;
1147 ensure_valgrind("pthread_cond_broadcast");
1148 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1149 VG_USERREQ__PTHREAD_COND_BROADCAST,
1150 cond, 0, 0, 0);
1151 return res;
1152}
1153
sewardj6072c362002-04-19 14:40:57 +00001154
1155/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001156 CANCELLATION
1157 ------------------------------------------------ */
1158
sewardj853f55d2002-04-26 00:27:53 +00001159int pthread_setcancelstate(int state, int *oldstate)
1160{
sewardj20917d82002-05-28 01:36:45 +00001161 int res;
1162 ensure_valgrind("pthread_setcancelstate");
1163 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +00001164 && state != PTHREAD_CANCEL_DISABLE) {
1165 pthread_error("pthread_setcancelstate: "
1166 "invalid state");
sewardj20917d82002-05-28 01:36:45 +00001167 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001168 }
sewardj2d94c112002-06-03 01:25:54 +00001169 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1170 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001171 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1172 VG_USERREQ__SET_CANCELSTATE,
1173 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001174 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001175 if (oldstate)
1176 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001177 return 0;
1178}
1179
sewardje663cb92002-04-12 10:26:32 +00001180int pthread_setcanceltype(int type, int *oldtype)
1181{
sewardj20917d82002-05-28 01:36:45 +00001182 int res;
1183 ensure_valgrind("pthread_setcanceltype");
1184 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001185 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1186 pthread_error("pthread_setcanceltype: "
1187 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001188 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001189 }
sewardj2d94c112002-06-03 01:25:54 +00001190 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1191 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001192 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1193 VG_USERREQ__SET_CANCELTYPE,
1194 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001195 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001196 if (oldtype)
1197 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001198 return 0;
1199}
1200
sewardje663cb92002-04-12 10:26:32 +00001201int pthread_cancel(pthread_t thread)
1202{
1203 int res;
1204 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001205 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1206 VG_USERREQ__SET_CANCELPEND,
1207 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001208 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001209 return res;
1210}
1211
sewardjd140e442002-05-29 01:21:19 +00001212static __inline__
1213void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001214{
sewardj20917d82002-05-28 01:36:45 +00001215 int res;
njn25e49d8e72002-09-23 09:36:25 +00001216 ensure_valgrind("__my_pthread_testcancel");
sewardj20917d82002-05-28 01:36:45 +00001217 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1218 VG_USERREQ__TESTCANCEL,
1219 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001220 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001221}
1222
sewardjd140e442002-05-29 01:21:19 +00001223void pthread_testcancel ( void )
1224{
1225 __my_pthread_testcancel();
1226}
1227
sewardj20917d82002-05-28 01:36:45 +00001228
sewardjef037c72002-05-30 00:40:03 +00001229/* Not really sure what this is for. I suspect for doing the POSIX
1230 requirements for fork() and exec(). We do this internally anyway
1231 whenever those syscalls are observed, so this could be superfluous,
1232 but hey ...
1233*/
sewardj853f55d2002-04-26 00:27:53 +00001234void __pthread_kill_other_threads_np ( void )
1235{
sewardjef037c72002-05-30 00:40:03 +00001236 int res;
1237 ensure_valgrind("__pthread_kill_other_threads_np");
1238 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1239 VG_USERREQ__NUKE_OTHER_THREADS,
1240 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001241 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001242}
1243
sewardje663cb92002-04-12 10:26:32 +00001244
sewardjf8f819e2002-04-17 23:21:37 +00001245/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001246 SIGNALS
1247 ------------------------------------------------ */
1248
1249#include <signal.h>
1250
1251int pthread_sigmask(int how, const sigset_t *newmask,
1252 sigset_t *oldmask)
1253{
1254 int res;
1255
1256 /* A bit subtle, because the scheduler expects newmask and oldmask
1257 to be vki_sigset_t* rather than sigset_t*, and the two are
1258 different. Fortunately the first 64 bits of a sigset_t are
1259 exactly a vki_sigset_t, so we just pass the pointers through
1260 unmodified. Haaaack!
1261
1262 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001263 constants to VKI_ constants, so that the former do not have to
1264 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001265
1266 ensure_valgrind("pthread_sigmask");
1267
1268 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001269 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1270 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1271 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001272 default: pthread_error("pthread_sigmask: invalid how");
1273 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001274 }
1275
1276 /* Crude check */
1277 if (newmask == NULL)
1278 return EFAULT;
1279
1280 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1281 VG_USERREQ__PTHREAD_SIGMASK,
1282 how, newmask, oldmask, 0);
1283
1284 /* The scheduler tells us of any memory violations. */
1285 return res == 0 ? 0 : EFAULT;
1286}
1287
1288
1289int sigwait ( const sigset_t* set, int* sig )
1290{
1291 int res;
1292 ensure_valgrind("sigwait");
1293 /* As with pthread_sigmask we deliberately confuse sigset_t with
1294 vki_ksigset_t. */
1295 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1296 VG_USERREQ__SIGWAIT,
1297 set, sig, 0, 0);
1298 return res;
1299}
1300
1301
sewardj018f7622002-05-15 21:13:39 +00001302int pthread_kill(pthread_t thread, int signo)
1303{
1304 int res;
1305 ensure_valgrind("pthread_kill");
1306 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1307 VG_USERREQ__PTHREAD_KILL,
1308 thread, signo, 0, 0);
1309 return res;
1310}
1311
1312
sewardj3665ded2002-05-16 16:57:25 +00001313/* Copied verbatim from Linuxthreads */
1314/* Redefine raise() to send signal to calling thread only,
1315 as per POSIX 1003.1c */
1316int raise (int sig)
1317{
1318 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001319 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001320 return 0;
sewardj4dced352002-06-04 22:54:20 +00001321 } else {
sewardj25418ae2003-05-09 23:40:34 +00001322 *(__errno_location()) = retcode;
sewardj3665ded2002-05-16 16:57:25 +00001323 return -1;
1324 }
1325}
1326
1327
sewardj9a2224b2002-06-19 10:17:40 +00001328int pause ( void )
1329{
1330 unsigned int n_orig, n_now;
1331 struct vki_timespec nanosleep_interval;
1332 ensure_valgrind("pause");
1333
1334 /* This is surely a cancellation point. */
1335 __my_pthread_testcancel();
1336
1337 VALGRIND_MAGIC_SEQUENCE(n_orig, 0xFFFFFFFF /* default */,
1338 VG_USERREQ__GET_N_SIGS_RETURNED,
1339 0, 0, 0, 0);
1340 my_assert(n_orig != 0xFFFFFFFF);
1341
1342 while (1) {
1343 VALGRIND_MAGIC_SEQUENCE(n_now, 0xFFFFFFFF /* default */,
1344 VG_USERREQ__GET_N_SIGS_RETURNED,
1345 0, 0, 0, 0);
1346 my_assert(n_now != 0xFFFFFFFF);
1347 my_assert(n_now >= n_orig);
1348 if (n_now != n_orig) break;
1349
1350 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001351 nanosleep_interval.tv_nsec = 12 * 1000 * 1000; /* 12 milliseconds */
sewardj9a2224b2002-06-19 10:17:40 +00001352 /* It's critical here that valgrind's nanosleep implementation
1353 is nonblocking. */
1354 (void)my_do_syscall2(__NR_nanosleep,
1355 (int)(&nanosleep_interval), (int)NULL);
1356 }
1357
sewardj25418ae2003-05-09 23:40:34 +00001358 *(__errno_location()) = EINTR;
sewardj9a2224b2002-06-19 10:17:40 +00001359 return -1;
1360}
1361
1362
sewardjb48e5002002-05-13 00:16:03 +00001363/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001364 THREAD-SPECIFICs
1365 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001366
sewardj00a66b12002-10-12 16:42:35 +00001367static
1368int key_is_valid (pthread_key_t key)
1369{
1370 int res;
1371 VALGRIND_MAGIC_SEQUENCE(res, 2 /* default */,
1372 VG_USERREQ__PTHREAD_KEY_VALIDATE,
1373 key, 0, 0, 0);
1374 my_assert(res != 2);
1375 return res;
1376}
1377
1378
1379/* Returns NULL if thread is invalid. Otherwise, if the thread
1380 already has a specifics area, return that. Otherwise allocate it
1381 one. */
1382static
1383void** get_or_allocate_specifics_ptr ( pthread_t thread )
1384{
1385 int res, i;
1386 void** specifics_ptr;
1387 ensure_valgrind("get_or_allocate_specifics_ptr");
1388
1389 /* Returns zero if the thread has no specific_ptr. One if thread
1390 is invalid. Otherwise, the specific_ptr value. This is
1391 allocated with my_malloc and so is aligned and cannot be
1392 confused with 1 or 3. */
1393 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
1394 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
1395 thread, 0, 0, 0);
1396 my_assert(specifics_ptr != (void**)3);
1397
1398 if (specifics_ptr == (void**)1)
1399 return NULL; /* invalid thread */
1400
1401 if (specifics_ptr != NULL)
1402 return specifics_ptr; /* already has a specifics ptr. */
1403
1404 /* None yet ... allocate a new one. Should never fail. */
1405 specifics_ptr = my_malloc( VG_N_THREAD_KEYS * sizeof(void*) );
1406 my_assert(specifics_ptr != NULL);
1407
1408 VALGRIND_MAGIC_SEQUENCE(res, -1 /* default */,
1409 VG_USERREQ__PTHREAD_SETSPECIFIC_PTR,
1410 specifics_ptr, 0, 0, 0);
1411 my_assert(res == 0);
1412
1413 /* POSIX sez: "Upon thread creation, the value NULL shall be
1414 associated with all defined keys in the new thread." This
1415 allocation is in effect a delayed allocation of the specific
1416 data for a thread, at its first-use. Hence we initialise it
1417 here. */
1418 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
1419 specifics_ptr[i] = NULL;
1420 }
1421
1422 return specifics_ptr;
1423}
1424
1425
sewardj5905fae2002-04-26 13:25:00 +00001426int __pthread_key_create(pthread_key_t *key,
1427 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001428{
sewardj00a66b12002-10-12 16:42:35 +00001429 void** specifics_ptr;
1430 int res, i;
sewardj5f07b662002-04-23 16:52:51 +00001431 ensure_valgrind("pthread_key_create");
sewardj00a66b12002-10-12 16:42:35 +00001432
1433 /* This writes *key if successful. It should never fail. */
1434 VALGRIND_MAGIC_SEQUENCE(res, 1 /* default */,
sewardj5f07b662002-04-23 16:52:51 +00001435 VG_USERREQ__PTHREAD_KEY_CREATE,
1436 key, destr_function, 0, 0);
sewardj00a66b12002-10-12 16:42:35 +00001437 my_assert(res == 0);
1438
1439 /* POSIX sez: "Upon key creation, the value NULL shall be
1440 associated with the new key in all active threads." */
1441 for (i = 0; i < VG_N_THREADS; i++) {
1442 specifics_ptr = get_or_allocate_specifics_ptr(i);
1443 /* we get NULL if i is an invalid thread. */
1444 if (specifics_ptr != NULL)
1445 specifics_ptr[*key] = NULL;
1446 }
1447
sewardj5f07b662002-04-23 16:52:51 +00001448 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001449}
1450
1451int pthread_key_delete(pthread_key_t key)
1452{
sewardj00a66b12002-10-12 16:42:35 +00001453 int res;
1454 ensure_valgrind("pthread_key_create");
1455 if (!key_is_valid(key))
1456 return EINVAL;
1457 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1458 VG_USERREQ__PTHREAD_KEY_DELETE,
1459 key, 0, 0, 0);
1460 my_assert(res == 0);
sewardj5e5fa512002-04-14 13:13:05 +00001461 return 0;
1462}
1463
sewardj5905fae2002-04-26 13:25:00 +00001464int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001465{
sewardj00a66b12002-10-12 16:42:35 +00001466 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001467 ensure_valgrind("pthread_setspecific");
sewardj00a66b12002-10-12 16:42:35 +00001468
1469 if (!key_is_valid(key))
1470 return EINVAL;
1471
1472 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1473 specifics_ptr[key] = (void*)pointer;
1474 return 0;
sewardj5e5fa512002-04-14 13:13:05 +00001475}
1476
sewardj5905fae2002-04-26 13:25:00 +00001477void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001478{
sewardj00a66b12002-10-12 16:42:35 +00001479 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001480 ensure_valgrind("pthread_getspecific");
sewardj00a66b12002-10-12 16:42:35 +00001481
1482 if (!key_is_valid(key))
1483 return NULL;
1484
1485 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1486 return specifics_ptr[key];
1487}
1488
1489
sewardj9aa918d2002-10-20 16:25:55 +00001490#ifdef GLIBC_2_3
sewardj00a66b12002-10-12 16:42:35 +00001491static
1492void ** __pthread_getspecific_addr(pthread_key_t key)
1493{
1494 void** specifics_ptr;
1495 ensure_valgrind("pthread_getspecific_addr");
1496
1497 if (!key_is_valid(key))
1498 return NULL;
1499
1500 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1501 return &(specifics_ptr[key]);
sewardj5e5fa512002-04-14 13:13:05 +00001502}
sewardj9aa918d2002-10-20 16:25:55 +00001503#endif
sewardjf8f819e2002-04-17 23:21:37 +00001504
sewardjc91a4ff2003-07-11 00:12:58 +00001505
sewardjf8f819e2002-04-17 23:21:37 +00001506/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001507 ONCEry
1508 ------------------------------------------------ */
1509
sewardjc91a4ff2003-07-11 00:12:58 +00001510/* This protects reads and writes of the once_control variable
1511 supplied. It is never held whilst any particular initialiser is
1512 running. */
sewardj89d3d852002-04-24 19:21:39 +00001513static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1514
sewardjc91a4ff2003-07-11 00:12:58 +00001515/* Initialiser needs to be run. */
1516#define P_ONCE_NOT_DONE ((PTHREAD_ONCE_INIT) + 0)
1517
1518/* Initialiser currently running. */
1519#define P_ONCE_RUNNING ((PTHREAD_ONCE_INIT) + 1)
1520
1521/* Initialiser has completed. */
1522#define P_ONCE_COMPLETED ((PTHREAD_ONCE_INIT) + 2)
sewardj89d3d852002-04-24 19:21:39 +00001523
sewardj5905fae2002-04-26 13:25:00 +00001524int __pthread_once ( pthread_once_t *once_control,
1525 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001526{
1527 int res;
sewardjc91a4ff2003-07-11 00:12:58 +00001528 int done;
sewardj89d3d852002-04-24 19:21:39 +00001529 ensure_valgrind("pthread_once");
1530
sewardjc91a4ff2003-07-11 00:12:58 +00001531# define TAKE_LOCK \
1532 res = __pthread_mutex_lock(&once_masterlock); \
1533 my_assert(res == 0);
sewardj89d3d852002-04-24 19:21:39 +00001534
sewardjc91a4ff2003-07-11 00:12:58 +00001535# define RELEASE_LOCK \
1536 res = __pthread_mutex_unlock(&once_masterlock); \
1537 my_assert(res == 0);
sewardj89d3d852002-04-24 19:21:39 +00001538
sewardjc91a4ff2003-07-11 00:12:58 +00001539 /* Grab the lock transiently, so we can safely see what state this
1540 once_control is in. */
1541
1542 TAKE_LOCK;
1543
1544 switch (*once_control) {
1545
1546 case P_ONCE_NOT_DONE:
1547 /* Not started. Change state to indicate running, drop the
1548 lock and run. */
1549 *once_control = P_ONCE_RUNNING;
1550 RELEASE_LOCK;
1551 init_routine();
1552 /* re-take the lock, and set state to indicate done. */
1553 TAKE_LOCK;
1554 *once_control = P_ONCE_COMPLETED;
1555 RELEASE_LOCK;
1556 break;
1557
1558 case P_ONCE_RUNNING:
1559 /* This is the tricky case. The initialiser is running in
1560 some other thread, but we have to delay this thread till
1561 the other one completes. So we sort-of busy wait. In
1562 fact it makes sense to yield now, because what we want to
1563 happen is for the thread running the initialiser to
1564 complete ASAP. */
1565 RELEASE_LOCK;
1566 done = 0;
1567 while (1) {
1568 /* Let others run for a while. */
1569 __valgrind_pthread_yield();
1570 /* Grab the lock and see if we're done waiting. */
1571 TAKE_LOCK;
1572 if (*once_control == P_ONCE_COMPLETED)
1573 done = 1;
1574 RELEASE_LOCK;
1575 if (done)
1576 break;
1577 }
1578 break;
1579
1580 case P_ONCE_COMPLETED:
1581 default:
1582 /* Easy. It's already done. Just drop the lock. */
1583 RELEASE_LOCK;
1584 break;
sewardj89d3d852002-04-24 19:21:39 +00001585 }
1586
sewardj89d3d852002-04-24 19:21:39 +00001587 return 0;
sewardjc91a4ff2003-07-11 00:12:58 +00001588
1589# undef TAKE_LOCK
1590# undef RELEASE_LOCK
sewardj89d3d852002-04-24 19:21:39 +00001591}
1592
sewardjc91a4ff2003-07-11 00:12:58 +00001593#undef P_ONCE_NOT_DONE
1594#undef P_ONCE_RUNNING
1595#undef P_ONCE_COMPLETED
1596
sewardj89d3d852002-04-24 19:21:39 +00001597
1598/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001599 MISC
1600 ------------------------------------------------ */
1601
sewardj2cb00342002-06-28 01:46:26 +00001602static pthread_mutex_t pthread_atfork_lock
1603 = PTHREAD_MUTEX_INITIALIZER;
1604
sewardj5905fae2002-04-26 13:25:00 +00001605int __pthread_atfork ( void (*prepare)(void),
1606 void (*parent)(void),
1607 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001608{
sewardj2cb00342002-06-28 01:46:26 +00001609 int n, res;
1610 ForkHandlerEntry entry;
1611
1612 ensure_valgrind("pthread_atfork");
1613 __pthread_mutex_lock(&pthread_atfork_lock);
1614
1615 /* Fetch old counter */
1616 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1617 VG_USERREQ__GET_FHSTACK_USED,
1618 0, 0, 0, 0);
1619 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1620 if (n == VG_N_FORKHANDLERSTACK-1)
1621 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1622 "increase and recompile");
1623
1624 /* Add entry */
1625 entry.prepare = *prepare;
1626 entry.parent = *parent;
1627 entry.child = *child;
1628 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1629 VG_USERREQ__SET_FHSTACK_ENTRY,
1630 n, &entry, 0, 0);
1631 my_assert(res == 0);
1632
1633 /* Bump counter */
1634 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1635 VG_USERREQ__SET_FHSTACK_USED,
1636 n+1, 0, 0, 0);
1637 my_assert(res == 0);
1638
1639 __pthread_mutex_unlock(&pthread_atfork_lock);
1640 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001641}
1642
1643
sewardj9df78832003-05-04 12:35:54 +00001644#ifdef GLIBC_2_3
1645/* This seems to be a hook which appeared in glibc-2.3.2. */
1646int __register_atfork ( void (*prepare)(void),
1647 void (*parent)(void),
1648 void (*child)(void) )
1649{
1650 return __pthread_atfork(prepare,parent,child);
1651}
1652#endif
1653
sewardj11f0bb42003-04-26 20:11:15 +00001654WEAK
sewardjbb990782002-05-08 02:01:14 +00001655void __pthread_initialize ( void )
1656{
sewardjbea1caa2002-05-10 23:20:58 +00001657 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001658}
1659
1660
sewardj853f55d2002-04-26 00:27:53 +00001661/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001662 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001663 ------------------------------------------------ */
1664
sewardj3b13f0e2002-04-25 20:17:29 +00001665#include <resolv.h>
1666static int thread_specific_errno[VG_N_THREADS];
1667static int thread_specific_h_errno[VG_N_THREADS];
1668static struct __res_state
1669 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001670
sewardj25418ae2003-05-09 23:40:34 +00001671#undef errno
1672extern int errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001673int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001674{
1675 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001676 /* ensure_valgrind("__errno_location"); */
1677 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001678 VG_USERREQ__PTHREAD_GET_THREADID,
1679 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001680 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001681 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001682 barf("__errno_location: invalid ThreadId");
sewardj25418ae2003-05-09 23:40:34 +00001683 if (tid == 1)
1684 return &errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001685 return & thread_specific_errno[tid];
1686}
1687
sewardj25418ae2003-05-09 23:40:34 +00001688#undef h_errno
1689extern int h_errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001690int* __h_errno_location ( void )
1691{
1692 int tid;
1693 /* ensure_valgrind("__h_errno_location"); */
1694 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1695 VG_USERREQ__PTHREAD_GET_THREADID,
1696 0, 0, 0, 0);
1697 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001698 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001699 barf("__h_errno_location: invalid ThreadId");
sewardj25418ae2003-05-09 23:40:34 +00001700 if (tid == 1)
1701 return &h_errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001702 return & thread_specific_h_errno[tid];
1703}
1704
sewardjb0ff1032002-08-06 09:02:53 +00001705
1706#undef _res
1707extern struct __res_state _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001708struct __res_state* __res_state ( void )
1709{
1710 int tid;
1711 /* ensure_valgrind("__res_state"); */
1712 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1713 VG_USERREQ__PTHREAD_GET_THREADID,
1714 0, 0, 0, 0);
1715 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001716 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001717 barf("__res_state: invalid ThreadId");
sewardjb0ff1032002-08-06 09:02:53 +00001718 if (tid == 1)
1719 return & _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001720 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001721}
1722
1723
sewardj5716dbb2002-04-26 03:28:18 +00001724/* ---------------------------------------------------
1725 LIBC-PRIVATE SPECIFIC DATA
1726 ------------------------------------------------ */
1727
1728/* Relies on assumption that initial private data is NULL. This
1729 should be fixed somehow. */
1730
njn25e49d8e72002-09-23 09:36:25 +00001731/* The allowable keys (indices) (all 3 of them).
sewardj5716dbb2002-04-26 03:28:18 +00001732 From sysdeps/pthread/bits/libc-tsd.h
1733*/
sewardjcb7f08a2002-10-02 09:41:49 +00001734/* as per glibc anoncvs HEAD of 20021001. */
sewardj5716dbb2002-04-26 03:28:18 +00001735enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1736 _LIBC_TSD_KEY_DL_ERROR,
njn25e49d8e72002-09-23 09:36:25 +00001737 _LIBC_TSD_KEY_RPC_VARS,
sewardjcb7f08a2002-10-02 09:41:49 +00001738 _LIBC_TSD_KEY_LOCALE,
1739 _LIBC_TSD_KEY_CTYPE_B,
1740 _LIBC_TSD_KEY_CTYPE_TOLOWER,
1741 _LIBC_TSD_KEY_CTYPE_TOUPPER,
sewardj5716dbb2002-04-26 03:28:18 +00001742 _LIBC_TSD_KEY_N };
1743
1744/* Auto-initialising subsystem. libc_specifics_inited is set
1745 after initialisation. libc_specifics_inited_mx guards it. */
1746static int libc_specifics_inited = 0;
1747static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1748
sewardj00a66b12002-10-12 16:42:35 +00001749
sewardj5716dbb2002-04-26 03:28:18 +00001750/* These are the keys we must initialise the first time. */
sewardjcb7f08a2002-10-02 09:41:49 +00001751static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N];
sewardj5716dbb2002-04-26 03:28:18 +00001752
sewardj00a66b12002-10-12 16:42:35 +00001753
sewardjcb7f08a2002-10-02 09:41:49 +00001754/* Initialise the keys, if they are not already initialised. */
sewardj5716dbb2002-04-26 03:28:18 +00001755static
1756void init_libc_tsd_keys ( void )
1757{
1758 int res, i;
1759 pthread_key_t k;
1760
sewardj08c7f012002-10-07 23:56:55 +00001761 /* Don't fall into deadlock if we get called again whilst we still
1762 hold the lock, via the __uselocale() call herein. */
1763 if (libc_specifics_inited != 0)
1764 return;
1765
1766 /* Take the lock. */
sewardj00a66b12002-10-12 16:42:35 +00001767 res = __pthread_mutex_lock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001768 if (res != 0) barf("init_libc_tsd_keys: lock");
1769
sewardj08c7f012002-10-07 23:56:55 +00001770 /* Now test again, to be sure there is no mistake. */
1771 if (libc_specifics_inited != 0) {
sewardj00a66b12002-10-12 16:42:35 +00001772 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj08c7f012002-10-07 23:56:55 +00001773 if (res != 0) barf("init_libc_tsd_keys: unlock(1)");
1774 return;
sewardj5716dbb2002-04-26 03:28:18 +00001775 }
1776
sewardj08c7f012002-10-07 23:56:55 +00001777 /* Actually do the initialisation. */
1778 /* printf("INIT libc specifics\n"); */
1779 for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
sewardj00a66b12002-10-12 16:42:35 +00001780 res = __pthread_key_create(&k, NULL);
sewardj08c7f012002-10-07 23:56:55 +00001781 if (res != 0) barf("init_libc_tsd_keys: create");
1782 libc_specifics_keys[i] = k;
1783 }
1784
1785 /* Signify init done. */
1786 libc_specifics_inited = 1;
1787
1788# ifdef GLIBC_2_3
1789 /* Set the initialising thread's locale to the global (default)
sewardj00a66b12002-10-12 16:42:35 +00001790 locale. A hack in support of glibc-2.3. This does the biz for
1791 the root thread. For all other threads we run this in
1792 thread_wrapper(), which does the real work of
1793 pthread_create(). */
1794 /* assert that we are the root thread. I don't know if this is
1795 really a valid assertion to make; if it breaks I'll reconsider
1796 it. */
1797 my_assert(pthread_self() == 1);
sewardj08c7f012002-10-07 23:56:55 +00001798 __uselocale(LC_GLOBAL_LOCALE);
1799# endif
1800
1801 /* Unlock and return. */
sewardj00a66b12002-10-12 16:42:35 +00001802 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001803 if (res != 0) barf("init_libc_tsd_keys: unlock");
1804}
1805
1806
1807static int
1808libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1809 const void * pointer )
1810{
sewardjcb7f08a2002-10-02 09:41:49 +00001811 int res;
sewardj5716dbb2002-04-26 03:28:18 +00001812 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardjcb7f08a2002-10-02 09:41:49 +00001813 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001814 barf("libc_internal_tsd_set: invalid key");
1815 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001816 res = __pthread_setspecific(libc_specifics_keys[key], pointer);
sewardj5716dbb2002-04-26 03:28:18 +00001817 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1818 return 0;
1819}
1820
1821static void *
1822libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1823{
sewardjcb7f08a2002-10-02 09:41:49 +00001824 void* v;
sewardj5716dbb2002-04-26 03:28:18 +00001825 /* printf("GET GET GET key %d\n", key); */
sewardjcb7f08a2002-10-02 09:41:49 +00001826 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001827 barf("libc_internal_tsd_get: invalid key");
1828 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001829 v = __pthread_getspecific(libc_specifics_keys[key]);
sewardj5716dbb2002-04-26 03:28:18 +00001830 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1831 return v;
1832}
1833
1834
sewardj70adeb22002-04-27 01:35:38 +00001835int (*__libc_internal_tsd_set)
1836 (enum __libc_tsd_key_t key, const void * pointer)
1837 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001838
sewardj70adeb22002-04-27 01:35:38 +00001839void* (*__libc_internal_tsd_get)
1840 (enum __libc_tsd_key_t key)
1841 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001842
1843
sewardj00a66b12002-10-12 16:42:35 +00001844#ifdef GLIBC_2_3
1845/* This one was first spotted be me in the glibc-2.2.93 sources. */
1846static void**
1847libc_internal_tsd_address ( enum __libc_tsd_key_t key )
1848{
1849 void** v;
1850 /* printf("ADDR ADDR ADDR key %d\n", key); */
1851 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
1852 barf("libc_internal_tsd_address: invalid key");
1853 init_libc_tsd_keys();
1854 v = __pthread_getspecific_addr(libc_specifics_keys[key]);
1855 return v;
1856}
1857
1858void ** (*__libc_internal_tsd_address)
1859 (enum __libc_tsd_key_t key)
1860 = libc_internal_tsd_address;
1861#endif
1862
1863
sewardje663cb92002-04-12 10:26:32 +00001864/* ---------------------------------------------------------------------
1865 These are here (I think) because they are deemed cancellation
1866 points by POSIX. For the moment we'll simply pass the call along
1867 to the corresponding thread-unaware (?) libc routine.
1868 ------------------------------------------------------------------ */
1869
sewardjd529a442002-05-04 19:49:21 +00001870#ifdef GLIBC_2_1
1871extern
1872int __sigaction
1873 (int signum,
1874 const struct sigaction *act,
1875 struct sigaction *oldact);
1876#else
sewardje663cb92002-04-12 10:26:32 +00001877extern
1878int __libc_sigaction
1879 (int signum,
1880 const struct sigaction *act,
1881 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001882#endif
sewardje663cb92002-04-12 10:26:32 +00001883int sigaction(int signum,
1884 const struct sigaction *act,
1885 struct sigaction *oldact)
1886{
sewardjd140e442002-05-29 01:21:19 +00001887 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001888# ifdef GLIBC_2_1
1889 return __sigaction(signum, act, oldact);
1890# else
sewardj45b4b372002-04-16 22:50:32 +00001891 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001892# endif
sewardje663cb92002-04-12 10:26:32 +00001893}
1894
1895
1896extern
1897int __libc_connect(int sockfd,
1898 const struct sockaddr *serv_addr,
1899 socklen_t addrlen);
sewardj11f0bb42003-04-26 20:11:15 +00001900WEAK
sewardje663cb92002-04-12 10:26:32 +00001901int connect(int sockfd,
1902 const struct sockaddr *serv_addr,
1903 socklen_t addrlen)
1904{
sewardjd140e442002-05-29 01:21:19 +00001905 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001906 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001907}
1908
1909
1910extern
1911int __libc_fcntl(int fd, int cmd, long arg);
sewardj11f0bb42003-04-26 20:11:15 +00001912WEAK
sewardje663cb92002-04-12 10:26:32 +00001913int fcntl(int fd, int cmd, long arg)
1914{
sewardjd140e442002-05-29 01:21:19 +00001915 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001916 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001917}
1918
1919
1920extern
1921ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj11f0bb42003-04-26 20:11:15 +00001922WEAK
sewardje663cb92002-04-12 10:26:32 +00001923ssize_t write(int fd, const void *buf, size_t count)
1924{
sewardjd140e442002-05-29 01:21:19 +00001925 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001926 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001927}
1928
1929
1930extern
1931ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj11f0bb42003-04-26 20:11:15 +00001932WEAK
sewardje663cb92002-04-12 10:26:32 +00001933ssize_t read(int fd, void *buf, size_t count)
1934{
sewardjd140e442002-05-29 01:21:19 +00001935 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001936 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001937}
1938
sewardjf912dfc2002-11-13 21:51:10 +00001939/*
1940 * Ugh, this is horrible but here goes:
1941 *
1942 * Open of a named pipe (fifo file) can block. In a threaded program,
1943 * this means that the whole thing can block. We therefore need to
1944 * make the open appear to block to the caller, but still keep polling
1945 * for everyone else.
1946 *
1947 * There are four cases:
1948 *
1949 * - the caller asked for O_NONBLOCK. The easy one: we just do it.
1950 *
1951 * - the caller asked for a blocking O_RDONLY open. We open it with
1952 * O_NONBLOCK and then use poll to wait for it to become ready.
1953 *
1954 * - the caller asked for a blocking O_WRONLY open. Unfortunately, this
1955 * will fail with ENXIO when we make it non-blocking. Doubly
1956 * unfortunate is that we can only rely on these semantics if it is
1957 * actually a fifo file; the hack is that if we see that it is a
1958 * O_WRONLY open and we get ENXIO, then stat the path and see if it
1959 * actually is a fifo. This is racy, but it is the best we can do.
1960 * If it is a fifo, then keep trying the open until it works; if not
1961 * just return the error.
1962 *
1963 * - the caller asked for a blocking O_RDWR open. Well, under Linux,
1964 * this never blocks, so we just clear the non-blocking flag and
1965 * return.
1966 *
1967 * This code assumes that for whatever we open, O_NONBLOCK followed by
1968 * a fcntl clearing O_NONBLOCK is the same as opening without
1969 * O_NONBLOCK. Also assumes that stat and fstat have no side-effects.
1970 *
1971 * XXX Should probably put in special cases for some devices as well,
1972 * like serial ports. Unfortunately they don't work like fifos, so
1973 * this logic will become even more tortured. Wait until we really
1974 * need it.
1975 */
1976static inline int _open(const char *pathname, int flags, mode_t mode,
1977 int (*openp)(const char *, int, mode_t))
sewardjbe32e452002-04-24 20:29:58 +00001978{
sewardjf912dfc2002-11-13 21:51:10 +00001979 int fd;
1980 struct stat st;
1981 struct vki_timespec nanosleep_interval;
1982 int saved_errno;
1983
sewardjd140e442002-05-29 01:21:19 +00001984 __my_pthread_testcancel();
sewardjf912dfc2002-11-13 21:51:10 +00001985
1986 /* Assume we can only get O_RDONLY, O_WRONLY or O_RDWR */
1987 my_assert((flags & VKI_O_ACCMODE) != VKI_O_ACCMODE);
1988
1989 for(;;) {
1990 fd = (*openp)(pathname, flags | VKI_O_NONBLOCK, mode);
1991
1992 /* return immediately if caller wanted nonblocking anyway */
1993 if (flags & VKI_O_NONBLOCK)
1994 return fd;
1995
sewardj25418ae2003-05-09 23:40:34 +00001996 saved_errno = *(__errno_location());
sewardjf912dfc2002-11-13 21:51:10 +00001997
1998 if (fd != -1)
1999 break; /* open worked */
2000
2001 /* If we got ENXIO and we're opening WRONLY, and it turns out
2002 to really be a FIFO, then poll waiting for open to succeed */
sewardj25418ae2003-05-09 23:40:34 +00002003 if (*(__errno_location()) == ENXIO &&
sewardjf912dfc2002-11-13 21:51:10 +00002004 (flags & VKI_O_ACCMODE) == VKI_O_WRONLY &&
2005 (stat(pathname, &st) == 0 && S_ISFIFO(st.st_mode))) {
2006
2007 /* OK, we're opening a FIFO for writing; sleep and spin */
2008 nanosleep_interval.tv_sec = 0;
2009 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
2010 /* It's critical here that valgrind's nanosleep implementation
2011 is nonblocking. */
2012 (void)my_do_syscall2(__NR_nanosleep,
2013 (int)(&nanosleep_interval), (int)NULL);
2014 } else {
2015 /* it was just an error */
sewardj25418ae2003-05-09 23:40:34 +00002016 *(__errno_location()) = saved_errno;
sewardjf912dfc2002-11-13 21:51:10 +00002017 return -1;
2018 }
2019 }
2020
2021 /* OK, we've got a nonblocking FD for a caller who wants blocking;
2022 reset the flags to what they asked for */
2023 fcntl(fd, VKI_F_SETFL, flags);
2024
2025 /* Return now if one of:
2026 - we were opening O_RDWR (never blocks)
2027 - we opened with O_WRONLY (polling already done)
2028 - the thing we opened wasn't a FIFO after all (or fstat failed)
2029 */
2030 if ((flags & VKI_O_ACCMODE) != VKI_O_RDONLY ||
2031 (fstat(fd, &st) == -1 || !S_ISFIFO(st.st_mode))) {
sewardj25418ae2003-05-09 23:40:34 +00002032 *(__errno_location()) = saved_errno;
sewardjf912dfc2002-11-13 21:51:10 +00002033 return fd;
2034 }
2035
2036 /* OK, drop into the poll loop looking for something to read on the fd */
2037 my_assert((flags & VKI_O_ACCMODE) == VKI_O_RDONLY);
2038 for(;;) {
2039 struct pollfd pollfd;
2040 int res;
2041
2042 pollfd.fd = fd;
2043 pollfd.events = POLLIN;
2044 pollfd.revents = 0;
2045
2046 res = my_do_syscall3(__NR_poll, (int)&pollfd, 1, 0);
2047
2048 my_assert(res == 0 || res == 1);
2049
2050 if (res == 1) {
2051 /* OK, got it.
2052
2053 XXX This is wrong: we're waiting for either something to
2054 read or a HUP on the file descriptor, but the semantics of
2055 fifo open are that we should unblock as soon as someone
2056 simply opens the other end, not that they write something.
2057 With luck this won't matter in practice.
2058 */
2059 my_assert(pollfd.revents & (POLLIN|POLLHUP));
2060 break;
2061 }
2062
2063 /* Still nobody home; sleep and spin */
2064 nanosleep_interval.tv_sec = 0;
2065 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
2066 /* It's critical here that valgrind's nanosleep implementation
2067 is nonblocking. */
2068 (void)my_do_syscall2(__NR_nanosleep,
2069 (int)(&nanosleep_interval), (int)NULL);
2070 }
2071
sewardj25418ae2003-05-09 23:40:34 +00002072 *(__errno_location()) = saved_errno;
sewardjf912dfc2002-11-13 21:51:10 +00002073 return fd;
sewardjbe32e452002-04-24 20:29:58 +00002074}
2075
sewardjf912dfc2002-11-13 21:51:10 +00002076extern
2077int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj11f0bb42003-04-26 20:11:15 +00002078/* WEAK */
sewardjf912dfc2002-11-13 21:51:10 +00002079int open64(const char *pathname, int flags, mode_t mode)
2080{
2081 return _open(pathname, flags, mode, __libc_open64);
2082}
sewardje663cb92002-04-12 10:26:32 +00002083
2084extern
sewardj853f55d2002-04-26 00:27:53 +00002085int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj11f0bb42003-04-26 20:11:15 +00002086/* WEAK */
sewardj853f55d2002-04-26 00:27:53 +00002087int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00002088{
sewardjf912dfc2002-11-13 21:51:10 +00002089 return _open(pathname, flags, mode, __libc_open);
sewardje663cb92002-04-12 10:26:32 +00002090}
2091
sewardje663cb92002-04-12 10:26:32 +00002092extern
2093int __libc_close(int fd);
sewardj11f0bb42003-04-26 20:11:15 +00002094WEAK
sewardje663cb92002-04-12 10:26:32 +00002095int close(int fd)
2096{
sewardjd140e442002-05-29 01:21:19 +00002097 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002098 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00002099}
2100
2101
sewardj11f0bb42003-04-26 20:11:15 +00002102WEAK
2103int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
sewardje663cb92002-04-12 10:26:32 +00002104{
sewardj11f0bb42003-04-26 20:11:15 +00002105 return VGR_(accept)(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00002106}
2107
sewardj11f0bb42003-04-26 20:11:15 +00002108WEAK
2109int recv(int s, void *buf, size_t len, int flags)
sewardj0c573af92002-10-23 21:55:01 +00002110{
sewardj11f0bb42003-04-26 20:11:15 +00002111 return VGR_(recv)(s, buf, len, flags);
sewardj0c573af92002-10-23 21:55:01 +00002112}
2113
sewardj11f0bb42003-04-26 20:11:15 +00002114WEAK
2115int readv(int fd, const struct iovec *iov, int count)
sewardj2a68e7e2002-11-16 11:04:18 +00002116{
sewardj11f0bb42003-04-26 20:11:15 +00002117 return VGR_(readv)(fd, iov, count);
sewardj2a68e7e2002-11-16 11:04:18 +00002118}
2119
sewardj11f0bb42003-04-26 20:11:15 +00002120WEAK
2121int writev(int fd, const struct iovec *iov, int count)
sewardj2a68e7e2002-11-16 11:04:18 +00002122{
sewardj11f0bb42003-04-26 20:11:15 +00002123 return VGR_(writev)(fd, iov, count);
sewardj2a68e7e2002-11-16 11:04:18 +00002124}
sewardje663cb92002-04-12 10:26:32 +00002125
2126extern
sewardje663cb92002-04-12 10:26:32 +00002127pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj11f0bb42003-04-26 20:11:15 +00002128WEAK
sewardje663cb92002-04-12 10:26:32 +00002129pid_t waitpid(pid_t pid, int *status, int options)
2130{
sewardjd140e442002-05-29 01:21:19 +00002131 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002132 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00002133}
2134
2135
2136extern
2137int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj11f0bb42003-04-26 20:11:15 +00002138WEAK
sewardje663cb92002-04-12 10:26:32 +00002139int nanosleep(const struct timespec *req, struct timespec *rem)
2140{
sewardjd140e442002-05-29 01:21:19 +00002141 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00002142 return __libc_nanosleep(req, rem);
2143}
2144
sewardjbe32e452002-04-24 20:29:58 +00002145
sewardje663cb92002-04-12 10:26:32 +00002146extern
2147int __libc_fsync(int fd);
sewardj11f0bb42003-04-26 20:11:15 +00002148WEAK
sewardje663cb92002-04-12 10:26:32 +00002149int fsync(int fd)
2150{
sewardjd140e442002-05-29 01:21:19 +00002151 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002152 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00002153}
2154
sewardjbe32e452002-04-24 20:29:58 +00002155
sewardj70c75362002-04-13 04:18:32 +00002156extern
2157off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj11f0bb42003-04-26 20:11:15 +00002158WEAK
sewardj70c75362002-04-13 04:18:32 +00002159off_t lseek(int fildes, off_t offset, int whence)
2160{
sewardjd140e442002-05-29 01:21:19 +00002161 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002162 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00002163}
2164
sewardjbe32e452002-04-24 20:29:58 +00002165
2166extern
2167__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj11f0bb42003-04-26 20:11:15 +00002168WEAK
sewardjbe32e452002-04-24 20:29:58 +00002169__off64_t lseek64(int fildes, __off64_t offset, int whence)
2170{
sewardjd140e442002-05-29 01:21:19 +00002171 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00002172 return __libc_lseek64(fildes, offset, whence);
2173}
2174
2175
sewardj726c4122002-05-16 23:39:10 +00002176extern
2177ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
2178 __off64_t __offset);
2179ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
2180 __off64_t __offset)
2181{
sewardjd140e442002-05-29 01:21:19 +00002182 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00002183 return __libc_pread64(__fd, __buf, __nbytes, __offset);
2184}
2185
2186
sewardja18e2102002-05-18 10:43:22 +00002187extern
2188ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
2189 __off64_t __offset);
2190ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
2191 __off64_t __offset)
2192{
sewardjd140e442002-05-29 01:21:19 +00002193 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00002194 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
2195}
2196
sewardj726c4122002-05-16 23:39:10 +00002197
sewardj39b93b12002-05-18 10:56:27 +00002198extern
2199ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
sewardj11f0bb42003-04-26 20:11:15 +00002200WEAK
sewardj39b93b12002-05-18 10:56:27 +00002201ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
2202{
sewardjd140e442002-05-29 01:21:19 +00002203 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00002204 return __libc_pwrite(fd, buf, count, offset);
2205}
2206
2207
2208extern
2209ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
sewardj11f0bb42003-04-26 20:11:15 +00002210WEAK
sewardj39b93b12002-05-18 10:56:27 +00002211ssize_t pread(int fd, void *buf, size_t count, off_t offset)
2212{
sewardjd140e442002-05-29 01:21:19 +00002213 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00002214 return __libc_pread(fd, buf, count, offset);
2215}
2216
2217
sewardj6af4b5d2002-04-16 04:40:49 +00002218extern
2219void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj11f0bb42003-04-26 20:11:15 +00002220/* not weak: WEAK */
sewardj6af4b5d2002-04-16 04:40:49 +00002221void longjmp(jmp_buf env, int val)
2222{
2223 __libc_longjmp(env, val);
2224}
2225
sewardjbe32e452002-04-24 20:29:58 +00002226
sewardj436c2db2002-06-18 09:07:54 +00002227extern void __libc_siglongjmp (sigjmp_buf env, int val)
2228 __attribute__ ((noreturn));
2229void siglongjmp(sigjmp_buf env, int val)
2230{
2231 kludged("siglongjmp (cleanup handlers are ignored)");
2232 __libc_siglongjmp(env, val);
2233}
2234
2235
sewardj6af4b5d2002-04-16 04:40:49 +00002236extern
2237int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002238WEAK
sewardj6af4b5d2002-04-16 04:40:49 +00002239int send(int s, const void *msg, size_t len, int flags)
2240{
sewardjd140e442002-05-29 01:21:19 +00002241 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00002242 return __libc_send(s, msg, len, flags);
2243}
2244
sewardjbe32e452002-04-24 20:29:58 +00002245
sewardj3665ded2002-05-16 16:57:25 +00002246extern
2247int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002248WEAK
sewardj3665ded2002-05-16 16:57:25 +00002249int sendmsg(int s, const struct msghdr *msg, int flags)
2250{
sewardjd140e442002-05-29 01:21:19 +00002251 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00002252 return __libc_sendmsg(s, msg, flags);
2253}
2254
2255
sewardj796d6a22002-04-24 02:28:34 +00002256extern
sewardj59da27a2002-06-06 08:33:54 +00002257int __libc_recvmsg(int s, struct msghdr *msg, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002258WEAK
sewardj59da27a2002-06-06 08:33:54 +00002259int recvmsg(int s, struct msghdr *msg, int flags)
2260{
2261 __my_pthread_testcancel();
2262 return __libc_recvmsg(s, msg, flags);
2263}
2264
2265
2266extern
sewardj436e0582002-04-26 14:31:40 +00002267int __libc_recvfrom(int s, void *buf, size_t len, int flags,
2268 struct sockaddr *from, socklen_t *fromlen);
sewardj11f0bb42003-04-26 20:11:15 +00002269WEAK
sewardj436e0582002-04-26 14:31:40 +00002270int recvfrom(int s, void *buf, size_t len, int flags,
2271 struct sockaddr *from, socklen_t *fromlen)
2272{
sewardjd140e442002-05-29 01:21:19 +00002273 __my_pthread_testcancel();
sewardj11f0bb42003-04-26 20:11:15 +00002274 VGR_(wait_for_fd_to_be_readable_or_erring)(s);
sewardj2e207632002-06-13 17:29:53 +00002275 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00002276 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
2277}
2278
2279
2280extern
sewardj796d6a22002-04-24 02:28:34 +00002281int __libc_sendto(int s, const void *msg, size_t len, int flags,
2282 const struct sockaddr *to, socklen_t tolen);
sewardj11f0bb42003-04-26 20:11:15 +00002283WEAK
sewardj796d6a22002-04-24 02:28:34 +00002284int sendto(int s, const void *msg, size_t len, int flags,
2285 const struct sockaddr *to, socklen_t tolen)
2286{
sewardjd140e442002-05-29 01:21:19 +00002287 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00002288 return __libc_sendto(s, msg, len, flags, to, tolen);
2289}
2290
sewardjbe32e452002-04-24 20:29:58 +00002291
sewardj369b1702002-04-24 13:28:15 +00002292extern
2293int __libc_system(const char* str);
sewardj11f0bb42003-04-26 20:11:15 +00002294WEAK
sewardj369b1702002-04-24 13:28:15 +00002295int system(const char* str)
2296{
sewardjd140e442002-05-29 01:21:19 +00002297 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00002298 return __libc_system(str);
2299}
2300
sewardjbe32e452002-04-24 20:29:58 +00002301
sewardjab0b1c32002-04-24 19:26:47 +00002302extern
2303pid_t __libc_wait(int *status);
sewardj11f0bb42003-04-26 20:11:15 +00002304WEAK
sewardjab0b1c32002-04-24 19:26:47 +00002305pid_t wait(int *status)
2306{
sewardjd140e442002-05-29 01:21:19 +00002307 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00002308 return __libc_wait(status);
2309}
2310
sewardj45b4b372002-04-16 22:50:32 +00002311
sewardj67f1d582002-05-24 02:11:32 +00002312extern
2313int __libc_msync(const void *start, size_t length, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002314WEAK
sewardj67f1d582002-05-24 02:11:32 +00002315int msync(const void *start, size_t length, int flags)
2316{
sewardjd140e442002-05-29 01:21:19 +00002317 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00002318 return __libc_msync(start, length, flags);
2319}
2320
sewardj5905fae2002-04-26 13:25:00 +00002321
sewardj2cb00342002-06-28 01:46:26 +00002322/*--- fork and its helper ---*/
2323
2324static
2325void run_fork_handlers ( int what )
2326{
2327 ForkHandlerEntry entry;
2328 int n_h, n_handlers, i, res;
2329
2330 my_assert(what == 0 || what == 1 || what == 2);
2331
2332 /* Fetch old counter */
2333 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2334 VG_USERREQ__GET_FHSTACK_USED,
2335 0, 0, 0, 0);
2336 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2337
2338 /* Prepare handlers (what == 0) are called in opposite order of
2339 calls to pthread_atfork. Parent and child handlers are called
2340 in the same order as calls to pthread_atfork. */
2341 if (what == 0)
2342 n_h = n_handlers - 1;
2343 else
2344 n_h = 0;
2345
2346 for (i = 0; i < n_handlers; i++) {
2347 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2348 VG_USERREQ__GET_FHSTACK_ENTRY,
2349 n_h, &entry, 0, 0);
2350 my_assert(res == 0);
2351 switch (what) {
2352 case 0: if (entry.prepare) entry.prepare();
2353 n_h--; break;
2354 case 1: if (entry.parent) entry.parent();
2355 n_h++; break;
2356 case 2: if (entry.child) entry.child();
2357 n_h++; break;
2358 default: barf("run_fork_handlers: invalid what");
2359 }
2360 }
2361
2362 if (what != 0 /* prepare */) {
2363 /* Empty out the stack. */
2364 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2365 VG_USERREQ__SET_FHSTACK_USED,
2366 0, 0, 0, 0);
2367 my_assert(res == 0);
2368 }
2369}
2370
2371extern
2372pid_t __libc_fork(void);
2373pid_t __fork(void)
2374{
2375 pid_t pid;
2376 __my_pthread_testcancel();
2377 __pthread_mutex_lock(&pthread_atfork_lock);
2378
2379 run_fork_handlers(0 /* prepare */);
2380 pid = __libc_fork();
2381 if (pid == 0) {
2382 /* I am the child */
2383 run_fork_handlers(2 /* child */);
sewardjd8acdf22002-11-13 21:57:52 +00002384 __pthread_mutex_unlock(&pthread_atfork_lock);
sewardj2cb00342002-06-28 01:46:26 +00002385 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2386 } else {
2387 /* I am the parent */
2388 run_fork_handlers(1 /* parent */);
2389 __pthread_mutex_unlock(&pthread_atfork_lock);
2390 }
2391 return pid;
2392}
2393
2394
njn25e49d8e72002-09-23 09:36:25 +00002395pid_t __vfork(void)
2396{
2397 return __fork();
2398}
sewardj2cb00342002-06-28 01:46:26 +00002399
2400
sewardj08a4c3f2002-04-13 03:45:44 +00002401static
sewardj08a4c3f2002-04-13 03:45:44 +00002402int my_do_syscall1 ( int syscallno, int arg1 )
2403{
2404 int __res;
2405 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2406 : "=a" (__res)
2407 : "0" (syscallno),
2408 "d" (arg1) );
2409 return __res;
2410}
2411
2412static
2413int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00002414 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00002415{
2416 int __res;
2417 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2418 : "=a" (__res)
2419 : "0" (syscallno),
2420 "d" (arg1),
2421 "c" (arg2) );
2422 return __res;
2423}
2424
2425static
sewardjf854f472002-04-21 12:19:41 +00002426int my_do_syscall3 ( int syscallno,
2427 int arg1, int arg2, int arg3 )
2428{
2429 int __res;
2430 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
2431 : "=a" (__res)
2432 : "0" (syscallno),
2433 "S" (arg1),
2434 "c" (arg2),
2435 "d" (arg3) );
2436 return __res;
2437}
2438
sewardjd5bef572002-10-23 21:49:33 +00002439static inline
2440int my_do_syscall5 ( int syscallno,
2441 int arg1, int arg2, int arg3, int arg4, int arg5 )
2442{
2443 int __res;
2444 __asm__ volatile ("int $0x80"
2445 : "=a" (__res)
2446 : "0" (syscallno),
2447 "b" (arg1),
2448 "c" (arg2),
2449 "d" (arg3),
2450 "S" (arg4),
2451 "D" (arg5));
2452 return __res;
2453}
2454
sewardj11f0bb42003-04-26 20:11:15 +00002455
2456WEAK
2457int select ( int n,
2458 fd_set *rfds,
2459 fd_set *wfds,
2460 fd_set *xfds,
2461 struct timeval *timeout )
sewardj08a4c3f2002-04-13 03:45:44 +00002462{
sewardj11f0bb42003-04-26 20:11:15 +00002463 return VGR_(select)(n, rfds, wfds, xfds, timeout);
sewardj08a4c3f2002-04-13 03:45:44 +00002464}
2465
2466
sewardj3b13f0e2002-04-25 20:17:29 +00002467/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002468 Hacky implementation of semaphores.
2469 ------------------------------------------------------------------ */
2470
2471#include <semaphore.h>
2472
2473/* This is a terrible way to do the remapping. Plan is to import an
2474 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002475
2476typedef
2477 struct {
2478 pthread_mutex_t se_mx;
2479 pthread_cond_t se_cv;
2480 int count;
2481 }
2482 vg_sem_t;
2483
2484static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2485
2486static int se_remap_used = 0;
2487static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2488static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2489
2490static vg_sem_t* se_remap ( sem_t* orig )
2491{
2492 int res, i;
2493 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002494 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002495
2496 for (i = 0; i < se_remap_used; i++) {
2497 if (se_remap_orig[i] == orig)
2498 break;
2499 }
2500 if (i == se_remap_used) {
2501 if (se_remap_used == VG_N_SEMAPHORES) {
2502 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002503 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002504 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002505 }
2506 se_remap_used++;
2507 se_remap_orig[i] = orig;
2508 /* printf("allocated semaphore %d\n", i); */
2509 }
2510 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002511 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002512 return &se_remap_new[i];
2513}
2514
2515
2516int sem_init(sem_t *sem, int pshared, unsigned int value)
2517{
2518 int res;
2519 vg_sem_t* vg_sem;
2520 ensure_valgrind("sem_init");
2521 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002522 pthread_error("sem_init: unsupported pshared value");
sewardj25418ae2003-05-09 23:40:34 +00002523 *(__errno_location()) = ENOSYS;
sewardj8f253ff2002-05-19 00:13:34 +00002524 return -1;
2525 }
2526 vg_sem = se_remap(sem);
2527 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002528 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002529 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002530 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002531 vg_sem->count = value;
2532 return 0;
2533}
2534
2535
2536int sem_wait ( sem_t* sem )
2537{
2538 int res;
2539 vg_sem_t* vg_sem;
2540 ensure_valgrind("sem_wait");
2541 vg_sem = se_remap(sem);
2542 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002543 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002544 while (vg_sem->count == 0) {
2545 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002546 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002547 }
2548 vg_sem->count--;
2549 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002550 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002551 return 0;
2552}
2553
2554int sem_post ( sem_t* sem )
2555{
2556 int res;
2557 vg_sem_t* vg_sem;
2558 ensure_valgrind("sem_post");
2559 vg_sem = se_remap(sem);
2560 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002561 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002562 if (vg_sem->count == 0) {
2563 vg_sem->count++;
2564 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002565 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002566 } else {
2567 vg_sem->count++;
2568 }
2569 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002570 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002571 return 0;
2572}
2573
2574
2575int sem_trywait ( sem_t* sem )
2576{
2577 int ret, res;
2578 vg_sem_t* vg_sem;
2579 ensure_valgrind("sem_trywait");
2580 vg_sem = se_remap(sem);
2581 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002582 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002583 if (vg_sem->count > 0) {
2584 vg_sem->count--;
2585 ret = 0;
2586 } else {
2587 ret = -1;
sewardj25418ae2003-05-09 23:40:34 +00002588 *(__errno_location()) = EAGAIN;
sewardj8f253ff2002-05-19 00:13:34 +00002589 }
2590 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002591 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002592 return ret;
2593}
2594
2595
2596int sem_getvalue(sem_t* sem, int * sval)
2597{
2598 vg_sem_t* vg_sem;
2599 ensure_valgrind("sem_trywait");
2600 vg_sem = se_remap(sem);
2601 *sval = vg_sem->count;
2602 return 0;
2603}
2604
2605
2606int sem_destroy(sem_t * sem)
2607{
2608 kludged("sem_destroy");
2609 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2610 return 0;
2611}
2612
sewardj9ad92d92002-10-16 19:45:06 +00002613
2614int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2615{
2616 int res;
2617 vg_sem_t* vg_sem;
2618 ensure_valgrind("sem_timedwait");
2619 vg_sem = se_remap(sem);
2620 res = __pthread_mutex_lock(&vg_sem->se_mx);
2621 my_assert(res == 0);
2622 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
2623 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
2624 }
2625 if ( vg_sem->count > 0 ) {
2626 vg_sem->count--;
2627 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2628 my_assert(res == 0 );
2629 return 0;
2630 } else {
2631 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2632 my_assert(res == 0 );
2633 *(__errno_location()) = ETIMEDOUT;
2634 return -1;
2635 }
2636}
2637
sewardj8f253ff2002-05-19 00:13:34 +00002638
2639/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002640 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002641 ------------------------------------------------------------------ */
2642
sewardj2d8b3f02002-06-01 14:14:19 +00002643typedef
2644 struct {
2645 int initted; /* != 0 --> in use; sanity check only */
2646 int prefer_w; /* != 0 --> prefer writer */
2647 int nwait_r; /* # of waiting readers */
2648 int nwait_w; /* # of waiting writers */
2649 pthread_cond_t cv_r; /* for signalling readers */
2650 pthread_cond_t cv_w; /* for signalling writers */
2651 pthread_mutex_t mx;
2652 int status;
2653 /* allowed range for status: >= -1. -1 means 1 writer currently
2654 active, >= 0 means N readers currently active. */
2655 }
2656 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002657
2658
2659static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2660
2661static int rw_remap_used = 0;
2662static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2663static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2664
sewardj2d8b3f02002-06-01 14:14:19 +00002665
2666static
2667void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2668{
2669 int res = 0;
2670 vg_rwl->initted = 1;
2671 vg_rwl->prefer_w = 1;
2672 vg_rwl->nwait_r = 0;
2673 vg_rwl->nwait_w = 0;
2674 vg_rwl->status = 0;
2675 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2676 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2677 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002678 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002679}
2680
2681
sewardja1ac5cb2002-05-27 13:00:05 +00002682/* Take the address of a LinuxThreads rwlock_t and return the shadow
2683 address of our version. Further, if the LinuxThreads version
2684 appears to have been statically initialised, do the same to the one
2685 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2686 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2687 uninitialised and non-zero meaning initialised.
2688*/
2689static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2690{
2691 int res, i;
2692 vg_rwlock_t* vg_rwl;
2693 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002694 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002695
2696 for (i = 0; i < rw_remap_used; i++) {
2697 if (rw_remap_orig[i] == orig)
2698 break;
2699 }
2700 if (i == rw_remap_used) {
2701 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002702 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002703 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002704 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2705 }
2706 rw_remap_used++;
2707 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002708 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002709 if (0) printf("allocated rwlock %d\n", i);
2710 }
2711 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002712 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002713 vg_rwl = &rw_remap_new[i];
2714
sewardj2d8b3f02002-06-01 14:14:19 +00002715 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002716 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002717 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002718 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002719 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002720 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002721 }
2722
2723 return vg_rwl;
2724}
2725
2726
sewardja1ac5cb2002-05-27 13:00:05 +00002727int pthread_rwlock_init ( pthread_rwlock_t* orig,
2728 const pthread_rwlockattr_t* attr )
2729{
sewardja1ac5cb2002-05-27 13:00:05 +00002730 vg_rwlock_t* rwl;
2731 if (0) printf ("pthread_rwlock_init\n");
2732 /* Force the remapper to initialise the shadow. */
2733 orig->__rw_readers = 0;
2734 /* Install the lock preference; the remapper needs to know it. */
2735 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2736 if (attr)
2737 orig->__rw_kind = attr->__lockkind;
2738 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002739 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002740}
2741
sewardj2d8b3f02002-06-01 14:14:19 +00002742
2743static
2744void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002745{
sewardj2d8b3f02002-06-01 14:14:19 +00002746 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2747 rwl->nwait_r--;
2748 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002749}
2750
sewardj2d8b3f02002-06-01 14:14:19 +00002751
sewardja1ac5cb2002-05-27 13:00:05 +00002752int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2753{
2754 int res;
2755 vg_rwlock_t* rwl;
2756 if (0) printf ("pthread_rwlock_rdlock\n");
2757 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002758 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002759 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002760 if (!rwl->initted) {
2761 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002762 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002763 return EINVAL;
2764 }
2765 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002766 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002767 rwl->nwait_r++;
2768 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2769 while (1) {
2770 if (rwl->status == 0) break;
2771 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002772 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002773 }
2774 pthread_cleanup_pop(0);
2775 rwl->nwait_r--;
2776 }
sewardj2d94c112002-06-03 01:25:54 +00002777 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002778 rwl->status++;
2779 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002780 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002781 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002782}
2783
sewardj2d8b3f02002-06-01 14:14:19 +00002784
sewardja1ac5cb2002-05-27 13:00:05 +00002785int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2786{
2787 int res;
2788 vg_rwlock_t* rwl;
2789 if (0) printf ("pthread_rwlock_tryrdlock\n");
2790 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002791 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002792 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002793 if (!rwl->initted) {
2794 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002795 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002796 return EINVAL;
2797 }
2798 if (rwl->status == -1) {
2799 /* Writer active; we have to give up. */
2800 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002801 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002802 return EBUSY;
2803 }
2804 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002805 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002806 rwl->status++;
2807 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002808 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002809 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002810}
2811
sewardj2d8b3f02002-06-01 14:14:19 +00002812
2813static
2814void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2815{
2816 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2817 rwl->nwait_w--;
2818 pthread_mutex_unlock (&rwl->mx);
2819}
2820
2821
sewardja1ac5cb2002-05-27 13:00:05 +00002822int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2823{
2824 int res;
2825 vg_rwlock_t* rwl;
2826 if (0) printf ("pthread_rwlock_wrlock\n");
2827 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002828 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002829 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002830 if (!rwl->initted) {
2831 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002832 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002833 return EINVAL;
2834 }
2835 if (rwl->status != 0) {
2836 rwl->nwait_w++;
2837 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2838 while (1) {
2839 if (rwl->status == 0) break;
2840 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002841 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002842 }
2843 pthread_cleanup_pop(0);
2844 rwl->nwait_w--;
2845 }
sewardj2d94c112002-06-03 01:25:54 +00002846 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002847 rwl->status = -1;
2848 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002849 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002850 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002851}
2852
sewardj2d8b3f02002-06-01 14:14:19 +00002853
sewardja1ac5cb2002-05-27 13:00:05 +00002854int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2855{
2856 int res;
2857 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002858 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002859 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002860 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002861 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002862 if (!rwl->initted) {
2863 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002864 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002865 return EINVAL;
2866 }
2867 if (rwl->status != 0) {
2868 /* Reader(s) or a writer active; we have to give up. */
2869 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002870 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002871 return EBUSY;
2872 }
2873 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002874 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002875 rwl->status = -1;
2876 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002877 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002878 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002879}
2880
sewardj2d8b3f02002-06-01 14:14:19 +00002881
sewardja1ac5cb2002-05-27 13:00:05 +00002882int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2883{
2884 int res;
2885 vg_rwlock_t* rwl;
2886 if (0) printf ("pthread_rwlock_unlock\n");
2887 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002888 rwl = rw_remap ( orig );
2889 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002890 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002891 if (!rwl->initted) {
2892 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002893 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002894 return EINVAL;
2895 }
2896 if (rwl->status == 0) {
2897 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002898 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002899 return EPERM;
2900 }
sewardj2d94c112002-06-03 01:25:54 +00002901 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002902 if (rwl->status == -1) {
2903 rwl->status = 0;
2904 } else {
sewardj2d94c112002-06-03 01:25:54 +00002905 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002906 rwl->status--;
2907 }
2908
sewardj2d94c112002-06-03 01:25:54 +00002909 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002910
2911 if (rwl->prefer_w) {
2912
2913 /* Favour waiting writers, if any. */
2914 if (rwl->nwait_w > 0) {
2915 /* Writer(s) are waiting. */
2916 if (rwl->status == 0) {
2917 /* We can let a writer in. */
2918 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002919 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002920 } else {
2921 /* There are still readers active. Do nothing; eventually
2922 they will disappear, at which point a writer will be
2923 admitted. */
2924 }
2925 }
2926 else
2927 /* No waiting writers. */
2928 if (rwl->nwait_r > 0) {
2929 /* Let in a waiting reader. */
2930 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002931 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002932 }
2933
2934 } else {
2935
2936 /* Favour waiting readers, if any. */
2937 if (rwl->nwait_r > 0) {
2938 /* Reader(s) are waiting; let one in. */
2939 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002940 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002941 }
2942 else
2943 /* No waiting readers. */
2944 if (rwl->nwait_w > 0 && rwl->status == 0) {
2945 /* We have waiting writers and no active readers; let a
2946 writer in. */
2947 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002948 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002949 }
2950 }
2951
2952 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002953 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002954 return 0;
2955}
2956
2957
2958int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2959{
2960 int res;
2961 vg_rwlock_t* rwl;
2962 if (0) printf ("pthread_rwlock_destroy\n");
2963 rwl = rw_remap ( orig );
2964 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002965 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002966 if (!rwl->initted) {
2967 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002968 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002969 return EINVAL;
2970 }
2971 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2972 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002973 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002974 return EBUSY;
2975 }
2976 rwl->initted = 0;
2977 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002978 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002979 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002980}
2981
2982
sewardj47e4e312002-06-18 09:24:34 +00002983/* Copied directly from LinuxThreads. */
2984int
2985pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
2986{
2987 attr->__lockkind = 0;
2988 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
2989
2990 return 0;
2991}
2992
sewardjfe18eb82002-07-13 12:58:44 +00002993/* Copied directly from LinuxThreads. */
2994int
sewardj5706bfa2002-12-08 23:42:17 +00002995pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
2996{
2997 return 0;
2998}
2999
3000/* Copied directly from LinuxThreads. */
3001int
sewardjfe18eb82002-07-13 12:58:44 +00003002pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
3003{
3004 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
3005 return EINVAL;
3006
3007 /* For now it is not possible to shared a conditional variable. */
3008 if (pshared != PTHREAD_PROCESS_PRIVATE)
3009 return ENOSYS;
3010
3011 attr->__pshared = pshared;
3012
3013 return 0;
3014}
3015
sewardj47e4e312002-06-18 09:24:34 +00003016
sewardja1ac5cb2002-05-27 13:00:05 +00003017/* ---------------------------------------------------------------------
sewardj11f0bb42003-04-26 20:11:15 +00003018 Make SYSV IPC not block everything -- pass to vg_intercept.c.
sewardjd5bef572002-10-23 21:49:33 +00003019 ------------------------------------------------------------------ */
3020
sewardj11f0bb42003-04-26 20:11:15 +00003021WEAK
3022int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
sewardjd5bef572002-10-23 21:49:33 +00003023{
sewardj11f0bb42003-04-26 20:11:15 +00003024 return VGR_(msgsnd)(msgid, msgp, msgsz, msgflg);
sewardjd5bef572002-10-23 21:49:33 +00003025}
3026
sewardj11f0bb42003-04-26 20:11:15 +00003027WEAK
3028int msgrcv(int msqid, void* msgp, size_t msgsz,
3029 long msgtyp, int msgflg )
sewardjd5bef572002-10-23 21:49:33 +00003030{
sewardj11f0bb42003-04-26 20:11:15 +00003031 return VGR_(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg );
sewardjd5bef572002-10-23 21:49:33 +00003032}
3033
sewardj262b5be2003-04-26 21:19:53 +00003034
3035/* ---------------------------------------------------------------------
3036 The glibc sources say that returning -1 in these 3 functions
3037 causes real time signals not to be used.
3038 ------------------------------------------------------------------ */
3039
3040int __libc_current_sigrtmin (void)
3041{
3042 static int moans = N_MOANS;
3043 if (moans-- > 0)
3044 kludged("__libc_current_sigrtmin");
3045 return -1;
3046}
3047
3048int __libc_current_sigrtmax (void)
3049{
3050 static int moans = N_MOANS;
3051 if (moans-- > 0)
3052 kludged("__libc_current_sigrtmax");
3053 return -1;
3054}
3055
3056int __libc_allocate_rtsig (int high)
3057{
3058 static int moans = N_MOANS;
3059 if (moans-- > 0)
3060 kludged("__libc_allocate_rtsig");
3061 return -1;
3062}
3063
3064
sewardjd5bef572002-10-23 21:49:33 +00003065/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00003066 B'stard.
3067 ------------------------------------------------------------------ */
3068
3069# define strong_alias(name, aliasname) \
3070 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
3071
sewardj5905fae2002-04-26 13:25:00 +00003072# define weak_alias(name, aliasname) \
3073 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00003074
sewardj5905fae2002-04-26 13:25:00 +00003075strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
3076strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
3077strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
3078strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
3079 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
sewardjf0995512003-07-06 01:29:49 +00003080 weak_alias(__pthread_mutexattr_setpshared, pthread_mutexattr_setpshared)
sewardj5905fae2002-04-26 13:25:00 +00003081strong_alias(__pthread_mutex_init, pthread_mutex_init)
3082strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
3083strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
3084strong_alias(__pthread_once, pthread_once)
3085strong_alias(__pthread_atfork, pthread_atfork)
3086strong_alias(__pthread_key_create, pthread_key_create)
3087strong_alias(__pthread_getspecific, pthread_getspecific)
3088strong_alias(__pthread_setspecific, pthread_setspecific)
3089
sewardjd529a442002-05-04 19:49:21 +00003090#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00003091strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00003092#endif
3093
sewardj5905fae2002-04-26 13:25:00 +00003094strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00003095strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00003096strong_alias(lseek, __lseek)
3097strong_alias(open, __open)
3098strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00003099strong_alias(read, __read)
3100strong_alias(wait, __wait)
3101strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00003102strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00003103strong_alias(send, __send)
3104
sewardj726c4122002-05-16 23:39:10 +00003105weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00003106weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00003107weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00003108weak_alias(__vfork, vfork)
sewardj7f6456d2002-05-21 00:51:21 +00003109
sewardjf0b06452002-06-04 08:38:04 +00003110weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00003111
3112/*--------------------------------------------------*/
3113
sewardj5905fae2002-04-26 13:25:00 +00003114weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00003115weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00003116weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00003117
sewardja1ac5cb2002-05-27 13:00:05 +00003118weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
3119weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
3120weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
3121weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
3122
sewardj060b04f2002-04-26 21:01:13 +00003123
sewardj3b13f0e2002-04-25 20:17:29 +00003124/* I've no idea what these are, but they get called quite a lot.
3125 Anybody know? */
3126
3127#undef _IO_flockfile
3128void _IO_flockfile ( _IO_FILE * file )
3129{
sewardj853f55d2002-04-26 00:27:53 +00003130 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003131}
sewardj5905fae2002-04-26 13:25:00 +00003132weak_alias(_IO_flockfile, flockfile);
3133
sewardj3b13f0e2002-04-25 20:17:29 +00003134
3135#undef _IO_funlockfile
3136void _IO_funlockfile ( _IO_FILE * file )
3137{
sewardj853f55d2002-04-26 00:27:53 +00003138 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003139}
sewardj5905fae2002-04-26 13:25:00 +00003140weak_alias(_IO_funlockfile, funlockfile);
3141
sewardj3b13f0e2002-04-25 20:17:29 +00003142
sewardjd4f2c712002-04-30 10:20:10 +00003143/* This doesn't seem to be needed to simulate libpthread.so's external
3144 interface, but many people complain about its absence. */
3145
3146strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
3147weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00003148
3149
3150/*--------------------------------------------------------------------*/
3151/*--- end vg_libpthread.c ---*/
3152/*--------------------------------------------------------------------*/