blob: 0d0d2b597f8ccf3c5b9116bbfb653ce65c4e0389 [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
jsgf855d93d2003-10-13 22:26:55 +000077# define strong_alias(name, aliasname) \
78 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
79
80# define weak_alias(name, aliasname) \
81 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
82
83
sewardj705d3cb2002-05-23 13:13:12 +000084/* ---------------------------------------------------------------------
85 Forwardses.
86 ------------------------------------------------------------------ */
87
sewardj11f0bb42003-04-26 20:11:15 +000088#define WEAK __attribute__((weak))
89
sewardjfd7747b2002-12-01 10:25:53 +000090static
91__inline__
92int is_kerror ( int res )
93{
94 if (res >= -4095 && res <= -1)
95 return 1;
96 else
97 return 0;
98}
99
sewardj08c7f012002-10-07 23:56:55 +0000100
101#ifdef GLIBC_2_3
102 /* kludge by JRS (not from glibc) ... */
103 typedef void* __locale_t;
104
105 /* Copied from locale/locale.h in glibc-2.2.93 sources */
106 /* This value can be passed to `uselocale' and may be returned by
107 it. Passing this value to any other function has undefined
108 behavior. */
109# define LC_GLOBAL_LOCALE ((__locale_t) -1L)
110 extern __locale_t __uselocale ( __locale_t );
111#endif
112
sewardj00a66b12002-10-12 16:42:35 +0000113static
114void init_libc_tsd_keys ( void );
115
sewardj705d3cb2002-05-23 13:13:12 +0000116
sewardje663cb92002-04-12 10:26:32 +0000117/* ---------------------------------------------------------------------
118 Helpers. We have to be pretty self-sufficient.
119 ------------------------------------------------------------------ */
120
sewardj436e0582002-04-26 14:31:40 +0000121/* Number of times any given error message is printed. */
122#define N_MOANS 3
123
sewardj45b4b372002-04-16 22:50:32 +0000124/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
125 Returns 0 (none) if not running on Valgrind. */
126static
127int get_pt_trace_level ( void )
128{
129 int res;
130 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
131 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
132 0, 0, 0, 0);
133 return res;
134}
135
sewardje663cb92002-04-12 10:26:32 +0000136static
sewardj2d94c112002-06-03 01:25:54 +0000137void my_exit ( int arg )
sewardje663cb92002-04-12 10:26:32 +0000138{
jsgf855d93d2003-10-13 22:26:55 +0000139 VG_(do_syscall)(__NR_exit, arg);
sewardj08c7f012002-10-07 23:56:55 +0000140 /*NOTREACHED*/
sewardje663cb92002-04-12 10:26:32 +0000141}
142
sewardje0cfe2a2002-11-30 14:04:45 +0000143/* Apparently unused.
sewardj08c7f012002-10-07 23:56:55 +0000144static
145void my_write ( int fd, const void *buf, int count )
146{
jsgf855d93d2003-10-13 22:26:55 +0000147 VG_(do_syscall)(__NR_write, fd, (int)buf, count );
sewardj08c7f012002-10-07 23:56:55 +0000148}
sewardje0cfe2a2002-11-30 14:04:45 +0000149*/
sewardje663cb92002-04-12 10:26:32 +0000150
sewardj68b2dd92002-05-10 21:03:56 +0000151/* We need this guy -- it's in valgrind.so. */
152extern void VG_(startup) ( void );
153
154
155/* Just start up Valgrind if it's not already going. VG_(startup)()
156 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000157static __inline__
sewardje663cb92002-04-12 10:26:32 +0000158void ensure_valgrind ( char* caller )
159{
sewardj68b2dd92002-05-10 21:03:56 +0000160 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000161}
162
sewardjbea1caa2002-05-10 23:20:58 +0000163/* While we're at it ... hook our own startup function into this
164 game. */
165__asm__ (
166 ".section .init\n"
167 "\tcall vgPlain_startup"
168);
169
sewardje663cb92002-04-12 10:26:32 +0000170
171static
sewardj3b5d8862002-04-20 13:53:23 +0000172__attribute__((noreturn))
daywalker3222e0a2003-09-18 01:39:50 +0000173void barf ( const char* str )
sewardje663cb92002-04-12 10:26:32 +0000174{
sewardj69a72a52002-11-03 13:41:41 +0000175 char buf[1000];
daywalker3222e0a2003-09-18 01:39:50 +0000176 strcpy(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000177 strcat(buf, str);
178 strcat(buf, "\n\n");
njn4c791212003-05-02 17:53:54 +0000179 VALGRIND_NON_SIMD_CALL2(VG_(message), Vg_UserMsg, buf);
sewardj2d94c112002-06-03 01:25:54 +0000180 my_exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000181 /* We have to persuade gcc into believing this doesn't return. */
182 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000183}
184
185
sewardj69a72a52002-11-03 13:41:41 +0000186static void cat_n_send ( char* pre, char* msg )
sewardj2a3d28c2002-04-14 13:27:00 +0000187{
sewardj69a72a52002-11-03 13:41:41 +0000188 char buf[1000];
sewardj436e0582002-04-26 14:31:40 +0000189 if (get_pt_trace_level() >= 0) {
sewardj69a72a52002-11-03 13:41:41 +0000190 snprintf(buf, sizeof(buf), "%s%s", pre, msg );
191 buf[sizeof(buf)-1] = '\0';
njn4c791212003-05-02 17:53:54 +0000192 VALGRIND_NON_SIMD_CALL2(VG_(message), Vg_UserMsg, buf);
sewardj45b4b372002-04-16 22:50:32 +0000193 }
sewardj2a3d28c2002-04-14 13:27:00 +0000194}
195
sewardj69a72a52002-11-03 13:41:41 +0000196static void ignored ( char* msg )
197{
198 cat_n_send ( "valgrind's libpthread.so: IGNORED call to: ", msg );
199}
200
201
sewardj30671ff2002-04-21 00:13:57 +0000202static void kludged ( char* msg )
203{
sewardj69a72a52002-11-03 13:41:41 +0000204 cat_n_send ( "valgrind's libpthread.so: KLUDGED call to: ", msg );
sewardj439d45e2002-05-03 20:43:10 +0000205}
206
sewardj69a72a52002-11-03 13:41:41 +0000207
sewardjccef2e62002-05-29 19:26:32 +0000208__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000209void vgPlain_unimp ( char* what )
210{
sewardj69a72a52002-11-03 13:41:41 +0000211 cat_n_send (
212 "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ", what );
sewardj3b13f0e2002-04-25 20:17:29 +0000213 barf("Please report this bug to me at: jseward@acm.org");
214}
215
sewardje663cb92002-04-12 10:26:32 +0000216
sewardj457cc472002-06-03 23:13:47 +0000217static
daywalker3222e0a2003-09-18 01:39:50 +0000218void my_assert_fail ( const Char* expr, const Char* file, Int line, const Char* fn )
sewardj2d94c112002-06-03 01:25:54 +0000219{
sewardj69a72a52002-11-03 13:41:41 +0000220 char buf[1000];
sewardj2d94c112002-06-03 01:25:54 +0000221 static Bool entered = False;
222 if (entered)
223 my_exit(2);
224 entered = True;
sewardj69a72a52002-11-03 13:41:41 +0000225 sprintf(buf, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
226 "valgrind", file, line, fn, expr );
227 cat_n_send ( "", buf );
228 sprintf(buf, "Please report this bug to me at: %s\n\n",
229 VG_EMAIL_ADDR);
230 cat_n_send ( "", buf );
sewardj2d94c112002-06-03 01:25:54 +0000231 my_exit(1);
232}
233
234#define MY__STRING(__str) #__str
235
236#define my_assert(expr) \
237 ((void) ((expr) ? 0 : \
238 (my_assert_fail (MY__STRING(expr), \
239 __FILE__, __LINE__, \
240 __PRETTY_FUNCTION__), 0)))
241
sewardj00a66b12002-10-12 16:42:35 +0000242static
243void my_free ( void* ptr )
244{
245 int res;
246 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
247 VG_USERREQ__FREE, ptr, 0, 0, 0);
248 my_assert(res == 0);
249}
250
251
252static
253void* my_malloc ( int nbytes )
254{
255 void* res;
256 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
257 VG_USERREQ__MALLOC, nbytes, 0, 0, 0);
258 my_assert(res != (void*)0);
259 return res;
260}
261
262
sewardj2d94c112002-06-03 01:25:54 +0000263
sewardje663cb92002-04-12 10:26:32 +0000264/* ---------------------------------------------------------------------
265 Pass pthread_ calls to Valgrind's request mechanism.
266 ------------------------------------------------------------------ */
267
sewardjf8f819e2002-04-17 23:21:37 +0000268#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000269#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000270
sewardja1ac5cb2002-05-27 13:00:05 +0000271
sewardjf8f819e2002-04-17 23:21:37 +0000272/* ---------------------------------------------------
sewardj4dced352002-06-04 22:54:20 +0000273 Ummm ..
274 ------------------------------------------------ */
275
276static
277void pthread_error ( const char* msg )
278{
279 int res;
280 VALGRIND_MAGIC_SEQUENCE(res, 0,
281 VG_USERREQ__PTHREAD_ERROR,
282 msg, 0, 0, 0);
283}
284
285
286/* ---------------------------------------------------
sewardj00a66b12002-10-12 16:42:35 +0000287 Here so it can be inlined without complaint.
288 ------------------------------------------------ */
289
290__inline__
291pthread_t pthread_self(void)
292{
293 int tid;
294 ensure_valgrind("pthread_self");
295 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
296 VG_USERREQ__PTHREAD_GET_THREADID,
297 0, 0, 0, 0);
298 if (tid < 1 || tid >= VG_N_THREADS)
299 barf("pthread_self: invalid ThreadId");
300 return tid;
301}
302
303
304/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000305 THREAD ATTRIBUTES
306 ------------------------------------------------ */
307
sewardj6af4b5d2002-04-16 04:40:49 +0000308int pthread_attr_init(pthread_attr_t *attr)
309{
sewardj7989d0c2002-05-28 11:00:01 +0000310 /* Just initialise the fields which we might look at. */
311 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj111b14c2002-10-20 16:22:57 +0000312 /* Linuxthreads sets this field to the value __getpagesize(), so I
313 guess the following is OK. */
314 attr->__guardsize = VKI_BYTES_PER_PAGE; return 0;
sewardj6af4b5d2002-04-16 04:40:49 +0000315}
316
317int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
318{
sewardj7989d0c2002-05-28 11:00:01 +0000319 if (detachstate != PTHREAD_CREATE_JOINABLE
sewardj4dced352002-06-04 22:54:20 +0000320 && detachstate != PTHREAD_CREATE_DETACHED) {
321 pthread_error("pthread_attr_setdetachstate: "
322 "detachstate is invalid");
sewardj7989d0c2002-05-28 11:00:01 +0000323 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000324 }
sewardj7989d0c2002-05-28 11:00:01 +0000325 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000326 return 0;
327}
328
njn25e49d8e72002-09-23 09:36:25 +0000329int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
330{
331 *detachstate = attr->__detachstate;
332 return 0;
333}
334
sewardj30671ff2002-04-21 00:13:57 +0000335int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
336{
sewardj436e0582002-04-26 14:31:40 +0000337 static int moans = N_MOANS;
338 if (moans-- > 0)
339 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000340 return 0;
341}
sewardj6af4b5d2002-04-16 04:40:49 +0000342
sewardj11f0bb42003-04-26 20:11:15 +0000343WEAK
sewardj0286dd52002-05-16 20:51:15 +0000344int pthread_attr_setstacksize (pthread_attr_t *__attr,
345 size_t __stacksize)
346{
sewardja18e2102002-05-18 10:43:22 +0000347 size_t limit;
sewardj3d7c8d62002-06-04 20:59:16 +0000348 char buf[1024];
sewardj0286dd52002-05-16 20:51:15 +0000349 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000350 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
351 - 1000; /* paranoia */
352 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000353 return 0;
sewardj3d7c8d62002-06-04 20:59:16 +0000354 snprintf(buf, sizeof(buf), "pthread_attr_setstacksize: "
355 "requested size %d >= VG_PTHREAD_STACK_SIZE\n "
356 "edit vg_include.h and rebuild.", __stacksize);
357 buf[sizeof(buf)-1] = '\0'; /* Make sure it is zero terminated */
358 barf(buf);
sewardj0286dd52002-05-16 20:51:15 +0000359}
360
361
sewardj30671ff2002-04-21 00:13:57 +0000362/* This is completely bogus. */
363int pthread_attr_getschedparam(const pthread_attr_t *attr,
364 struct sched_param *param)
365{
sewardj436e0582002-04-26 14:31:40 +0000366 static int moans = N_MOANS;
367 if (moans-- > 0)
368 kludged("pthread_attr_getschedparam");
sewardj3e909ce2002-06-03 13:27:15 +0000369# ifdef HAVE_SCHED_PRIORITY
sewardj72d58482002-04-24 02:20:20 +0000370 if (param) param->sched_priority = 0; /* who knows */
371# else
sewardj30671ff2002-04-21 00:13:57 +0000372 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000373# endif
sewardj30671ff2002-04-21 00:13:57 +0000374 return 0;
375}
376
377int pthread_attr_setschedparam(pthread_attr_t *attr,
378 const struct sched_param *param)
379{
sewardj436e0582002-04-26 14:31:40 +0000380 static int moans = N_MOANS;
381 if (moans-- > 0)
382 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000383 return 0;
384}
385
386int pthread_attr_destroy(pthread_attr_t *attr)
387{
sewardj436e0582002-04-26 14:31:40 +0000388 static int moans = N_MOANS;
389 if (moans-- > 0)
390 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000391 return 0;
392}
sewardjf8f819e2002-04-17 23:21:37 +0000393
sewardj0d844232002-06-02 09:29:31 +0000394/* These are no-ops, as with LinuxThreads. */
395int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
396{
397 ensure_valgrind("pthread_attr_setscope");
398 if (scope == PTHREAD_SCOPE_SYSTEM)
399 return 0;
sewardj4dced352002-06-04 22:54:20 +0000400 pthread_error("pthread_attr_setscope: "
401 "invalid or unsupported scope");
sewardj0d844232002-06-02 09:29:31 +0000402 if (scope == PTHREAD_SCOPE_PROCESS)
403 return ENOTSUP;
404 return EINVAL;
405}
406
407int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
408{
409 ensure_valgrind("pthread_attr_setscope");
410 if (scope)
411 *scope = PTHREAD_SCOPE_SYSTEM;
412 return 0;
413}
414
sewardj64039bb2002-06-03 00:58:18 +0000415
416/* Pretty bogus. Avoid if possible. */
417int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
418{
419 int detached;
420 size_t limit;
421 ensure_valgrind("pthread_getattr_np");
422 kludged("pthread_getattr_np");
423 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
424 - 1000; /* paranoia */
425 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
426 attr->__schedpolicy = SCHED_OTHER;
427 attr->__schedparam.sched_priority = 0;
428 attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
429 attr->__scope = PTHREAD_SCOPE_SYSTEM;
430 attr->__guardsize = VKI_BYTES_PER_PAGE;
431 attr->__stackaddr = NULL;
432 attr->__stackaddr_set = 0;
433 attr->__stacksize = limit;
434 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
435 VG_USERREQ__SET_OR_GET_DETACH,
436 2 /* get */, thread, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000437 my_assert(detached == 0 || detached == 1);
sewardj64039bb2002-06-03 00:58:18 +0000438 if (detached)
439 attr->__detachstate = PTHREAD_CREATE_DETACHED;
440 return 0;
441}
442
443
444/* Bogus ... */
sewardj11f0bb42003-04-26 20:11:15 +0000445WEAK
sewardj64039bb2002-06-03 00:58:18 +0000446int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
447 void ** stackaddr )
448{
449 ensure_valgrind("pthread_attr_getstackaddr");
450 kludged("pthread_attr_getstackaddr");
451 if (stackaddr)
452 *stackaddr = NULL;
453 return 0;
454}
455
456/* Not bogus (!) */
sewardj11f0bb42003-04-26 20:11:15 +0000457WEAK
sewardj64039bb2002-06-03 00:58:18 +0000458int pthread_attr_getstacksize ( const pthread_attr_t * _attr,
459 size_t * __stacksize )
460{
461 size_t limit;
462 ensure_valgrind("pthread_attr_getstacksize");
463 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
464 - 1000; /* paranoia */
465 if (__stacksize)
466 *__stacksize = limit;
467 return 0;
468}
469
sewardja3be12f2002-06-17 12:19:44 +0000470int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
471{
472 if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
473 return EINVAL;
474 attr->__schedpolicy = policy;
475 return 0;
476}
477
478int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
479{
480 *policy = attr->__schedpolicy;
481 return 0;
482}
483
484
sewardj111b14c2002-10-20 16:22:57 +0000485/* This is completely bogus. We reject all attempts to change it from
486 VKI_BYTES_PER_PAGE. I don't have a clue what it's for so it seems
487 safest to be paranoid. */
sewardj11f0bb42003-04-26 20:11:15 +0000488WEAK
sewardj111b14c2002-10-20 16:22:57 +0000489int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
490{
491 static int moans = N_MOANS;
492
493 if (guardsize == VKI_BYTES_PER_PAGE)
494 return 0;
495
496 if (moans-- > 0)
497 ignored("pthread_attr_setguardsize: ignoring guardsize != 4096");
498
499 return 0;
500}
501
502/* A straight copy of the LinuxThreads code. */
sewardj11f0bb42003-04-26 20:11:15 +0000503WEAK
sewardj111b14c2002-10-20 16:22:57 +0000504int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
505{
506 *guardsize = attr->__guardsize;
507 return 0;
508}
509
sewardjab2e1232002-12-26 12:16:11 +0000510/* Again, like LinuxThreads. */
511
512static int concurrency_current_level = 0;
513
sewardj11f0bb42003-04-26 20:11:15 +0000514WEAK
sewardjb34e4db2002-12-08 23:51:32 +0000515int pthread_setconcurrency(int new_level)
516{
517 if (new_level < 0)
518 return EINVAL;
sewardjab2e1232002-12-26 12:16:11 +0000519 else {
520 concurrency_current_level = new_level;
sewardjb34e4db2002-12-08 23:51:32 +0000521 return 0;
sewardjab2e1232002-12-26 12:16:11 +0000522 }
sewardjb34e4db2002-12-08 23:51:32 +0000523}
524
sewardj11f0bb42003-04-26 20:11:15 +0000525WEAK
sewardjab2e1232002-12-26 12:16:11 +0000526int pthread_getconcurrency(void)
527{
528 return concurrency_current_level;
529}
530
531
sewardj111b14c2002-10-20 16:22:57 +0000532
sewardj20917d82002-05-28 01:36:45 +0000533/* ---------------------------------------------------
534 Helper functions for running a thread
535 and for clearing up afterwards.
536 ------------------------------------------------ */
537
538/* All exiting threads eventually pass through here, bearing the
539 return value, or PTHREAD_CANCELED, in ret_val. */
540static
541__attribute__((noreturn))
542void thread_exit_wrapper ( void* ret_val )
543{
sewardj870497a2002-05-29 01:06:47 +0000544 int detached, res;
545 CleanupEntry cu;
546 pthread_key_t key;
sewardj00a66b12002-10-12 16:42:35 +0000547 void** specifics_ptr;
sewardj870497a2002-05-29 01:06:47 +0000548
sewardj20917d82002-05-28 01:36:45 +0000549 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000550 while (1) {
551 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
552 VG_USERREQ__CLEANUP_POP,
553 &cu, 0, 0, 0);
554 if (res == -1) break; /* stack empty */
sewardj2d94c112002-06-03 01:25:54 +0000555 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000556 if (0) printf("running exit cleanup handler");
557 cu.fn ( cu.arg );
558 }
559
sewardj870497a2002-05-29 01:06:47 +0000560 /* Run this thread's key finalizers. Really this should be run
561 PTHREAD_DESTRUCTOR_ITERATIONS times. */
562 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
563 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
564 VG_USERREQ__GET_KEY_D_AND_S,
565 key, &cu, 0, 0 );
566 if (res == 0) {
567 /* valid key */
568 if (cu.fn && cu.arg)
569 cu.fn /* destructor for key */
570 ( cu.arg /* specific for key for this thread */ );
571 continue;
572 }
sewardj2d94c112002-06-03 01:25:54 +0000573 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000574 }
sewardj20917d82002-05-28 01:36:45 +0000575
sewardj00a66b12002-10-12 16:42:35 +0000576 /* Free up my specifics space, if any. */
577 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
578 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
579 pthread_self(), 0, 0, 0);
580 my_assert(specifics_ptr != (void**)3);
581 my_assert(specifics_ptr != (void**)1); /* 1 means invalid thread */
582 if (specifics_ptr != NULL)
583 my_free(specifics_ptr);
584
sewardj20917d82002-05-28 01:36:45 +0000585 /* Decide on my final disposition. */
586 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
587 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000588 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000589 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000590
591 if (detached) {
592 /* Detached; I just quit right now. */
593 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
594 VG_USERREQ__QUIT, 0, 0, 0, 0);
595 } else {
596 /* Not detached; so I wait for a joiner. */
597 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
598 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
599 }
600 /* NOTREACHED */
601 barf("thread_exit_wrapper: still alive?!");
602}
603
604
605/* This function is a wrapper function for running a thread. It runs
606 the root function specified in pthread_create, and then, should the
607 root function return a value, it arranges to run the thread's
608 cleanup handlers and exit correctly. */
609
sewardj728a5272002-06-20 10:25:37 +0000610/* Struct used to convey info from pthread_create to thread_wrapper.
611 Must be careful not to pass to the child thread any pointers to
612 objects which might be on the parent's stack. */
sewardj20917d82002-05-28 01:36:45 +0000613typedef
614 struct {
sewardj728a5272002-06-20 10:25:37 +0000615 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000616 void* (*root_fn) ( void* );
617 void* arg;
618 }
619 NewThreadInfo;
620
621
622/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
623 not return. Note that this runs in the new thread, not the
624 parent. */
625static
626__attribute__((noreturn))
627void thread_wrapper ( NewThreadInfo* info )
628{
sewardj728a5272002-06-20 10:25:37 +0000629 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000630 void* (*root_fn) ( void* );
631 void* arg;
632 void* ret_val;
633
sewardj728a5272002-06-20 10:25:37 +0000634 attr__detachstate = info->attr__detachstate;
635 root_fn = info->root_fn;
636 arg = info->arg;
sewardj20917d82002-05-28 01:36:45 +0000637
sewardj20917d82002-05-28 01:36:45 +0000638 /* Free up the arg block that pthread_create malloced. */
sewardj00a66b12002-10-12 16:42:35 +0000639 my_free(info);
sewardj20917d82002-05-28 01:36:45 +0000640
sewardj7989d0c2002-05-28 11:00:01 +0000641 /* Minimally observe the attributes supplied. */
sewardj728a5272002-06-20 10:25:37 +0000642 if (attr__detachstate != PTHREAD_CREATE_DETACHED
643 && attr__detachstate != PTHREAD_CREATE_JOINABLE)
644 pthread_error("thread_wrapper: invalid attr->__detachstate");
645 if (attr__detachstate == PTHREAD_CREATE_DETACHED)
646 pthread_detach(pthread_self());
sewardj7989d0c2002-05-28 11:00:01 +0000647
sewardj00a66b12002-10-12 16:42:35 +0000648# ifdef GLIBC_2_3
649 /* Set this thread's locale to the global (default) locale. A hack
650 in support of glibc-2.3. This does the biz for the all new
651 threads; the root thread is done with a horrible hack in
652 init_libc_tsd_keys() below.
653 */
654 __uselocale(LC_GLOBAL_LOCALE);
655# endif
656
sewardj20917d82002-05-28 01:36:45 +0000657 /* The root function might not return. But if it does we simply
658 move along to thread_exit_wrapper. All other ways out for the
659 thread (cancellation, or calling pthread_exit) lead there
660 too. */
661 ret_val = root_fn(arg);
662 thread_exit_wrapper(ret_val);
663 /* NOTREACHED */
664}
665
666
sewardjf8f819e2002-04-17 23:21:37 +0000667/* ---------------------------------------------------
668 THREADs
669 ------------------------------------------------ */
670
sewardjc91a4ff2003-07-11 00:12:58 +0000671static void __valgrind_pthread_yield ( void )
sewardjff42d1d2002-05-22 13:17:31 +0000672{
673 int res;
674 ensure_valgrind("pthread_yield");
675 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
676 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
sewardjc91a4ff2003-07-11 00:12:58 +0000677}
678
679WEAK
680int pthread_yield ( void )
681{
682 __valgrind_pthread_yield();
sewardjff42d1d2002-05-22 13:17:31 +0000683 return 0;
684}
685
686
sewardj6072c362002-04-19 14:40:57 +0000687int pthread_equal(pthread_t thread1, pthread_t thread2)
688{
689 return thread1 == thread2 ? 1 : 0;
690}
691
692
sewardj20917d82002-05-28 01:36:45 +0000693/* Bundle up the args into a malloc'd block and create a new thread
694 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000695int
sewardj1462c8b2002-07-24 09:41:52 +0000696pthread_create (pthread_t *__restrict __thredd,
sewardje663cb92002-04-12 10:26:32 +0000697 __const pthread_attr_t *__restrict __attr,
698 void *(*__start_routine) (void *),
699 void *__restrict __arg)
700{
sewardj20917d82002-05-28 01:36:45 +0000701 int tid_child;
702 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000703
sewardj20917d82002-05-28 01:36:45 +0000704 ensure_valgrind("pthread_create");
705
sewardj00a66b12002-10-12 16:42:35 +0000706 /* make sure the tsd keys, and hence locale info, are initialised
707 before we get into complications making new threads. */
708 init_libc_tsd_keys();
709
sewardj20917d82002-05-28 01:36:45 +0000710 /* Allocate space for the arg block. thread_wrapper will free
711 it. */
sewardj00a66b12002-10-12 16:42:35 +0000712 info = my_malloc(sizeof(NewThreadInfo));
sewardj2d94c112002-06-03 01:25:54 +0000713 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000714
sewardj728a5272002-06-20 10:25:37 +0000715 if (__attr)
716 info->attr__detachstate = __attr->__detachstate;
717 else
718 info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
719
sewardj20917d82002-05-28 01:36:45 +0000720 info->root_fn = __start_routine;
721 info->arg = __arg;
722 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
723 VG_USERREQ__APPLY_IN_NEW_THREAD,
724 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000725 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000726
sewardj1462c8b2002-07-24 09:41:52 +0000727 if (__thredd)
728 *__thredd = tid_child;
sewardj20917d82002-05-28 01:36:45 +0000729 return 0; /* success */
730}
sewardje663cb92002-04-12 10:26:32 +0000731
732
733int
734pthread_join (pthread_t __th, void **__thread_return)
735{
736 int res;
737 ensure_valgrind("pthread_join");
738 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
739 VG_USERREQ__PTHREAD_JOIN,
740 __th, __thread_return, 0, 0);
741 return res;
742}
743
744
sewardj3b5d8862002-04-20 13:53:23 +0000745void pthread_exit(void *retval)
746{
sewardj3b5d8862002-04-20 13:53:23 +0000747 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000748 /* Simple! */
749 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000750}
751
sewardje663cb92002-04-12 10:26:32 +0000752
sewardj853f55d2002-04-26 00:27:53 +0000753int pthread_detach(pthread_t th)
754{
sewardj20917d82002-05-28 01:36:45 +0000755 int res;
756 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000757 /* First we enquire as to the current detach state. */
758 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000759 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000760 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000761 if (res == -1) {
762 /* not found */
763 pthread_error("pthread_detach: "
764 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000765 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000766 }
767 if (res == 1) {
768 /* already detached */
769 pthread_error("pthread_detach: "
770 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000771 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000772 }
sewardj7989d0c2002-05-28 11:00:01 +0000773 if (res == 0) {
774 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
775 VG_USERREQ__SET_OR_GET_DETACH,
776 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000777 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000778 return 0;
779 }
780 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000781}
782
783
sewardjf8f819e2002-04-17 23:21:37 +0000784/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000785 CLEANUP STACKS
786 ------------------------------------------------ */
787
788void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
789 void (*__routine) (void *),
790 void *__arg)
791{
792 int res;
793 CleanupEntry cu;
794 ensure_valgrind("_pthread_cleanup_push");
795 cu.fn = __routine;
796 cu.arg = __arg;
797 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
798 VG_USERREQ__CLEANUP_PUSH,
799 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000800 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000801}
802
803
804void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
805 void (*__routine) (void *),
806 void *__arg)
807{
808 /* As _pthread_cleanup_push, but first save the thread's original
809 cancellation type in __buffer and set it to Deferred. */
810 int orig_ctype;
811 ensure_valgrind("_pthread_cleanup_push_defer");
812 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000813 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
814 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
815 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000816 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
817 VG_USERREQ__SET_CANCELTYPE,
818 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000819 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000820 *((int*)(__buffer)) = orig_ctype;
821 /* Now push the cleanup. */
822 _pthread_cleanup_push(NULL, __routine, __arg);
823}
824
825
826void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
827 int __execute)
828{
829 int res;
830 CleanupEntry cu;
831 ensure_valgrind("_pthread_cleanup_push");
832 cu.fn = cu.arg = NULL; /* paranoia */
833 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
834 VG_USERREQ__CLEANUP_POP,
835 &cu, 0, 0, 0);
836 if (res == 0) {
837 /* pop succeeded */
838 if (__execute) {
839 cu.fn ( cu.arg );
840 }
841 return;
842 }
843 if (res == -1) {
844 /* stack underflow */
845 return;
846 }
847 barf("_pthread_cleanup_pop");
848}
849
850
851void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
852 int __execute)
853{
854 int orig_ctype, fake_ctype;
855 /* As _pthread_cleanup_pop, but after popping/running the handler,
856 restore the thread's original cancellation type from the first
857 word of __buffer. */
858 _pthread_cleanup_pop(NULL, __execute);
859 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000860 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000861 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000862 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
863 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
864 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000865 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
866 VG_USERREQ__SET_CANCELTYPE,
867 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000868 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000869}
870
871
872/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000873 MUTEX ATTRIBUTES
874 ------------------------------------------------ */
875
sewardj5905fae2002-04-26 13:25:00 +0000876int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000877{
sewardjf8f819e2002-04-17 23:21:37 +0000878 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000879 return 0;
sewardje663cb92002-04-12 10:26:32 +0000880}
881
sewardj5905fae2002-04-26 13:25:00 +0000882int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000883{
884 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000885# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000886 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000887 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000888# endif
sewardja1679dd2002-05-10 22:31:40 +0000889# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000890 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000891# endif
sewardjf8f819e2002-04-17 23:21:37 +0000892 case PTHREAD_MUTEX_RECURSIVE_NP:
893 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000894 attr->__mutexkind = type;
895 return 0;
896 default:
sewardj4dced352002-06-04 22:54:20 +0000897 pthread_error("pthread_mutexattr_settype: "
898 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000899 return EINVAL;
900 }
901}
902
sewardj5905fae2002-04-26 13:25:00 +0000903int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000904{
905 return 0;
906}
907
sewardjf0995512003-07-06 01:29:49 +0000908int __pthread_mutexattr_setpshared ( pthread_mutexattr_t* attr, int pshared)
sewardj7685cae2003-07-06 01:23:11 +0000909{
910 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
911 return EINVAL;
912
913 /* For now it is not possible to shared a conditional variable. */
914 if (pshared != PTHREAD_PROCESS_PRIVATE)
915 return ENOSYS;
916
917 return 0;
918}
919
sewardjf8f819e2002-04-17 23:21:37 +0000920
921/* ---------------------------------------------------
922 MUTEXes
923 ------------------------------------------------ */
924
sewardj5905fae2002-04-26 13:25:00 +0000925int __pthread_mutex_init(pthread_mutex_t *mutex,
926 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000927{
sewardj604ec3c2002-04-18 22:38:41 +0000928 mutex->__m_count = 0;
929 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
930 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
931 if (mutexattr)
932 mutex->__m_kind = mutexattr->__mutexkind;
933 return 0;
sewardje663cb92002-04-12 10:26:32 +0000934}
935
sewardj439d45e2002-05-03 20:43:10 +0000936
sewardj5905fae2002-04-26 13:25:00 +0000937int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000938{
939 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000940
sewardj439d45e2002-05-03 20:43:10 +0000941 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000942 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
943 VG_USERREQ__PTHREAD_MUTEX_LOCK,
944 mutex, 0, 0, 0);
945 return res;
sewardj439d45e2002-05-03 20:43:10 +0000946 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000947 /* Play at locking */
948 if (0)
949 kludged("prehistoric lock");
950 mutex->__m_owner = (_pthread_descr)1;
951 mutex->__m_count = 1;
952 mutex->__m_kind |= VG_PTHREAD_PREHISTORY;
sewardj439d45e2002-05-03 20:43:10 +0000953 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000954 }
955}
956
sewardj439d45e2002-05-03 20:43:10 +0000957
sewardj5905fae2002-04-26 13:25:00 +0000958int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000959{
960 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000961
sewardj439d45e2002-05-03 20:43:10 +0000962 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000963 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
964 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
965 mutex, 0, 0, 0);
966 return res;
sewardj439d45e2002-05-03 20:43:10 +0000967 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000968 /* Play at locking */
969 if (0)
970 kludged("prehistoric trylock");
971 mutex->__m_owner = (_pthread_descr)1;
972 mutex->__m_count = 1;
973 mutex->__m_kind |= VG_PTHREAD_PREHISTORY;
974 return 0; /* success */
sewardj30671ff2002-04-21 00:13:57 +0000975 }
976}
977
sewardj439d45e2002-05-03 20:43:10 +0000978
sewardj5905fae2002-04-26 13:25:00 +0000979int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000980{
981 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000982
sewardj439d45e2002-05-03 20:43:10 +0000983 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000984 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
985 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
986 mutex, 0, 0, 0);
987 return res;
sewardj439d45e2002-05-03 20:43:10 +0000988 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000989 /* Play at locking */
990 if (0)
991 kludged("prehistoric unlock");
992 mutex->__m_owner = 0;
993 mutex->__m_count = 0;
994 mutex->__m_kind &= ~VG_PTHREAD_PREHISTORY;
995 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000996 }
997}
998
sewardj439d45e2002-05-03 20:43:10 +0000999
sewardj5905fae2002-04-26 13:25:00 +00001000int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +00001001{
sewardj604ec3c2002-04-18 22:38:41 +00001002 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
1003 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +00001004 if (mutex->__m_count > 0) {
sewardjd8acdf22002-11-13 21:57:52 +00001005 /* Oh, the horror. glibc's internal use of pthreads "knows"
1006 that destroying a lock does an implicit unlock. Make it
1007 explicit. */
1008 __pthread_mutex_unlock(mutex);
1009 pthread_error("pthread_mutex_destroy: "
1010 "mutex is still in use");
1011 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +00001012 }
1013 mutex->__m_count = 0;
1014 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
1015 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
1016 return 0;
sewardje663cb92002-04-12 10:26:32 +00001017}
1018
1019
sewardjf8f819e2002-04-17 23:21:37 +00001020/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +00001021 CONDITION VARIABLES
1022 ------------------------------------------------ */
1023
1024/* LinuxThreads supports no attributes for conditions. Hence ... */
1025
1026int pthread_condattr_init(pthread_condattr_t *attr)
1027{
1028 return 0;
1029}
1030
sewardj0738a592002-04-20 13:59:33 +00001031int pthread_condattr_destroy(pthread_condattr_t *attr)
1032{
1033 return 0;
1034}
sewardj6072c362002-04-19 14:40:57 +00001035
1036int pthread_cond_init( pthread_cond_t *cond,
1037 const pthread_condattr_t *cond_attr)
1038{
1039 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
1040 return 0;
1041}
1042
sewardjf854f472002-04-21 12:19:41 +00001043int pthread_cond_destroy(pthread_cond_t *cond)
1044{
1045 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +00001046 static int moans = N_MOANS;
1047 if (moans-- > 0)
1048 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +00001049 return 0;
1050}
sewardj6072c362002-04-19 14:40:57 +00001051
1052/* ---------------------------------------------------
1053 SCHEDULING
1054 ------------------------------------------------ */
1055
1056/* This is completely bogus. */
1057int pthread_getschedparam(pthread_t target_thread,
1058 int *policy,
1059 struct sched_param *param)
1060{
sewardj436e0582002-04-26 14:31:40 +00001061 static int moans = N_MOANS;
1062 if (moans-- > 0)
1063 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +00001064 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +00001065# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +00001066 if (param) param->sched_priority = 0; /* who knows */
1067# else
sewardj6072c362002-04-19 14:40:57 +00001068 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +00001069# endif
sewardj6072c362002-04-19 14:40:57 +00001070 return 0;
1071}
1072
1073int pthread_setschedparam(pthread_t target_thread,
1074 int policy,
1075 const struct sched_param *param)
1076{
sewardj436e0582002-04-26 14:31:40 +00001077 static int moans = N_MOANS;
1078 if (moans-- > 0)
1079 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +00001080 return 0;
1081}
1082
sewardj3b5d8862002-04-20 13:53:23 +00001083int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
1084{
1085 int res;
1086 ensure_valgrind("pthread_cond_wait");
1087 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1088 VG_USERREQ__PTHREAD_COND_WAIT,
1089 cond, mutex, 0, 0);
1090 return res;
1091}
1092
sewardj5f07b662002-04-23 16:52:51 +00001093int pthread_cond_timedwait ( pthread_cond_t *cond,
1094 pthread_mutex_t *mutex,
1095 const struct timespec *abstime )
1096{
1097 int res;
1098 unsigned int ms_now, ms_end;
1099 struct timeval timeval_now;
1100 unsigned long long int ull_ms_now_after_1970;
1101 unsigned long long int ull_ms_end_after_1970;
1102
1103 ensure_valgrind("pthread_cond_timedwait");
1104 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1105 VG_USERREQ__READ_MILLISECOND_TIMER,
1106 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001107 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001108 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +00001109 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001110
1111 ull_ms_now_after_1970
1112 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
1113 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
1114 ull_ms_end_after_1970
1115 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
1116 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +00001117 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
1118 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +00001119 ms_end
1120 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
1121 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1122 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
1123 cond, mutex, ms_end, 0);
1124 return res;
1125}
1126
1127
sewardj3b5d8862002-04-20 13:53:23 +00001128int pthread_cond_signal(pthread_cond_t *cond)
1129{
1130 int res;
1131 ensure_valgrind("pthread_cond_signal");
1132 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1133 VG_USERREQ__PTHREAD_COND_SIGNAL,
1134 cond, 0, 0, 0);
1135 return res;
1136}
1137
1138int pthread_cond_broadcast(pthread_cond_t *cond)
1139{
1140 int res;
1141 ensure_valgrind("pthread_cond_broadcast");
1142 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1143 VG_USERREQ__PTHREAD_COND_BROADCAST,
1144 cond, 0, 0, 0);
1145 return res;
1146}
1147
sewardj6072c362002-04-19 14:40:57 +00001148
1149/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001150 CANCELLATION
1151 ------------------------------------------------ */
1152
sewardj853f55d2002-04-26 00:27:53 +00001153int pthread_setcancelstate(int state, int *oldstate)
1154{
sewardj20917d82002-05-28 01:36:45 +00001155 int res;
1156 ensure_valgrind("pthread_setcancelstate");
1157 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +00001158 && state != PTHREAD_CANCEL_DISABLE) {
1159 pthread_error("pthread_setcancelstate: "
1160 "invalid state");
sewardj20917d82002-05-28 01:36:45 +00001161 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001162 }
sewardj2d94c112002-06-03 01:25:54 +00001163 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1164 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001165 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1166 VG_USERREQ__SET_CANCELSTATE,
1167 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001168 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001169 if (oldstate)
1170 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001171 return 0;
1172}
1173
sewardje663cb92002-04-12 10:26:32 +00001174int pthread_setcanceltype(int type, int *oldtype)
1175{
sewardj20917d82002-05-28 01:36:45 +00001176 int res;
1177 ensure_valgrind("pthread_setcanceltype");
1178 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001179 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1180 pthread_error("pthread_setcanceltype: "
1181 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001182 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001183 }
sewardj2d94c112002-06-03 01:25:54 +00001184 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1185 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001186 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1187 VG_USERREQ__SET_CANCELTYPE,
1188 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001189 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001190 if (oldtype)
1191 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001192 return 0;
1193}
1194
sewardje663cb92002-04-12 10:26:32 +00001195int pthread_cancel(pthread_t thread)
1196{
1197 int res;
1198 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001199 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1200 VG_USERREQ__SET_CANCELPEND,
1201 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001202 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001203 return res;
1204}
1205
jsgf855d93d2003-10-13 22:26:55 +00001206static
sewardjd140e442002-05-29 01:21:19 +00001207void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001208{
sewardj20917d82002-05-28 01:36:45 +00001209 int res;
njn25e49d8e72002-09-23 09:36:25 +00001210 ensure_valgrind("__my_pthread_testcancel");
sewardj20917d82002-05-28 01:36:45 +00001211 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1212 VG_USERREQ__TESTCANCEL,
1213 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001214 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001215}
1216
sewardjd140e442002-05-29 01:21:19 +00001217void pthread_testcancel ( void )
1218{
1219 __my_pthread_testcancel();
1220}
1221
sewardj20917d82002-05-28 01:36:45 +00001222
sewardjef037c72002-05-30 00:40:03 +00001223/* Not really sure what this is for. I suspect for doing the POSIX
1224 requirements for fork() and exec(). We do this internally anyway
1225 whenever those syscalls are observed, so this could be superfluous,
1226 but hey ...
1227*/
sewardj853f55d2002-04-26 00:27:53 +00001228void __pthread_kill_other_threads_np ( void )
1229{
sewardjef037c72002-05-30 00:40:03 +00001230 int res;
1231 ensure_valgrind("__pthread_kill_other_threads_np");
1232 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1233 VG_USERREQ__NUKE_OTHER_THREADS,
1234 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001235 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001236}
1237
sewardje663cb92002-04-12 10:26:32 +00001238
sewardjf8f819e2002-04-17 23:21:37 +00001239/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001240 SIGNALS
1241 ------------------------------------------------ */
1242
1243#include <signal.h>
1244
1245int pthread_sigmask(int how, const sigset_t *newmask,
1246 sigset_t *oldmask)
1247{
1248 int res;
1249
1250 /* A bit subtle, because the scheduler expects newmask and oldmask
1251 to be vki_sigset_t* rather than sigset_t*, and the two are
1252 different. Fortunately the first 64 bits of a sigset_t are
1253 exactly a vki_sigset_t, so we just pass the pointers through
1254 unmodified. Haaaack!
1255
1256 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001257 constants to VKI_ constants, so that the former do not have to
1258 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001259
1260 ensure_valgrind("pthread_sigmask");
1261
1262 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001263 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1264 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1265 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001266 default: pthread_error("pthread_sigmask: invalid how");
1267 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001268 }
1269
sewardjb48e5002002-05-13 00:16:03 +00001270 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1271 VG_USERREQ__PTHREAD_SIGMASK,
1272 how, newmask, oldmask, 0);
1273
1274 /* The scheduler tells us of any memory violations. */
1275 return res == 0 ? 0 : EFAULT;
1276}
1277
sewardjb48e5002002-05-13 00:16:03 +00001278int sigwait ( const sigset_t* set, int* sig )
1279{
1280 int res;
jsgf855d93d2003-10-13 22:26:55 +00001281 vki_ksiginfo_t si;
1282
1283 __my_pthread_testcancel();
1284
sewardjb48e5002002-05-13 00:16:03 +00001285 /* As with pthread_sigmask we deliberately confuse sigset_t with
1286 vki_ksigset_t. */
jsgf855d93d2003-10-13 22:26:55 +00001287 si.si_signo = 0;
1288 res = VG_(ksigtimedwait)((const vki_ksigset_t *)set, &si, NULL);
1289 *sig = si.si_signo;
1290
1291 return 0; /* always returns 0 */
sewardjb48e5002002-05-13 00:16:03 +00001292}
1293
1294
sewardj018f7622002-05-15 21:13:39 +00001295int pthread_kill(pthread_t thread, int signo)
1296{
1297 int res;
1298 ensure_valgrind("pthread_kill");
1299 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1300 VG_USERREQ__PTHREAD_KILL,
1301 thread, signo, 0, 0);
1302 return res;
1303}
1304
1305
sewardj3665ded2002-05-16 16:57:25 +00001306/* Copied verbatim from Linuxthreads */
1307/* Redefine raise() to send signal to calling thread only,
1308 as per POSIX 1003.1c */
1309int raise (int sig)
1310{
1311 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001312 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001313 return 0;
sewardj4dced352002-06-04 22:54:20 +00001314 } else {
sewardj25418ae2003-05-09 23:40:34 +00001315 *(__errno_location()) = retcode;
sewardj3665ded2002-05-16 16:57:25 +00001316 return -1;
1317 }
1318}
1319
1320
sewardj9a2224b2002-06-19 10:17:40 +00001321
sewardjb48e5002002-05-13 00:16:03 +00001322/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001323 THREAD-SPECIFICs
1324 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001325
sewardj00a66b12002-10-12 16:42:35 +00001326static
1327int key_is_valid (pthread_key_t key)
1328{
1329 int res;
1330 VALGRIND_MAGIC_SEQUENCE(res, 2 /* default */,
1331 VG_USERREQ__PTHREAD_KEY_VALIDATE,
1332 key, 0, 0, 0);
1333 my_assert(res != 2);
1334 return res;
1335}
1336
1337
1338/* Returns NULL if thread is invalid. Otherwise, if the thread
1339 already has a specifics area, return that. Otherwise allocate it
1340 one. */
1341static
1342void** get_or_allocate_specifics_ptr ( pthread_t thread )
1343{
1344 int res, i;
1345 void** specifics_ptr;
1346 ensure_valgrind("get_or_allocate_specifics_ptr");
1347
1348 /* Returns zero if the thread has no specific_ptr. One if thread
1349 is invalid. Otherwise, the specific_ptr value. This is
1350 allocated with my_malloc and so is aligned and cannot be
1351 confused with 1 or 3. */
1352 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
1353 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
1354 thread, 0, 0, 0);
1355 my_assert(specifics_ptr != (void**)3);
1356
1357 if (specifics_ptr == (void**)1)
1358 return NULL; /* invalid thread */
1359
1360 if (specifics_ptr != NULL)
1361 return specifics_ptr; /* already has a specifics ptr. */
1362
1363 /* None yet ... allocate a new one. Should never fail. */
1364 specifics_ptr = my_malloc( VG_N_THREAD_KEYS * sizeof(void*) );
1365 my_assert(specifics_ptr != NULL);
1366
1367 VALGRIND_MAGIC_SEQUENCE(res, -1 /* default */,
1368 VG_USERREQ__PTHREAD_SETSPECIFIC_PTR,
1369 specifics_ptr, 0, 0, 0);
1370 my_assert(res == 0);
1371
1372 /* POSIX sez: "Upon thread creation, the value NULL shall be
1373 associated with all defined keys in the new thread." This
1374 allocation is in effect a delayed allocation of the specific
1375 data for a thread, at its first-use. Hence we initialise it
1376 here. */
1377 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
1378 specifics_ptr[i] = NULL;
1379 }
1380
1381 return specifics_ptr;
1382}
1383
1384
sewardj5905fae2002-04-26 13:25:00 +00001385int __pthread_key_create(pthread_key_t *key,
1386 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001387{
sewardj00a66b12002-10-12 16:42:35 +00001388 void** specifics_ptr;
1389 int res, i;
sewardj5f07b662002-04-23 16:52:51 +00001390 ensure_valgrind("pthread_key_create");
sewardj00a66b12002-10-12 16:42:35 +00001391
1392 /* This writes *key if successful. It should never fail. */
1393 VALGRIND_MAGIC_SEQUENCE(res, 1 /* default */,
sewardj5f07b662002-04-23 16:52:51 +00001394 VG_USERREQ__PTHREAD_KEY_CREATE,
1395 key, destr_function, 0, 0);
jsgf855d93d2003-10-13 22:26:55 +00001396
1397 if (res == 0) {
1398 /* POSIX sez: "Upon key creation, the value NULL shall be
1399 associated with the new key in all active threads." */
1400 for (i = 0; i < VG_N_THREADS; i++) {
1401 specifics_ptr = get_or_allocate_specifics_ptr(i);
1402 /* we get NULL if i is an invalid thread. */
1403 if (specifics_ptr != NULL)
1404 specifics_ptr[*key] = NULL;
1405 }
sewardj00a66b12002-10-12 16:42:35 +00001406 }
1407
sewardj5f07b662002-04-23 16:52:51 +00001408 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001409}
1410
1411int pthread_key_delete(pthread_key_t key)
1412{
sewardj00a66b12002-10-12 16:42:35 +00001413 int res;
njndfc9b8c2003-09-29 12:58:37 +00001414 ensure_valgrind("pthread_key_delete");
sewardj00a66b12002-10-12 16:42:35 +00001415 if (!key_is_valid(key))
1416 return EINVAL;
1417 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1418 VG_USERREQ__PTHREAD_KEY_DELETE,
1419 key, 0, 0, 0);
1420 my_assert(res == 0);
sewardj5e5fa512002-04-14 13:13:05 +00001421 return 0;
1422}
1423
sewardj5905fae2002-04-26 13:25:00 +00001424int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001425{
sewardj00a66b12002-10-12 16:42:35 +00001426 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001427 ensure_valgrind("pthread_setspecific");
sewardj00a66b12002-10-12 16:42:35 +00001428
1429 if (!key_is_valid(key))
1430 return EINVAL;
1431
1432 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1433 specifics_ptr[key] = (void*)pointer;
1434 return 0;
sewardj5e5fa512002-04-14 13:13:05 +00001435}
1436
sewardj5905fae2002-04-26 13:25:00 +00001437void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001438{
sewardj00a66b12002-10-12 16:42:35 +00001439 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001440 ensure_valgrind("pthread_getspecific");
sewardj00a66b12002-10-12 16:42:35 +00001441
1442 if (!key_is_valid(key))
1443 return NULL;
1444
1445 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1446 return specifics_ptr[key];
1447}
1448
1449
sewardj9aa918d2002-10-20 16:25:55 +00001450#ifdef GLIBC_2_3
sewardj00a66b12002-10-12 16:42:35 +00001451static
1452void ** __pthread_getspecific_addr(pthread_key_t key)
1453{
1454 void** specifics_ptr;
1455 ensure_valgrind("pthread_getspecific_addr");
1456
1457 if (!key_is_valid(key))
1458 return NULL;
1459
1460 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1461 return &(specifics_ptr[key]);
sewardj5e5fa512002-04-14 13:13:05 +00001462}
sewardj9aa918d2002-10-20 16:25:55 +00001463#endif
sewardjf8f819e2002-04-17 23:21:37 +00001464
sewardjc91a4ff2003-07-11 00:12:58 +00001465
sewardjf8f819e2002-04-17 23:21:37 +00001466/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001467 ONCEry
1468 ------------------------------------------------ */
1469
sewardjc91a4ff2003-07-11 00:12:58 +00001470/* This protects reads and writes of the once_control variable
1471 supplied. It is never held whilst any particular initialiser is
1472 running. */
sewardj89d3d852002-04-24 19:21:39 +00001473static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1474
sewardjc91a4ff2003-07-11 00:12:58 +00001475/* Initialiser needs to be run. */
1476#define P_ONCE_NOT_DONE ((PTHREAD_ONCE_INIT) + 0)
1477
1478/* Initialiser currently running. */
1479#define P_ONCE_RUNNING ((PTHREAD_ONCE_INIT) + 1)
1480
1481/* Initialiser has completed. */
1482#define P_ONCE_COMPLETED ((PTHREAD_ONCE_INIT) + 2)
sewardj89d3d852002-04-24 19:21:39 +00001483
sewardj5905fae2002-04-26 13:25:00 +00001484int __pthread_once ( pthread_once_t *once_control,
1485 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001486{
1487 int res;
sewardjc91a4ff2003-07-11 00:12:58 +00001488 int done;
sewardj89d3d852002-04-24 19:21:39 +00001489
sewardjc91a4ff2003-07-11 00:12:58 +00001490# define TAKE_LOCK \
1491 res = __pthread_mutex_lock(&once_masterlock); \
1492 my_assert(res == 0);
sewardj89d3d852002-04-24 19:21:39 +00001493
sewardjc91a4ff2003-07-11 00:12:58 +00001494# define RELEASE_LOCK \
1495 res = __pthread_mutex_unlock(&once_masterlock); \
1496 my_assert(res == 0);
sewardj89d3d852002-04-24 19:21:39 +00001497
jsgf855d93d2003-10-13 22:26:55 +00001498 void cleanup(void *v) {
1499 TAKE_LOCK;
1500 *once_control = P_ONCE_NOT_DONE;
1501 RELEASE_LOCK;
1502 }
1503
1504 ensure_valgrind("pthread_once");
1505
sewardjc91a4ff2003-07-11 00:12:58 +00001506 /* Grab the lock transiently, so we can safely see what state this
1507 once_control is in. */
1508
1509 TAKE_LOCK;
1510
1511 switch (*once_control) {
1512
1513 case P_ONCE_NOT_DONE:
1514 /* Not started. Change state to indicate running, drop the
1515 lock and run. */
1516 *once_control = P_ONCE_RUNNING;
jsgf855d93d2003-10-13 22:26:55 +00001517 _pthread_cleanup_push(NULL, cleanup, NULL);
sewardjc91a4ff2003-07-11 00:12:58 +00001518 RELEASE_LOCK;
1519 init_routine();
1520 /* re-take the lock, and set state to indicate done. */
1521 TAKE_LOCK;
jsgf855d93d2003-10-13 22:26:55 +00001522 _pthread_cleanup_pop(NULL, False);
sewardjc91a4ff2003-07-11 00:12:58 +00001523 *once_control = P_ONCE_COMPLETED;
1524 RELEASE_LOCK;
1525 break;
1526
1527 case P_ONCE_RUNNING:
1528 /* This is the tricky case. The initialiser is running in
1529 some other thread, but we have to delay this thread till
1530 the other one completes. So we sort-of busy wait. In
1531 fact it makes sense to yield now, because what we want to
1532 happen is for the thread running the initialiser to
1533 complete ASAP. */
1534 RELEASE_LOCK;
1535 done = 0;
1536 while (1) {
1537 /* Let others run for a while. */
1538 __valgrind_pthread_yield();
1539 /* Grab the lock and see if we're done waiting. */
1540 TAKE_LOCK;
1541 if (*once_control == P_ONCE_COMPLETED)
1542 done = 1;
1543 RELEASE_LOCK;
1544 if (done)
1545 break;
1546 }
1547 break;
1548
1549 case P_ONCE_COMPLETED:
1550 default:
1551 /* Easy. It's already done. Just drop the lock. */
1552 RELEASE_LOCK;
1553 break;
sewardj89d3d852002-04-24 19:21:39 +00001554 }
1555
sewardj89d3d852002-04-24 19:21:39 +00001556 return 0;
sewardjc91a4ff2003-07-11 00:12:58 +00001557
1558# undef TAKE_LOCK
1559# undef RELEASE_LOCK
sewardj89d3d852002-04-24 19:21:39 +00001560}
1561
sewardjc91a4ff2003-07-11 00:12:58 +00001562#undef P_ONCE_NOT_DONE
1563#undef P_ONCE_RUNNING
1564#undef P_ONCE_COMPLETED
1565
sewardj89d3d852002-04-24 19:21:39 +00001566
1567/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001568 MISC
1569 ------------------------------------------------ */
1570
sewardj2cb00342002-06-28 01:46:26 +00001571static pthread_mutex_t pthread_atfork_lock
1572 = PTHREAD_MUTEX_INITIALIZER;
1573
sewardj5905fae2002-04-26 13:25:00 +00001574int __pthread_atfork ( void (*prepare)(void),
1575 void (*parent)(void),
1576 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001577{
sewardj2cb00342002-06-28 01:46:26 +00001578 int n, res;
1579 ForkHandlerEntry entry;
1580
1581 ensure_valgrind("pthread_atfork");
1582 __pthread_mutex_lock(&pthread_atfork_lock);
1583
1584 /* Fetch old counter */
1585 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1586 VG_USERREQ__GET_FHSTACK_USED,
1587 0, 0, 0, 0);
1588 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1589 if (n == VG_N_FORKHANDLERSTACK-1)
1590 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1591 "increase and recompile");
1592
1593 /* Add entry */
1594 entry.prepare = *prepare;
1595 entry.parent = *parent;
1596 entry.child = *child;
1597 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1598 VG_USERREQ__SET_FHSTACK_ENTRY,
1599 n, &entry, 0, 0);
1600 my_assert(res == 0);
1601
1602 /* Bump counter */
1603 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1604 VG_USERREQ__SET_FHSTACK_USED,
1605 n+1, 0, 0, 0);
1606 my_assert(res == 0);
1607
1608 __pthread_mutex_unlock(&pthread_atfork_lock);
1609 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001610}
1611
1612
sewardj9df78832003-05-04 12:35:54 +00001613#ifdef GLIBC_2_3
1614/* This seems to be a hook which appeared in glibc-2.3.2. */
1615int __register_atfork ( void (*prepare)(void),
1616 void (*parent)(void),
1617 void (*child)(void) )
1618{
1619 return __pthread_atfork(prepare,parent,child);
1620}
1621#endif
1622
sewardj11f0bb42003-04-26 20:11:15 +00001623WEAK
sewardjbb990782002-05-08 02:01:14 +00001624void __pthread_initialize ( void )
1625{
sewardjbea1caa2002-05-10 23:20:58 +00001626 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001627}
1628
1629
sewardj853f55d2002-04-26 00:27:53 +00001630/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001631 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001632 ------------------------------------------------ */
1633
sewardj3b13f0e2002-04-25 20:17:29 +00001634#include <resolv.h>
1635static int thread_specific_errno[VG_N_THREADS];
1636static int thread_specific_h_errno[VG_N_THREADS];
1637static struct __res_state
1638 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001639
sewardj25418ae2003-05-09 23:40:34 +00001640#undef errno
1641extern int errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001642int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001643{
1644 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001645 /* ensure_valgrind("__errno_location"); */
1646 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001647 VG_USERREQ__PTHREAD_GET_THREADID,
1648 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001649 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001650 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001651 barf("__errno_location: invalid ThreadId");
sewardj25418ae2003-05-09 23:40:34 +00001652 if (tid == 1)
1653 return &errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001654 return & thread_specific_errno[tid];
1655}
1656
sewardj25418ae2003-05-09 23:40:34 +00001657#undef h_errno
1658extern int h_errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001659int* __h_errno_location ( void )
1660{
1661 int tid;
1662 /* ensure_valgrind("__h_errno_location"); */
1663 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1664 VG_USERREQ__PTHREAD_GET_THREADID,
1665 0, 0, 0, 0);
1666 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001667 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001668 barf("__h_errno_location: invalid ThreadId");
sewardj25418ae2003-05-09 23:40:34 +00001669 if (tid == 1)
1670 return &h_errno;
sewardj3b13f0e2002-04-25 20:17:29 +00001671 return & thread_specific_h_errno[tid];
1672}
1673
sewardjb0ff1032002-08-06 09:02:53 +00001674
1675#undef _res
1676extern struct __res_state _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001677struct __res_state* __res_state ( void )
1678{
1679 int tid;
1680 /* ensure_valgrind("__res_state"); */
1681 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1682 VG_USERREQ__PTHREAD_GET_THREADID,
1683 0, 0, 0, 0);
1684 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001685 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001686 barf("__res_state: invalid ThreadId");
sewardjb0ff1032002-08-06 09:02:53 +00001687 if (tid == 1)
1688 return & _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001689 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001690}
1691
1692
sewardj5716dbb2002-04-26 03:28:18 +00001693/* ---------------------------------------------------
1694 LIBC-PRIVATE SPECIFIC DATA
1695 ------------------------------------------------ */
1696
1697/* Relies on assumption that initial private data is NULL. This
1698 should be fixed somehow. */
1699
njn25e49d8e72002-09-23 09:36:25 +00001700/* The allowable keys (indices) (all 3 of them).
sewardj5716dbb2002-04-26 03:28:18 +00001701 From sysdeps/pthread/bits/libc-tsd.h
1702*/
sewardjcb7f08a2002-10-02 09:41:49 +00001703/* as per glibc anoncvs HEAD of 20021001. */
sewardj5716dbb2002-04-26 03:28:18 +00001704enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1705 _LIBC_TSD_KEY_DL_ERROR,
njn25e49d8e72002-09-23 09:36:25 +00001706 _LIBC_TSD_KEY_RPC_VARS,
sewardjcb7f08a2002-10-02 09:41:49 +00001707 _LIBC_TSD_KEY_LOCALE,
1708 _LIBC_TSD_KEY_CTYPE_B,
1709 _LIBC_TSD_KEY_CTYPE_TOLOWER,
1710 _LIBC_TSD_KEY_CTYPE_TOUPPER,
sewardj5716dbb2002-04-26 03:28:18 +00001711 _LIBC_TSD_KEY_N };
1712
1713/* Auto-initialising subsystem. libc_specifics_inited is set
1714 after initialisation. libc_specifics_inited_mx guards it. */
1715static int libc_specifics_inited = 0;
1716static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1717
sewardj00a66b12002-10-12 16:42:35 +00001718
sewardj5716dbb2002-04-26 03:28:18 +00001719/* These are the keys we must initialise the first time. */
sewardjcb7f08a2002-10-02 09:41:49 +00001720static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N];
sewardj5716dbb2002-04-26 03:28:18 +00001721
sewardj00a66b12002-10-12 16:42:35 +00001722
sewardjcb7f08a2002-10-02 09:41:49 +00001723/* Initialise the keys, if they are not already initialised. */
sewardj5716dbb2002-04-26 03:28:18 +00001724static
1725void init_libc_tsd_keys ( void )
1726{
1727 int res, i;
1728 pthread_key_t k;
1729
sewardj08c7f012002-10-07 23:56:55 +00001730 /* Don't fall into deadlock if we get called again whilst we still
1731 hold the lock, via the __uselocale() call herein. */
1732 if (libc_specifics_inited != 0)
1733 return;
1734
1735 /* Take the lock. */
sewardj00a66b12002-10-12 16:42:35 +00001736 res = __pthread_mutex_lock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001737 if (res != 0) barf("init_libc_tsd_keys: lock");
1738
sewardj08c7f012002-10-07 23:56:55 +00001739 /* Now test again, to be sure there is no mistake. */
1740 if (libc_specifics_inited != 0) {
sewardj00a66b12002-10-12 16:42:35 +00001741 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj08c7f012002-10-07 23:56:55 +00001742 if (res != 0) barf("init_libc_tsd_keys: unlock(1)");
1743 return;
sewardj5716dbb2002-04-26 03:28:18 +00001744 }
1745
sewardj08c7f012002-10-07 23:56:55 +00001746 /* Actually do the initialisation. */
1747 /* printf("INIT libc specifics\n"); */
1748 for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
sewardj00a66b12002-10-12 16:42:35 +00001749 res = __pthread_key_create(&k, NULL);
sewardj08c7f012002-10-07 23:56:55 +00001750 if (res != 0) barf("init_libc_tsd_keys: create");
1751 libc_specifics_keys[i] = k;
1752 }
1753
1754 /* Signify init done. */
1755 libc_specifics_inited = 1;
1756
1757# ifdef GLIBC_2_3
1758 /* Set the initialising thread's locale to the global (default)
sewardj00a66b12002-10-12 16:42:35 +00001759 locale. A hack in support of glibc-2.3. This does the biz for
1760 the root thread. For all other threads we run this in
1761 thread_wrapper(), which does the real work of
1762 pthread_create(). */
1763 /* assert that we are the root thread. I don't know if this is
1764 really a valid assertion to make; if it breaks I'll reconsider
1765 it. */
1766 my_assert(pthread_self() == 1);
sewardj08c7f012002-10-07 23:56:55 +00001767 __uselocale(LC_GLOBAL_LOCALE);
1768# endif
1769
1770 /* Unlock and return. */
sewardj00a66b12002-10-12 16:42:35 +00001771 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001772 if (res != 0) barf("init_libc_tsd_keys: unlock");
1773}
1774
1775
1776static int
1777libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1778 const void * pointer )
1779{
sewardjcb7f08a2002-10-02 09:41:49 +00001780 int res;
sewardj5716dbb2002-04-26 03:28:18 +00001781 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardjcb7f08a2002-10-02 09:41:49 +00001782 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001783 barf("libc_internal_tsd_set: invalid key");
1784 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001785 res = __pthread_setspecific(libc_specifics_keys[key], pointer);
sewardj5716dbb2002-04-26 03:28:18 +00001786 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1787 return 0;
1788}
1789
1790static void *
1791libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1792{
sewardjcb7f08a2002-10-02 09:41:49 +00001793 void* v;
sewardj5716dbb2002-04-26 03:28:18 +00001794 /* printf("GET GET GET key %d\n", key); */
sewardjcb7f08a2002-10-02 09:41:49 +00001795 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001796 barf("libc_internal_tsd_get: invalid key");
1797 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001798 v = __pthread_getspecific(libc_specifics_keys[key]);
sewardj5716dbb2002-04-26 03:28:18 +00001799 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1800 return v;
1801}
1802
1803
sewardj70adeb22002-04-27 01:35:38 +00001804int (*__libc_internal_tsd_set)
1805 (enum __libc_tsd_key_t key, const void * pointer)
1806 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001807
sewardj70adeb22002-04-27 01:35:38 +00001808void* (*__libc_internal_tsd_get)
1809 (enum __libc_tsd_key_t key)
1810 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001811
1812
sewardj00a66b12002-10-12 16:42:35 +00001813#ifdef GLIBC_2_3
1814/* This one was first spotted be me in the glibc-2.2.93 sources. */
1815static void**
1816libc_internal_tsd_address ( enum __libc_tsd_key_t key )
1817{
1818 void** v;
1819 /* printf("ADDR ADDR ADDR key %d\n", key); */
1820 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
1821 barf("libc_internal_tsd_address: invalid key");
1822 init_libc_tsd_keys();
1823 v = __pthread_getspecific_addr(libc_specifics_keys[key]);
1824 return v;
1825}
1826
1827void ** (*__libc_internal_tsd_address)
1828 (enum __libc_tsd_key_t key)
1829 = libc_internal_tsd_address;
1830#endif
1831
1832
sewardje663cb92002-04-12 10:26:32 +00001833/* ---------------------------------------------------------------------
1834 These are here (I think) because they are deemed cancellation
1835 points by POSIX. For the moment we'll simply pass the call along
1836 to the corresponding thread-unaware (?) libc routine.
1837 ------------------------------------------------------------------ */
1838
sewardjd529a442002-05-04 19:49:21 +00001839#ifdef GLIBC_2_1
1840extern
1841int __sigaction
1842 (int signum,
1843 const struct sigaction *act,
1844 struct sigaction *oldact);
1845#else
sewardje663cb92002-04-12 10:26:32 +00001846extern
1847int __libc_sigaction
1848 (int signum,
1849 const struct sigaction *act,
1850 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001851#endif
sewardje663cb92002-04-12 10:26:32 +00001852int sigaction(int signum,
1853 const struct sigaction *act,
1854 struct sigaction *oldact)
1855{
sewardjd140e442002-05-29 01:21:19 +00001856 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001857# ifdef GLIBC_2_1
1858 return __sigaction(signum, act, oldact);
1859# else
sewardj45b4b372002-04-16 22:50:32 +00001860 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001861# endif
sewardje663cb92002-04-12 10:26:32 +00001862}
1863
jsgf855d93d2003-10-13 22:26:55 +00001864extern
1865int __libc_accept(int fd, struct sockaddr *addr, socklen_t *len);
1866
1867WEAK int __accept(int fd, struct sockaddr *addr, socklen_t *len)
1868{
1869 __my_pthread_testcancel();
1870 return __libc_accept(fd, addr, len);
1871}
1872strong_alias(__accept, accept);
sewardje663cb92002-04-12 10:26:32 +00001873
1874extern
1875int __libc_connect(int sockfd,
1876 const struct sockaddr *serv_addr,
1877 socklen_t addrlen);
sewardj11f0bb42003-04-26 20:11:15 +00001878WEAK
sewardje663cb92002-04-12 10:26:32 +00001879int connect(int sockfd,
1880 const struct sockaddr *serv_addr,
1881 socklen_t addrlen)
1882{
sewardjd140e442002-05-29 01:21:19 +00001883 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001884 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001885}
1886
1887
1888extern
1889int __libc_fcntl(int fd, int cmd, long arg);
sewardj11f0bb42003-04-26 20:11:15 +00001890WEAK
sewardje663cb92002-04-12 10:26:32 +00001891int fcntl(int fd, int cmd, long arg)
1892{
sewardjd140e442002-05-29 01:21:19 +00001893 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001894 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001895}
1896
1897
1898extern
1899ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj11f0bb42003-04-26 20:11:15 +00001900WEAK
sewardje663cb92002-04-12 10:26:32 +00001901ssize_t write(int fd, const void *buf, size_t count)
1902{
sewardjd140e442002-05-29 01:21:19 +00001903 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001904 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001905}
1906
1907
1908extern
1909ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj11f0bb42003-04-26 20:11:15 +00001910WEAK
sewardje663cb92002-04-12 10:26:32 +00001911ssize_t read(int fd, void *buf, size_t count)
1912{
sewardjd140e442002-05-29 01:21:19 +00001913 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001914 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001915}
1916
sewardjf912dfc2002-11-13 21:51:10 +00001917extern
1918int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj11f0bb42003-04-26 20:11:15 +00001919/* WEAK */
sewardjf912dfc2002-11-13 21:51:10 +00001920int open64(const char *pathname, int flags, mode_t mode)
1921{
jsgf855d93d2003-10-13 22:26:55 +00001922 return __libc_open64(pathname, flags, mode);
sewardjf912dfc2002-11-13 21:51:10 +00001923}
sewardje663cb92002-04-12 10:26:32 +00001924
1925extern
sewardj853f55d2002-04-26 00:27:53 +00001926int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj11f0bb42003-04-26 20:11:15 +00001927/* WEAK */
sewardj853f55d2002-04-26 00:27:53 +00001928int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001929{
jsgf855d93d2003-10-13 22:26:55 +00001930 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001931}
1932
sewardje663cb92002-04-12 10:26:32 +00001933extern
1934int __libc_close(int fd);
sewardj11f0bb42003-04-26 20:11:15 +00001935WEAK
sewardje663cb92002-04-12 10:26:32 +00001936int close(int fd)
1937{
sewardjd140e442002-05-29 01:21:19 +00001938 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001939 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001940}
1941
1942
sewardje663cb92002-04-12 10:26:32 +00001943extern
sewardje663cb92002-04-12 10:26:32 +00001944pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj11f0bb42003-04-26 20:11:15 +00001945WEAK
sewardje663cb92002-04-12 10:26:32 +00001946pid_t waitpid(pid_t pid, int *status, int options)
1947{
sewardjd140e442002-05-29 01:21:19 +00001948 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001949 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001950}
1951
1952
1953extern
1954int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj11f0bb42003-04-26 20:11:15 +00001955WEAK
jsgf855d93d2003-10-13 22:26:55 +00001956int __nanosleep(const struct timespec *req, struct timespec *rem)
sewardje663cb92002-04-12 10:26:32 +00001957{
sewardjd140e442002-05-29 01:21:19 +00001958 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001959 return __libc_nanosleep(req, rem);
1960}
1961
jsgf855d93d2003-10-13 22:26:55 +00001962extern
1963int __libc_pause(void);
1964WEAK
1965int __pause(void)
1966{
1967 __my_pthread_testcancel();
1968 return __libc_pause();
1969}
1970
sewardjbe32e452002-04-24 20:29:58 +00001971
sewardje663cb92002-04-12 10:26:32 +00001972extern
1973int __libc_fsync(int fd);
sewardj11f0bb42003-04-26 20:11:15 +00001974WEAK
sewardje663cb92002-04-12 10:26:32 +00001975int fsync(int fd)
1976{
sewardjd140e442002-05-29 01:21:19 +00001977 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001978 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001979}
1980
sewardjbe32e452002-04-24 20:29:58 +00001981
sewardj70c75362002-04-13 04:18:32 +00001982extern
1983off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj11f0bb42003-04-26 20:11:15 +00001984WEAK
sewardj70c75362002-04-13 04:18:32 +00001985off_t lseek(int fildes, off_t offset, int whence)
1986{
sewardjd140e442002-05-29 01:21:19 +00001987 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001988 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001989}
1990
sewardjbe32e452002-04-24 20:29:58 +00001991
1992extern
1993__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj11f0bb42003-04-26 20:11:15 +00001994WEAK
sewardjbe32e452002-04-24 20:29:58 +00001995__off64_t lseek64(int fildes, __off64_t offset, int whence)
1996{
sewardjd140e442002-05-29 01:21:19 +00001997 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001998 return __libc_lseek64(fildes, offset, whence);
1999}
2000
2001
sewardj726c4122002-05-16 23:39:10 +00002002extern
2003ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
2004 __off64_t __offset);
2005ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
2006 __off64_t __offset)
2007{
sewardjd140e442002-05-29 01:21:19 +00002008 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00002009 return __libc_pread64(__fd, __buf, __nbytes, __offset);
2010}
2011
2012
sewardja18e2102002-05-18 10:43:22 +00002013extern
2014ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
2015 __off64_t __offset);
2016ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
2017 __off64_t __offset)
2018{
sewardjd140e442002-05-29 01:21:19 +00002019 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00002020 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
2021}
2022
sewardj726c4122002-05-16 23:39:10 +00002023
sewardj39b93b12002-05-18 10:56:27 +00002024extern
2025ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
sewardj11f0bb42003-04-26 20:11:15 +00002026WEAK
sewardj39b93b12002-05-18 10:56:27 +00002027ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
2028{
sewardjd140e442002-05-29 01:21:19 +00002029 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00002030 return __libc_pwrite(fd, buf, count, offset);
2031}
2032
2033
2034extern
2035ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
sewardj11f0bb42003-04-26 20:11:15 +00002036WEAK
sewardj39b93b12002-05-18 10:56:27 +00002037ssize_t pread(int fd, void *buf, size_t count, off_t offset)
2038{
sewardjd140e442002-05-29 01:21:19 +00002039 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00002040 return __libc_pread(fd, buf, count, offset);
2041}
2042
jsgf855d93d2003-10-13 22:26:55 +00002043extern
2044int __libc_recv(int s, void *msg, size_t len, int flags);
2045WEAK
2046int recv(int s, void *msg, size_t len, int flags)
sewardj6af4b5d2002-04-16 04:40:49 +00002047{
jsgf855d93d2003-10-13 22:26:55 +00002048 __my_pthread_testcancel();
2049 return __libc_recv(s, msg, len, flags);
sewardj6af4b5d2002-04-16 04:40:49 +00002050}
2051
2052extern
2053int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002054WEAK
sewardj6af4b5d2002-04-16 04:40:49 +00002055int send(int s, const void *msg, size_t len, int flags)
2056{
sewardjd140e442002-05-29 01:21:19 +00002057 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00002058 return __libc_send(s, msg, len, flags);
2059}
2060
sewardjbe32e452002-04-24 20:29:58 +00002061
sewardj3665ded2002-05-16 16:57:25 +00002062extern
2063int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002064WEAK
sewardj3665ded2002-05-16 16:57:25 +00002065int sendmsg(int s, const struct msghdr *msg, int flags)
2066{
sewardjd140e442002-05-29 01:21:19 +00002067 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00002068 return __libc_sendmsg(s, msg, flags);
2069}
2070
2071
sewardj796d6a22002-04-24 02:28:34 +00002072extern
sewardj59da27a2002-06-06 08:33:54 +00002073int __libc_recvmsg(int s, struct msghdr *msg, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002074WEAK
sewardj59da27a2002-06-06 08:33:54 +00002075int recvmsg(int s, struct msghdr *msg, int flags)
2076{
2077 __my_pthread_testcancel();
2078 return __libc_recvmsg(s, msg, flags);
2079}
2080
2081
2082extern
sewardj436e0582002-04-26 14:31:40 +00002083int __libc_recvfrom(int s, void *buf, size_t len, int flags,
2084 struct sockaddr *from, socklen_t *fromlen);
sewardj11f0bb42003-04-26 20:11:15 +00002085WEAK
sewardj436e0582002-04-26 14:31:40 +00002086int recvfrom(int s, void *buf, size_t len, int flags,
2087 struct sockaddr *from, socklen_t *fromlen)
2088{
sewardjd140e442002-05-29 01:21:19 +00002089 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00002090 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
2091}
2092
2093
2094extern
sewardj796d6a22002-04-24 02:28:34 +00002095int __libc_sendto(int s, const void *msg, size_t len, int flags,
2096 const struct sockaddr *to, socklen_t tolen);
sewardj11f0bb42003-04-26 20:11:15 +00002097WEAK
sewardj796d6a22002-04-24 02:28:34 +00002098int sendto(int s, const void *msg, size_t len, int flags,
2099 const struct sockaddr *to, socklen_t tolen)
2100{
sewardjd140e442002-05-29 01:21:19 +00002101 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00002102 return __libc_sendto(s, msg, len, flags, to, tolen);
2103}
2104
sewardjbe32e452002-04-24 20:29:58 +00002105
sewardj369b1702002-04-24 13:28:15 +00002106extern
2107int __libc_system(const char* str);
sewardj11f0bb42003-04-26 20:11:15 +00002108WEAK
sewardj369b1702002-04-24 13:28:15 +00002109int system(const char* str)
2110{
sewardjd140e442002-05-29 01:21:19 +00002111 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00002112 return __libc_system(str);
2113}
2114
sewardjbe32e452002-04-24 20:29:58 +00002115
sewardjab0b1c32002-04-24 19:26:47 +00002116extern
2117pid_t __libc_wait(int *status);
sewardj11f0bb42003-04-26 20:11:15 +00002118WEAK
sewardjab0b1c32002-04-24 19:26:47 +00002119pid_t wait(int *status)
2120{
sewardjd140e442002-05-29 01:21:19 +00002121 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00002122 return __libc_wait(status);
2123}
2124
sewardj45b4b372002-04-16 22:50:32 +00002125
sewardj67f1d582002-05-24 02:11:32 +00002126extern
2127int __libc_msync(const void *start, size_t length, int flags);
sewardj11f0bb42003-04-26 20:11:15 +00002128WEAK
sewardj67f1d582002-05-24 02:11:32 +00002129int msync(const void *start, size_t length, int flags)
2130{
sewardjd140e442002-05-29 01:21:19 +00002131 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00002132 return __libc_msync(start, length, flags);
2133}
2134
jsgf855d93d2003-10-13 22:26:55 +00002135strong_alias(close, __close)
2136strong_alias(fcntl, __fcntl)
2137strong_alias(lseek, __lseek)
2138strong_alias(open, __open)
2139strong_alias(open64, __open64)
2140strong_alias(read, __read)
2141strong_alias(wait, __wait)
2142strong_alias(write, __write)
2143strong_alias(connect, __connect)
2144strong_alias(send, __send)
2145
2146weak_alias (__pread64, pread64)
2147weak_alias (__pwrite64, pwrite64)
2148weak_alias(__nanosleep, nanosleep)
2149weak_alias(__pause, pause)
2150
2151
2152extern
2153void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
2154/* not weak: WEAK */
2155void longjmp(jmp_buf env, int val)
2156{
2157 __libc_longjmp(env, val);
2158}
2159
2160
2161extern void __libc_siglongjmp (sigjmp_buf env, int val)
2162 __attribute__ ((noreturn));
2163void siglongjmp(sigjmp_buf env, int val)
2164{
2165 kludged("siglongjmp (cleanup handlers are ignored)");
2166 __libc_siglongjmp(env, val);
2167}
2168
sewardj5905fae2002-04-26 13:25:00 +00002169
sewardj2cb00342002-06-28 01:46:26 +00002170/*--- fork and its helper ---*/
2171
2172static
2173void run_fork_handlers ( int what )
2174{
2175 ForkHandlerEntry entry;
2176 int n_h, n_handlers, i, res;
2177
2178 my_assert(what == 0 || what == 1 || what == 2);
2179
2180 /* Fetch old counter */
2181 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2182 VG_USERREQ__GET_FHSTACK_USED,
2183 0, 0, 0, 0);
2184 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2185
2186 /* Prepare handlers (what == 0) are called in opposite order of
2187 calls to pthread_atfork. Parent and child handlers are called
2188 in the same order as calls to pthread_atfork. */
2189 if (what == 0)
2190 n_h = n_handlers - 1;
2191 else
2192 n_h = 0;
2193
2194 for (i = 0; i < n_handlers; i++) {
2195 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2196 VG_USERREQ__GET_FHSTACK_ENTRY,
2197 n_h, &entry, 0, 0);
2198 my_assert(res == 0);
2199 switch (what) {
2200 case 0: if (entry.prepare) entry.prepare();
2201 n_h--; break;
2202 case 1: if (entry.parent) entry.parent();
2203 n_h++; break;
2204 case 2: if (entry.child) entry.child();
2205 n_h++; break;
2206 default: barf("run_fork_handlers: invalid what");
2207 }
2208 }
2209
2210 if (what != 0 /* prepare */) {
2211 /* Empty out the stack. */
2212 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2213 VG_USERREQ__SET_FHSTACK_USED,
2214 0, 0, 0, 0);
2215 my_assert(res == 0);
2216 }
2217}
2218
2219extern
2220pid_t __libc_fork(void);
2221pid_t __fork(void)
2222{
2223 pid_t pid;
2224 __my_pthread_testcancel();
2225 __pthread_mutex_lock(&pthread_atfork_lock);
2226
2227 run_fork_handlers(0 /* prepare */);
2228 pid = __libc_fork();
2229 if (pid == 0) {
2230 /* I am the child */
2231 run_fork_handlers(2 /* child */);
sewardjd8acdf22002-11-13 21:57:52 +00002232 __pthread_mutex_unlock(&pthread_atfork_lock);
sewardj2cb00342002-06-28 01:46:26 +00002233 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2234 } else {
2235 /* I am the parent */
2236 run_fork_handlers(1 /* parent */);
2237 __pthread_mutex_unlock(&pthread_atfork_lock);
2238 }
2239 return pid;
2240}
2241
2242
njn25e49d8e72002-09-23 09:36:25 +00002243pid_t __vfork(void)
2244{
2245 return __fork();
2246}
sewardj2cb00342002-06-28 01:46:26 +00002247
2248
sewardj08a4c3f2002-04-13 03:45:44 +00002249
sewardj3b13f0e2002-04-25 20:17:29 +00002250/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002251 Hacky implementation of semaphores.
2252 ------------------------------------------------------------------ */
2253
2254#include <semaphore.h>
2255
2256/* This is a terrible way to do the remapping. Plan is to import an
2257 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002258
2259typedef
2260 struct {
2261 pthread_mutex_t se_mx;
2262 pthread_cond_t se_cv;
2263 int count;
2264 }
2265 vg_sem_t;
2266
2267static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2268
2269static int se_remap_used = 0;
2270static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2271static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2272
2273static vg_sem_t* se_remap ( sem_t* orig )
2274{
2275 int res, i;
2276 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002277 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002278
2279 for (i = 0; i < se_remap_used; i++) {
2280 if (se_remap_orig[i] == orig)
2281 break;
2282 }
2283 if (i == se_remap_used) {
2284 if (se_remap_used == VG_N_SEMAPHORES) {
2285 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002286 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002287 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002288 }
2289 se_remap_used++;
2290 se_remap_orig[i] = orig;
2291 /* printf("allocated semaphore %d\n", i); */
2292 }
2293 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002294 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002295 return &se_remap_new[i];
2296}
2297
2298
2299int sem_init(sem_t *sem, int pshared, unsigned int value)
2300{
2301 int res;
2302 vg_sem_t* vg_sem;
2303 ensure_valgrind("sem_init");
2304 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002305 pthread_error("sem_init: unsupported pshared value");
sewardj25418ae2003-05-09 23:40:34 +00002306 *(__errno_location()) = ENOSYS;
sewardj8f253ff2002-05-19 00:13:34 +00002307 return -1;
2308 }
2309 vg_sem = se_remap(sem);
2310 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002311 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002312 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002313 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002314 vg_sem->count = value;
2315 return 0;
2316}
2317
2318
2319int sem_wait ( sem_t* sem )
2320{
2321 int res;
2322 vg_sem_t* vg_sem;
2323 ensure_valgrind("sem_wait");
2324 vg_sem = se_remap(sem);
2325 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002326 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002327 while (vg_sem->count == 0) {
2328 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002329 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002330 }
2331 vg_sem->count--;
2332 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002333 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002334 return 0;
2335}
2336
2337int sem_post ( sem_t* sem )
2338{
2339 int res;
2340 vg_sem_t* vg_sem;
2341 ensure_valgrind("sem_post");
2342 vg_sem = se_remap(sem);
2343 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002344 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002345 if (vg_sem->count == 0) {
2346 vg_sem->count++;
2347 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002348 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002349 } else {
2350 vg_sem->count++;
2351 }
2352 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002353 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002354 return 0;
2355}
2356
2357
2358int sem_trywait ( sem_t* sem )
2359{
2360 int ret, res;
2361 vg_sem_t* vg_sem;
2362 ensure_valgrind("sem_trywait");
2363 vg_sem = se_remap(sem);
2364 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002365 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002366 if (vg_sem->count > 0) {
2367 vg_sem->count--;
2368 ret = 0;
2369 } else {
2370 ret = -1;
sewardj25418ae2003-05-09 23:40:34 +00002371 *(__errno_location()) = EAGAIN;
sewardj8f253ff2002-05-19 00:13:34 +00002372 }
2373 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002374 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002375 return ret;
2376}
2377
2378
2379int sem_getvalue(sem_t* sem, int * sval)
2380{
2381 vg_sem_t* vg_sem;
2382 ensure_valgrind("sem_trywait");
2383 vg_sem = se_remap(sem);
2384 *sval = vg_sem->count;
2385 return 0;
2386}
2387
2388
2389int sem_destroy(sem_t * sem)
2390{
2391 kludged("sem_destroy");
2392 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2393 return 0;
2394}
2395
sewardj9ad92d92002-10-16 19:45:06 +00002396
2397int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2398{
2399 int res;
2400 vg_sem_t* vg_sem;
2401 ensure_valgrind("sem_timedwait");
2402 vg_sem = se_remap(sem);
2403 res = __pthread_mutex_lock(&vg_sem->se_mx);
2404 my_assert(res == 0);
2405 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
2406 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
2407 }
2408 if ( vg_sem->count > 0 ) {
2409 vg_sem->count--;
2410 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2411 my_assert(res == 0 );
2412 return 0;
2413 } else {
2414 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2415 my_assert(res == 0 );
2416 *(__errno_location()) = ETIMEDOUT;
2417 return -1;
2418 }
2419}
2420
sewardj8f253ff2002-05-19 00:13:34 +00002421
2422/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002423 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002424 ------------------------------------------------------------------ */
2425
sewardj2d8b3f02002-06-01 14:14:19 +00002426typedef
2427 struct {
2428 int initted; /* != 0 --> in use; sanity check only */
2429 int prefer_w; /* != 0 --> prefer writer */
2430 int nwait_r; /* # of waiting readers */
2431 int nwait_w; /* # of waiting writers */
2432 pthread_cond_t cv_r; /* for signalling readers */
2433 pthread_cond_t cv_w; /* for signalling writers */
2434 pthread_mutex_t mx;
2435 int status;
2436 /* allowed range for status: >= -1. -1 means 1 writer currently
2437 active, >= 0 means N readers currently active. */
2438 }
2439 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002440
2441
2442static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2443
2444static int rw_remap_used = 0;
2445static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2446static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2447
sewardj2d8b3f02002-06-01 14:14:19 +00002448
2449static
2450void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2451{
2452 int res = 0;
2453 vg_rwl->initted = 1;
2454 vg_rwl->prefer_w = 1;
2455 vg_rwl->nwait_r = 0;
2456 vg_rwl->nwait_w = 0;
2457 vg_rwl->status = 0;
2458 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2459 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2460 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002461 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002462}
2463
2464
sewardja1ac5cb2002-05-27 13:00:05 +00002465/* Take the address of a LinuxThreads rwlock_t and return the shadow
2466 address of our version. Further, if the LinuxThreads version
2467 appears to have been statically initialised, do the same to the one
2468 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2469 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2470 uninitialised and non-zero meaning initialised.
2471*/
2472static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2473{
2474 int res, i;
2475 vg_rwlock_t* vg_rwl;
2476 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002477 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002478
2479 for (i = 0; i < rw_remap_used; i++) {
2480 if (rw_remap_orig[i] == orig)
2481 break;
2482 }
2483 if (i == rw_remap_used) {
2484 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002485 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002486 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002487 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2488 }
2489 rw_remap_used++;
2490 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002491 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002492 if (0) printf("allocated rwlock %d\n", i);
2493 }
2494 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002495 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002496 vg_rwl = &rw_remap_new[i];
2497
sewardj2d8b3f02002-06-01 14:14:19 +00002498 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002499 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002500 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002501 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002502 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002503 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002504 }
2505
2506 return vg_rwl;
2507}
2508
2509
sewardja1ac5cb2002-05-27 13:00:05 +00002510int pthread_rwlock_init ( pthread_rwlock_t* orig,
2511 const pthread_rwlockattr_t* attr )
2512{
sewardja1ac5cb2002-05-27 13:00:05 +00002513 vg_rwlock_t* rwl;
2514 if (0) printf ("pthread_rwlock_init\n");
2515 /* Force the remapper to initialise the shadow. */
2516 orig->__rw_readers = 0;
2517 /* Install the lock preference; the remapper needs to know it. */
2518 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2519 if (attr)
2520 orig->__rw_kind = attr->__lockkind;
2521 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002522 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002523}
2524
sewardj2d8b3f02002-06-01 14:14:19 +00002525
2526static
2527void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002528{
sewardj2d8b3f02002-06-01 14:14:19 +00002529 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2530 rwl->nwait_r--;
2531 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002532}
2533
sewardj2d8b3f02002-06-01 14:14:19 +00002534
sewardja1ac5cb2002-05-27 13:00:05 +00002535int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2536{
2537 int res;
2538 vg_rwlock_t* rwl;
2539 if (0) printf ("pthread_rwlock_rdlock\n");
2540 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002541 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002542 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002543 if (!rwl->initted) {
2544 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002545 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002546 return EINVAL;
2547 }
2548 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002549 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002550 rwl->nwait_r++;
2551 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2552 while (1) {
2553 if (rwl->status == 0) break;
2554 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002555 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002556 }
2557 pthread_cleanup_pop(0);
2558 rwl->nwait_r--;
2559 }
sewardj2d94c112002-06-03 01:25:54 +00002560 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002561 rwl->status++;
2562 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002563 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002564 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002565}
2566
sewardj2d8b3f02002-06-01 14:14:19 +00002567
sewardja1ac5cb2002-05-27 13:00:05 +00002568int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2569{
2570 int res;
2571 vg_rwlock_t* rwl;
2572 if (0) printf ("pthread_rwlock_tryrdlock\n");
2573 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002574 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002575 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002576 if (!rwl->initted) {
2577 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002578 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002579 return EINVAL;
2580 }
2581 if (rwl->status == -1) {
2582 /* Writer active; we have to give up. */
2583 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002584 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002585 return EBUSY;
2586 }
2587 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002588 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002589 rwl->status++;
2590 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002591 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002592 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002593}
2594
sewardj2d8b3f02002-06-01 14:14:19 +00002595
2596static
2597void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2598{
2599 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2600 rwl->nwait_w--;
2601 pthread_mutex_unlock (&rwl->mx);
2602}
2603
2604
sewardja1ac5cb2002-05-27 13:00:05 +00002605int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2606{
2607 int res;
2608 vg_rwlock_t* rwl;
2609 if (0) printf ("pthread_rwlock_wrlock\n");
2610 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002611 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002612 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002613 if (!rwl->initted) {
2614 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002615 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002616 return EINVAL;
2617 }
2618 if (rwl->status != 0) {
2619 rwl->nwait_w++;
2620 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2621 while (1) {
2622 if (rwl->status == 0) break;
2623 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002624 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002625 }
2626 pthread_cleanup_pop(0);
2627 rwl->nwait_w--;
2628 }
sewardj2d94c112002-06-03 01:25:54 +00002629 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002630 rwl->status = -1;
2631 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002632 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002633 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002634}
2635
sewardj2d8b3f02002-06-01 14:14:19 +00002636
sewardja1ac5cb2002-05-27 13:00:05 +00002637int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2638{
2639 int res;
2640 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002641 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002642 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002643 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002644 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002645 if (!rwl->initted) {
2646 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002647 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002648 return EINVAL;
2649 }
2650 if (rwl->status != 0) {
2651 /* Reader(s) or a writer active; we have to give up. */
2652 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002653 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002654 return EBUSY;
2655 }
2656 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002657 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002658 rwl->status = -1;
2659 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002660 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002661 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002662}
2663
sewardj2d8b3f02002-06-01 14:14:19 +00002664
sewardja1ac5cb2002-05-27 13:00:05 +00002665int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2666{
2667 int res;
2668 vg_rwlock_t* rwl;
2669 if (0) printf ("pthread_rwlock_unlock\n");
2670 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002671 rwl = rw_remap ( orig );
2672 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002673 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002674 if (!rwl->initted) {
2675 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002676 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002677 return EINVAL;
2678 }
2679 if (rwl->status == 0) {
2680 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002681 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002682 return EPERM;
2683 }
sewardj2d94c112002-06-03 01:25:54 +00002684 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002685 if (rwl->status == -1) {
2686 rwl->status = 0;
2687 } else {
sewardj2d94c112002-06-03 01:25:54 +00002688 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002689 rwl->status--;
2690 }
2691
sewardj2d94c112002-06-03 01:25:54 +00002692 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002693
2694 if (rwl->prefer_w) {
2695
2696 /* Favour waiting writers, if any. */
2697 if (rwl->nwait_w > 0) {
2698 /* Writer(s) are waiting. */
2699 if (rwl->status == 0) {
2700 /* We can let a writer in. */
2701 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002702 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002703 } else {
2704 /* There are still readers active. Do nothing; eventually
2705 they will disappear, at which point a writer will be
2706 admitted. */
2707 }
2708 }
2709 else
2710 /* No waiting writers. */
2711 if (rwl->nwait_r > 0) {
2712 /* Let in a waiting reader. */
2713 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002714 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002715 }
2716
2717 } else {
2718
2719 /* Favour waiting readers, if any. */
2720 if (rwl->nwait_r > 0) {
2721 /* Reader(s) are waiting; let one in. */
2722 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002723 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002724 }
2725 else
2726 /* No waiting readers. */
2727 if (rwl->nwait_w > 0 && rwl->status == 0) {
2728 /* We have waiting writers and no active readers; let a
2729 writer in. */
2730 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002731 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002732 }
2733 }
2734
2735 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002736 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002737 return 0;
2738}
2739
2740
2741int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2742{
2743 int res;
2744 vg_rwlock_t* rwl;
2745 if (0) printf ("pthread_rwlock_destroy\n");
2746 rwl = rw_remap ( orig );
2747 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002748 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002749 if (!rwl->initted) {
2750 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002751 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002752 return EINVAL;
2753 }
2754 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2755 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002756 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002757 return EBUSY;
2758 }
2759 rwl->initted = 0;
2760 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002761 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002762 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002763}
2764
2765
sewardj47e4e312002-06-18 09:24:34 +00002766/* Copied directly from LinuxThreads. */
2767int
2768pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
2769{
2770 attr->__lockkind = 0;
2771 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
2772
2773 return 0;
2774}
2775
sewardjfe18eb82002-07-13 12:58:44 +00002776/* Copied directly from LinuxThreads. */
2777int
sewardj5706bfa2002-12-08 23:42:17 +00002778pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
2779{
2780 return 0;
2781}
2782
2783/* Copied directly from LinuxThreads. */
2784int
sewardjfe18eb82002-07-13 12:58:44 +00002785pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
2786{
2787 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
2788 return EINVAL;
2789
2790 /* For now it is not possible to shared a conditional variable. */
2791 if (pshared != PTHREAD_PROCESS_PRIVATE)
2792 return ENOSYS;
2793
2794 attr->__pshared = pshared;
2795
2796 return 0;
2797}
2798
sewardj47e4e312002-06-18 09:24:34 +00002799
sewardj262b5be2003-04-26 21:19:53 +00002800
2801/* ---------------------------------------------------------------------
jsgf855d93d2003-10-13 22:26:55 +00002802 Manage the allocation and use of RT signals. The Valgrind core
2803 uses one. glibc needs us to implement this to make RT signals
2804 work; things just seem to crash if we don't.
sewardj262b5be2003-04-26 21:19:53 +00002805 ------------------------------------------------------------------ */
sewardj262b5be2003-04-26 21:19:53 +00002806int __libc_current_sigrtmin (void)
2807{
jsgf855d93d2003-10-13 22:26:55 +00002808 return VG_(sig_rtmin);
sewardj262b5be2003-04-26 21:19:53 +00002809}
2810
2811int __libc_current_sigrtmax (void)
2812{
jsgf855d93d2003-10-13 22:26:55 +00002813 return VG_(sig_rtmax);
sewardj262b5be2003-04-26 21:19:53 +00002814}
2815
2816int __libc_allocate_rtsig (int high)
2817{
jsgf855d93d2003-10-13 22:26:55 +00002818 return VG_(sig_alloc_rtsig)(high);
sewardj262b5be2003-04-26 21:19:53 +00002819}
2820
sewardjd5bef572002-10-23 21:49:33 +00002821/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002822 B'stard.
2823 ------------------------------------------------------------------ */
sewardj5905fae2002-04-26 13:25:00 +00002824strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2825strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2826strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2827strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2828 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
sewardjf0995512003-07-06 01:29:49 +00002829 weak_alias(__pthread_mutexattr_setpshared, pthread_mutexattr_setpshared)
sewardj5905fae2002-04-26 13:25:00 +00002830strong_alias(__pthread_mutex_init, pthread_mutex_init)
2831strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2832strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2833strong_alias(__pthread_once, pthread_once)
2834strong_alias(__pthread_atfork, pthread_atfork)
2835strong_alias(__pthread_key_create, pthread_key_create)
2836strong_alias(__pthread_getspecific, pthread_getspecific)
2837strong_alias(__pthread_setspecific, pthread_setspecific)
2838
sewardjd529a442002-05-04 19:49:21 +00002839#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002840strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002841#endif
2842
sewardj5905fae2002-04-26 13:25:00 +00002843weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00002844weak_alias(__vfork, vfork)
sewardjf0b06452002-06-04 08:38:04 +00002845weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00002846
2847/*--------------------------------------------------*/
2848
sewardj5905fae2002-04-26 13:25:00 +00002849weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002850weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002851weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002852
sewardja1ac5cb2002-05-27 13:00:05 +00002853weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2854weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2855weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2856weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2857
sewardj060b04f2002-04-26 21:01:13 +00002858
sewardj3b13f0e2002-04-25 20:17:29 +00002859/* I've no idea what these are, but they get called quite a lot.
2860 Anybody know? */
2861
njnff28df92003-10-12 17:26:04 +00002862#ifndef __UCLIBC__
sewardj3b13f0e2002-04-25 20:17:29 +00002863#undef _IO_flockfile
2864void _IO_flockfile ( _IO_FILE * file )
2865{
sewardj853f55d2002-04-26 00:27:53 +00002866 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002867}
sewardj5905fae2002-04-26 13:25:00 +00002868weak_alias(_IO_flockfile, flockfile);
2869
sewardj3b13f0e2002-04-25 20:17:29 +00002870#undef _IO_funlockfile
2871void _IO_funlockfile ( _IO_FILE * file )
2872{
sewardj853f55d2002-04-26 00:27:53 +00002873 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002874}
sewardj5905fae2002-04-26 13:25:00 +00002875weak_alias(_IO_funlockfile, funlockfile);
njnff28df92003-10-12 17:26:04 +00002876#endif
sewardj5905fae2002-04-26 13:25:00 +00002877
sewardj3b13f0e2002-04-25 20:17:29 +00002878
sewardjd4f2c712002-04-30 10:20:10 +00002879/* This doesn't seem to be needed to simulate libpthread.so's external
2880 interface, but many people complain about its absence. */
2881
2882strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2883weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002884
sewardj5e657c32003-10-12 08:33:30 +00002885/* POSIX spinlocks, taken from glibc linuxthreads/sysdeps/i386 */
2886
2887typedef volatile int pthread_spinlock_t; /* Huh? Guarded by __USE_XOPEN2K */
2888
2889int pthread_spin_init(pthread_spinlock_t *lock, int pshared)
2890{
2891 /* We can ignore the `pshared' parameter. Since we are busy-waiting
2892 all processes which can access the memory location `lock' points
2893 to can use the spinlock. */
2894 *lock = 1;
2895 return 0;
2896}
2897
2898int pthread_spin_lock(pthread_spinlock_t *lock)
2899{
2900 asm volatile
2901 ("\n"
2902 "1:\n\t"
2903 "lock; decl %0\n\t"
2904 "js 2f\n\t"
2905 ".section .text.spinlock,\"ax\"\n"
2906 "2:\n\t"
2907 "cmpl $0,%0\n\t"
2908 "rep; nop\n\t"
2909 "jle 2b\n\t"
2910 "jmp 1b\n\t"
2911 ".previous"
2912 : "=m" (*lock));
2913 return 0;
2914}
2915
2916int pthread_spin_unlock(pthread_spinlock_t *lock)
2917{
2918 asm volatile
2919 ("movl $1,%0"
2920 : "=m" (*lock));
2921 return 0;
2922}
2923
2924int pthread_spin_destroy(pthread_spinlock_t *lock)
2925{
2926 /* Nothing to do. */
2927 return 0;
2928}
2929
2930int pthread_spin_trylock(pthread_spinlock_t *lock)
2931{
2932 int oldval;
2933
2934 asm volatile
2935 ("xchgl %0,%1"
2936 : "=r" (oldval), "=m" (*lock)
2937 : "0" (0));
2938 return oldval > 0 ? 0 : EBUSY;
2939}
sewardj439d45e2002-05-03 20:43:10 +00002940
2941/*--------------------------------------------------------------------*/
2942/*--- end vg_libpthread.c ---*/
2943/*--------------------------------------------------------------------*/