blob: 42f51d6853298878abcb3ef4e7b054bf50551b22 [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
11 Copyright (C) 2000-2002 Julian Seward
12 jseward@acm.org
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardj439d45e2002-05-03 20:43:10 +000030*/
31
32/* ALL THIS CODE RUNS ON THE SIMULATED CPU.
33
34 This is a replacement for the standard libpthread.so. It is loaded
sewardje663cb92002-04-12 10:26:32 +000035 as part of the client's image (if required) and directs pthread
36 calls through to Valgrind's request mechanism.
37
38 A couple of caveats.
39
40 1. Since it's a binary-compatible replacement for an existing library,
41 we must take care to used exactly the same data layouts, etc, as
42 the standard pthread.so does.
43
44 2. Since this runs as part of the client, there are no specific
45 restrictions on what headers etc we can include, so long as
46 this libpthread.so does not end up having dependencies on .so's
47 which the real one doesn't.
48
49 Later ... it appears we cannot call file-related stuff in libc here,
50 perhaps fair enough. Be careful what you call from here. Even exit()
51 doesn't work (gives infinite recursion and then stack overflow); hence
52 myexit(). Also fprintf doesn't seem safe.
53*/
54
55#include "valgrind.h" /* For the request-passing mechanism */
56#include "vg_include.h" /* For the VG_USERREQ__* constants */
57
sewardja1ac5cb2002-05-27 13:00:05 +000058#define __USE_UNIX98
59#include <sys/types.h>
60#include <pthread.h>
61#undef __USE_UNIX98
62
sewardje663cb92002-04-12 10:26:32 +000063#include <unistd.h>
64#include <string.h>
sewardj2a1dcce2002-04-22 12:45:25 +000065#ifdef GLIBC_2_1
66#include <sys/time.h>
67#endif
sewardje663cb92002-04-12 10:26:32 +000068
sewardj2d94c112002-06-03 01:25:54 +000069#include <stdio.h>
70
sewardj705d3cb2002-05-23 13:13:12 +000071
72/* ---------------------------------------------------------------------
73 Forwardses.
74 ------------------------------------------------------------------ */
75
76static void wait_for_fd_to_be_readable_or_erring ( int fd );
77
sewardj9a2224b2002-06-19 10:17:40 +000078static
sewardj08c7f012002-10-07 23:56:55 +000079int my_do_syscall1 ( int syscallno, int arg1 );
80
81static
sewardj9a2224b2002-06-19 10:17:40 +000082int my_do_syscall2 ( int syscallno,
83 int arg1, int arg2 );
84
sewardj08c7f012002-10-07 23:56:55 +000085static
86int my_do_syscall3 ( int syscallno,
87 int arg1, int arg2, int arg3 );
88
89
90#ifdef GLIBC_2_3
91 /* kludge by JRS (not from glibc) ... */
92 typedef void* __locale_t;
93
94 /* Copied from locale/locale.h in glibc-2.2.93 sources */
95 /* This value can be passed to `uselocale' and may be returned by
96 it. Passing this value to any other function has undefined
97 behavior. */
98# define LC_GLOBAL_LOCALE ((__locale_t) -1L)
99 extern __locale_t __uselocale ( __locale_t );
100#endif
101
sewardj00a66b12002-10-12 16:42:35 +0000102static
103void init_libc_tsd_keys ( void );
104
sewardj705d3cb2002-05-23 13:13:12 +0000105
sewardje663cb92002-04-12 10:26:32 +0000106/* ---------------------------------------------------------------------
107 Helpers. We have to be pretty self-sufficient.
108 ------------------------------------------------------------------ */
109
sewardj436e0582002-04-26 14:31:40 +0000110/* Number of times any given error message is printed. */
111#define N_MOANS 3
112
sewardj45b4b372002-04-16 22:50:32 +0000113/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
114 Returns 0 (none) if not running on Valgrind. */
115static
116int get_pt_trace_level ( void )
117{
118 int res;
119 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
120 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
121 0, 0, 0, 0);
122 return res;
123}
124
sewardje663cb92002-04-12 10:26:32 +0000125static
sewardj2d94c112002-06-03 01:25:54 +0000126void my_exit ( int arg )
sewardje663cb92002-04-12 10:26:32 +0000127{
sewardj08c7f012002-10-07 23:56:55 +0000128 my_do_syscall1(__NR_exit, arg);
129 /*NOTREACHED*/
sewardje663cb92002-04-12 10:26:32 +0000130}
131
sewardj08c7f012002-10-07 23:56:55 +0000132static
133void my_write ( int fd, const void *buf, int count )
134{
135 my_do_syscall3(__NR_write, fd, (int)buf, count );
136}
sewardje663cb92002-04-12 10:26:32 +0000137
sewardj68b2dd92002-05-10 21:03:56 +0000138/* We need this guy -- it's in valgrind.so. */
139extern void VG_(startup) ( void );
140
141
142/* Just start up Valgrind if it's not already going. VG_(startup)()
143 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000144static __inline__
sewardje663cb92002-04-12 10:26:32 +0000145void ensure_valgrind ( char* caller )
146{
sewardj68b2dd92002-05-10 21:03:56 +0000147 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000148}
149
sewardjbea1caa2002-05-10 23:20:58 +0000150/* While we're at it ... hook our own startup function into this
151 game. */
152__asm__ (
153 ".section .init\n"
154 "\tcall vgPlain_startup"
155);
156
sewardje663cb92002-04-12 10:26:32 +0000157
158static
sewardj3b5d8862002-04-20 13:53:23 +0000159__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +0000160void barf ( char* str )
161{
162 char buf[100];
163 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000164 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000165 strcat(buf, str);
166 strcat(buf, "\n\n");
sewardj08c7f012002-10-07 23:56:55 +0000167 my_write(2, buf, strlen(buf));
sewardj2d94c112002-06-03 01:25:54 +0000168 my_exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000169 /* We have to persuade gcc into believing this doesn't return. */
170 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000171}
172
173
sewardj2a3d28c2002-04-14 13:27:00 +0000174static void ignored ( char* msg )
175{
sewardj436e0582002-04-26 14:31:40 +0000176 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000177 char* ig = "valgrind's libpthread.so: IGNORED call to: ";
sewardj08c7f012002-10-07 23:56:55 +0000178 my_write(2, ig, strlen(ig));
179 my_write(2, msg, strlen(msg));
sewardj45b4b372002-04-16 22:50:32 +0000180 ig = "\n";
sewardj08c7f012002-10-07 23:56:55 +0000181 my_write(2, ig, strlen(ig));
sewardj45b4b372002-04-16 22:50:32 +0000182 }
sewardj2a3d28c2002-04-14 13:27:00 +0000183}
184
sewardj30671ff2002-04-21 00:13:57 +0000185static void kludged ( char* msg )
186{
sewardj436e0582002-04-26 14:31:40 +0000187 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000188 char* ig = "valgrind's libpthread.so: KLUDGED call to: ";
sewardj08c7f012002-10-07 23:56:55 +0000189 my_write(2, ig, strlen(ig));
190 my_write(2, msg, strlen(msg));
sewardj439d45e2002-05-03 20:43:10 +0000191 ig = "\n";
sewardj08c7f012002-10-07 23:56:55 +0000192 my_write(2, ig, strlen(ig));
sewardj439d45e2002-05-03 20:43:10 +0000193 }
194}
195
196static void not_inside ( char* msg )
197{
sewardj68b2dd92002-05-10 21:03:56 +0000198 VG_(startup)();
sewardj30671ff2002-04-21 00:13:57 +0000199}
200
sewardjccef2e62002-05-29 19:26:32 +0000201__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000202void vgPlain_unimp ( char* what )
203{
sewardj439d45e2002-05-03 20:43:10 +0000204 char* ig = "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ";
sewardj08c7f012002-10-07 23:56:55 +0000205 my_write(2, ig, strlen(ig));
206 my_write(2, what, strlen(what));
sewardj3b13f0e2002-04-25 20:17:29 +0000207 ig = "\n";
sewardj08c7f012002-10-07 23:56:55 +0000208 my_write(2, ig, strlen(ig));
sewardj3b13f0e2002-04-25 20:17:29 +0000209 barf("Please report this bug to me at: jseward@acm.org");
210}
211
sewardje663cb92002-04-12 10:26:32 +0000212
sewardj457cc472002-06-03 23:13:47 +0000213static
sewardj2d94c112002-06-03 01:25:54 +0000214void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
215{
216 static Bool entered = False;
217 if (entered)
218 my_exit(2);
219 entered = True;
220 fprintf(stderr, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
221 "valgrind", file, line, fn, expr );
222 fprintf(stderr, "Please report this bug to me at: %s\n\n",
223 VG_EMAIL_ADDR);
224 my_exit(1);
225}
226
227#define MY__STRING(__str) #__str
228
229#define my_assert(expr) \
230 ((void) ((expr) ? 0 : \
231 (my_assert_fail (MY__STRING(expr), \
232 __FILE__, __LINE__, \
233 __PRETTY_FUNCTION__), 0)))
234
sewardj00a66b12002-10-12 16:42:35 +0000235static
236void my_free ( void* ptr )
237{
238 int res;
239 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
240 VG_USERREQ__FREE, ptr, 0, 0, 0);
241 my_assert(res == 0);
242}
243
244
245static
246void* my_malloc ( int nbytes )
247{
248 void* res;
249 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
250 VG_USERREQ__MALLOC, nbytes, 0, 0, 0);
251 my_assert(res != (void*)0);
252 return res;
253}
254
255
sewardj2d94c112002-06-03 01:25:54 +0000256
sewardje663cb92002-04-12 10:26:32 +0000257/* ---------------------------------------------------------------------
258 Pass pthread_ calls to Valgrind's request mechanism.
259 ------------------------------------------------------------------ */
260
sewardjf8f819e2002-04-17 23:21:37 +0000261#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000262#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000263
sewardja1ac5cb2002-05-27 13:00:05 +0000264
sewardjf8f819e2002-04-17 23:21:37 +0000265/* ---------------------------------------------------
sewardj4dced352002-06-04 22:54:20 +0000266 Ummm ..
267 ------------------------------------------------ */
268
269static
270void pthread_error ( const char* msg )
271{
272 int res;
273 VALGRIND_MAGIC_SEQUENCE(res, 0,
274 VG_USERREQ__PTHREAD_ERROR,
275 msg, 0, 0, 0);
276}
277
278
279/* ---------------------------------------------------
sewardj00a66b12002-10-12 16:42:35 +0000280 Here so it can be inlined without complaint.
281 ------------------------------------------------ */
282
283__inline__
284pthread_t pthread_self(void)
285{
286 int tid;
287 ensure_valgrind("pthread_self");
288 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
289 VG_USERREQ__PTHREAD_GET_THREADID,
290 0, 0, 0, 0);
291 if (tid < 1 || tid >= VG_N_THREADS)
292 barf("pthread_self: invalid ThreadId");
293 return tid;
294}
295
296
297/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000298 THREAD ATTRIBUTES
299 ------------------------------------------------ */
300
sewardj6af4b5d2002-04-16 04:40:49 +0000301int pthread_attr_init(pthread_attr_t *attr)
302{
sewardj7989d0c2002-05-28 11:00:01 +0000303 /* Just initialise the fields which we might look at. */
304 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj6af4b5d2002-04-16 04:40:49 +0000305 return 0;
306}
307
308int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
309{
sewardj7989d0c2002-05-28 11:00:01 +0000310 if (detachstate != PTHREAD_CREATE_JOINABLE
sewardj4dced352002-06-04 22:54:20 +0000311 && detachstate != PTHREAD_CREATE_DETACHED) {
312 pthread_error("pthread_attr_setdetachstate: "
313 "detachstate is invalid");
sewardj7989d0c2002-05-28 11:00:01 +0000314 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000315 }
sewardj7989d0c2002-05-28 11:00:01 +0000316 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000317 return 0;
318}
319
njn25e49d8e72002-09-23 09:36:25 +0000320int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
321{
322 *detachstate = attr->__detachstate;
323 return 0;
324}
325
sewardj30671ff2002-04-21 00:13:57 +0000326int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
327{
sewardj436e0582002-04-26 14:31:40 +0000328 static int moans = N_MOANS;
329 if (moans-- > 0)
330 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000331 return 0;
332}
sewardj6af4b5d2002-04-16 04:40:49 +0000333
sewardj0286dd52002-05-16 20:51:15 +0000334__attribute__((weak))
335int pthread_attr_setstacksize (pthread_attr_t *__attr,
336 size_t __stacksize)
337{
sewardja18e2102002-05-18 10:43:22 +0000338 size_t limit;
sewardj3d7c8d62002-06-04 20:59:16 +0000339 char buf[1024];
sewardj0286dd52002-05-16 20:51:15 +0000340 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000341 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
342 - 1000; /* paranoia */
343 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000344 return 0;
sewardj3d7c8d62002-06-04 20:59:16 +0000345 snprintf(buf, sizeof(buf), "pthread_attr_setstacksize: "
346 "requested size %d >= VG_PTHREAD_STACK_SIZE\n "
347 "edit vg_include.h and rebuild.", __stacksize);
348 buf[sizeof(buf)-1] = '\0'; /* Make sure it is zero terminated */
349 barf(buf);
sewardj0286dd52002-05-16 20:51:15 +0000350}
351
352
sewardj30671ff2002-04-21 00:13:57 +0000353/* This is completely bogus. */
354int pthread_attr_getschedparam(const pthread_attr_t *attr,
355 struct sched_param *param)
356{
sewardj436e0582002-04-26 14:31:40 +0000357 static int moans = N_MOANS;
358 if (moans-- > 0)
359 kludged("pthread_attr_getschedparam");
sewardj3e909ce2002-06-03 13:27:15 +0000360# ifdef HAVE_SCHED_PRIORITY
sewardj72d58482002-04-24 02:20:20 +0000361 if (param) param->sched_priority = 0; /* who knows */
362# else
sewardj30671ff2002-04-21 00:13:57 +0000363 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000364# endif
sewardj30671ff2002-04-21 00:13:57 +0000365 return 0;
366}
367
368int pthread_attr_setschedparam(pthread_attr_t *attr,
369 const struct sched_param *param)
370{
sewardj436e0582002-04-26 14:31:40 +0000371 static int moans = N_MOANS;
372 if (moans-- > 0)
373 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000374 return 0;
375}
376
377int pthread_attr_destroy(pthread_attr_t *attr)
378{
sewardj436e0582002-04-26 14:31:40 +0000379 static int moans = N_MOANS;
380 if (moans-- > 0)
381 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000382 return 0;
383}
sewardjf8f819e2002-04-17 23:21:37 +0000384
sewardj0d844232002-06-02 09:29:31 +0000385/* These are no-ops, as with LinuxThreads. */
386int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
387{
388 ensure_valgrind("pthread_attr_setscope");
389 if (scope == PTHREAD_SCOPE_SYSTEM)
390 return 0;
sewardj4dced352002-06-04 22:54:20 +0000391 pthread_error("pthread_attr_setscope: "
392 "invalid or unsupported scope");
sewardj0d844232002-06-02 09:29:31 +0000393 if (scope == PTHREAD_SCOPE_PROCESS)
394 return ENOTSUP;
395 return EINVAL;
396}
397
398int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
399{
400 ensure_valgrind("pthread_attr_setscope");
401 if (scope)
402 *scope = PTHREAD_SCOPE_SYSTEM;
403 return 0;
404}
405
sewardj64039bb2002-06-03 00:58:18 +0000406
407/* Pretty bogus. Avoid if possible. */
408int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
409{
410 int detached;
411 size_t limit;
412 ensure_valgrind("pthread_getattr_np");
413 kludged("pthread_getattr_np");
414 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
415 - 1000; /* paranoia */
416 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
417 attr->__schedpolicy = SCHED_OTHER;
418 attr->__schedparam.sched_priority = 0;
419 attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
420 attr->__scope = PTHREAD_SCOPE_SYSTEM;
421 attr->__guardsize = VKI_BYTES_PER_PAGE;
422 attr->__stackaddr = NULL;
423 attr->__stackaddr_set = 0;
424 attr->__stacksize = limit;
425 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
426 VG_USERREQ__SET_OR_GET_DETACH,
427 2 /* get */, thread, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000428 my_assert(detached == 0 || detached == 1);
sewardj64039bb2002-06-03 00:58:18 +0000429 if (detached)
430 attr->__detachstate = PTHREAD_CREATE_DETACHED;
431 return 0;
432}
433
434
435/* Bogus ... */
436int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
437 void ** stackaddr )
438{
439 ensure_valgrind("pthread_attr_getstackaddr");
440 kludged("pthread_attr_getstackaddr");
441 if (stackaddr)
442 *stackaddr = NULL;
443 return 0;
444}
445
446/* Not bogus (!) */
447int pthread_attr_getstacksize ( const pthread_attr_t * _attr,
448 size_t * __stacksize )
449{
450 size_t limit;
451 ensure_valgrind("pthread_attr_getstacksize");
452 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
453 - 1000; /* paranoia */
454 if (__stacksize)
455 *__stacksize = limit;
456 return 0;
457}
458
sewardja3be12f2002-06-17 12:19:44 +0000459int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
460{
461 if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
462 return EINVAL;
463 attr->__schedpolicy = policy;
464 return 0;
465}
466
467int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
468{
469 *policy = attr->__schedpolicy;
470 return 0;
471}
472
473
sewardj20917d82002-05-28 01:36:45 +0000474/* ---------------------------------------------------
475 Helper functions for running a thread
476 and for clearing up afterwards.
477 ------------------------------------------------ */
478
479/* All exiting threads eventually pass through here, bearing the
480 return value, or PTHREAD_CANCELED, in ret_val. */
481static
482__attribute__((noreturn))
483void thread_exit_wrapper ( void* ret_val )
484{
sewardj870497a2002-05-29 01:06:47 +0000485 int detached, res;
486 CleanupEntry cu;
487 pthread_key_t key;
sewardj00a66b12002-10-12 16:42:35 +0000488 void** specifics_ptr;
sewardj870497a2002-05-29 01:06:47 +0000489
sewardj20917d82002-05-28 01:36:45 +0000490 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000491 while (1) {
492 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
493 VG_USERREQ__CLEANUP_POP,
494 &cu, 0, 0, 0);
495 if (res == -1) break; /* stack empty */
sewardj2d94c112002-06-03 01:25:54 +0000496 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000497 if (0) printf("running exit cleanup handler");
498 cu.fn ( cu.arg );
499 }
500
sewardj870497a2002-05-29 01:06:47 +0000501 /* Run this thread's key finalizers. Really this should be run
502 PTHREAD_DESTRUCTOR_ITERATIONS times. */
503 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
504 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
505 VG_USERREQ__GET_KEY_D_AND_S,
506 key, &cu, 0, 0 );
507 if (res == 0) {
508 /* valid key */
509 if (cu.fn && cu.arg)
510 cu.fn /* destructor for key */
511 ( cu.arg /* specific for key for this thread */ );
512 continue;
513 }
sewardj2d94c112002-06-03 01:25:54 +0000514 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000515 }
sewardj20917d82002-05-28 01:36:45 +0000516
sewardj00a66b12002-10-12 16:42:35 +0000517 /* Free up my specifics space, if any. */
518 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
519 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
520 pthread_self(), 0, 0, 0);
521 my_assert(specifics_ptr != (void**)3);
522 my_assert(specifics_ptr != (void**)1); /* 1 means invalid thread */
523 if (specifics_ptr != NULL)
524 my_free(specifics_ptr);
525
sewardj20917d82002-05-28 01:36:45 +0000526 /* Decide on my final disposition. */
527 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
528 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000529 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000530 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000531
532 if (detached) {
533 /* Detached; I just quit right now. */
534 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
535 VG_USERREQ__QUIT, 0, 0, 0, 0);
536 } else {
537 /* Not detached; so I wait for a joiner. */
538 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
539 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
540 }
541 /* NOTREACHED */
542 barf("thread_exit_wrapper: still alive?!");
543}
544
545
546/* This function is a wrapper function for running a thread. It runs
547 the root function specified in pthread_create, and then, should the
548 root function return a value, it arranges to run the thread's
549 cleanup handlers and exit correctly. */
550
sewardj728a5272002-06-20 10:25:37 +0000551/* Struct used to convey info from pthread_create to thread_wrapper.
552 Must be careful not to pass to the child thread any pointers to
553 objects which might be on the parent's stack. */
sewardj20917d82002-05-28 01:36:45 +0000554typedef
555 struct {
sewardj728a5272002-06-20 10:25:37 +0000556 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000557 void* (*root_fn) ( void* );
558 void* arg;
559 }
560 NewThreadInfo;
561
562
563/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
564 not return. Note that this runs in the new thread, not the
565 parent. */
566static
567__attribute__((noreturn))
568void thread_wrapper ( NewThreadInfo* info )
569{
sewardj728a5272002-06-20 10:25:37 +0000570 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000571 void* (*root_fn) ( void* );
572 void* arg;
573 void* ret_val;
574
sewardj728a5272002-06-20 10:25:37 +0000575 attr__detachstate = info->attr__detachstate;
576 root_fn = info->root_fn;
577 arg = info->arg;
sewardj20917d82002-05-28 01:36:45 +0000578
sewardj20917d82002-05-28 01:36:45 +0000579 /* Free up the arg block that pthread_create malloced. */
sewardj00a66b12002-10-12 16:42:35 +0000580 my_free(info);
sewardj20917d82002-05-28 01:36:45 +0000581
sewardj7989d0c2002-05-28 11:00:01 +0000582 /* Minimally observe the attributes supplied. */
sewardj728a5272002-06-20 10:25:37 +0000583 if (attr__detachstate != PTHREAD_CREATE_DETACHED
584 && attr__detachstate != PTHREAD_CREATE_JOINABLE)
585 pthread_error("thread_wrapper: invalid attr->__detachstate");
586 if (attr__detachstate == PTHREAD_CREATE_DETACHED)
587 pthread_detach(pthread_self());
sewardj7989d0c2002-05-28 11:00:01 +0000588
sewardj00a66b12002-10-12 16:42:35 +0000589# ifdef GLIBC_2_3
590 /* Set this thread's locale to the global (default) locale. A hack
591 in support of glibc-2.3. This does the biz for the all new
592 threads; the root thread is done with a horrible hack in
593 init_libc_tsd_keys() below.
594 */
595 __uselocale(LC_GLOBAL_LOCALE);
596# endif
597
sewardj20917d82002-05-28 01:36:45 +0000598 /* The root function might not return. But if it does we simply
599 move along to thread_exit_wrapper. All other ways out for the
600 thread (cancellation, or calling pthread_exit) lead there
601 too. */
602 ret_val = root_fn(arg);
603 thread_exit_wrapper(ret_val);
604 /* NOTREACHED */
605}
606
607
sewardjf8f819e2002-04-17 23:21:37 +0000608/* ---------------------------------------------------
609 THREADs
610 ------------------------------------------------ */
611
sewardjff42d1d2002-05-22 13:17:31 +0000612__attribute__((weak))
613int pthread_yield ( void )
614{
615 int res;
616 ensure_valgrind("pthread_yield");
617 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
618 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
619 return 0;
620}
621
622
sewardj6072c362002-04-19 14:40:57 +0000623int pthread_equal(pthread_t thread1, pthread_t thread2)
624{
625 return thread1 == thread2 ? 1 : 0;
626}
627
628
sewardj20917d82002-05-28 01:36:45 +0000629/* Bundle up the args into a malloc'd block and create a new thread
630 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000631int
sewardj1462c8b2002-07-24 09:41:52 +0000632pthread_create (pthread_t *__restrict __thredd,
sewardje663cb92002-04-12 10:26:32 +0000633 __const pthread_attr_t *__restrict __attr,
634 void *(*__start_routine) (void *),
635 void *__restrict __arg)
636{
sewardj20917d82002-05-28 01:36:45 +0000637 int tid_child;
638 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000639
sewardj20917d82002-05-28 01:36:45 +0000640 ensure_valgrind("pthread_create");
641
sewardj00a66b12002-10-12 16:42:35 +0000642 /* make sure the tsd keys, and hence locale info, are initialised
643 before we get into complications making new threads. */
644 init_libc_tsd_keys();
645
sewardj20917d82002-05-28 01:36:45 +0000646 /* Allocate space for the arg block. thread_wrapper will free
647 it. */
sewardj00a66b12002-10-12 16:42:35 +0000648 info = my_malloc(sizeof(NewThreadInfo));
sewardj2d94c112002-06-03 01:25:54 +0000649 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000650
sewardj728a5272002-06-20 10:25:37 +0000651 if (__attr)
652 info->attr__detachstate = __attr->__detachstate;
653 else
654 info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
655
sewardj20917d82002-05-28 01:36:45 +0000656 info->root_fn = __start_routine;
657 info->arg = __arg;
658 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
659 VG_USERREQ__APPLY_IN_NEW_THREAD,
660 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000661 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000662
sewardj1462c8b2002-07-24 09:41:52 +0000663 if (__thredd)
664 *__thredd = tid_child;
sewardj20917d82002-05-28 01:36:45 +0000665 return 0; /* success */
666}
sewardje663cb92002-04-12 10:26:32 +0000667
668
669int
670pthread_join (pthread_t __th, void **__thread_return)
671{
672 int res;
673 ensure_valgrind("pthread_join");
674 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
675 VG_USERREQ__PTHREAD_JOIN,
676 __th, __thread_return, 0, 0);
677 return res;
678}
679
680
sewardj3b5d8862002-04-20 13:53:23 +0000681void pthread_exit(void *retval)
682{
sewardj3b5d8862002-04-20 13:53:23 +0000683 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000684 /* Simple! */
685 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000686}
687
sewardje663cb92002-04-12 10:26:32 +0000688
sewardj853f55d2002-04-26 00:27:53 +0000689int pthread_detach(pthread_t th)
690{
sewardj20917d82002-05-28 01:36:45 +0000691 int res;
692 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000693 /* First we enquire as to the current detach state. */
694 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000695 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000696 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000697 if (res == -1) {
698 /* not found */
699 pthread_error("pthread_detach: "
700 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000701 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000702 }
703 if (res == 1) {
704 /* already detached */
705 pthread_error("pthread_detach: "
706 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000707 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000708 }
sewardj7989d0c2002-05-28 11:00:01 +0000709 if (res == 0) {
710 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
711 VG_USERREQ__SET_OR_GET_DETACH,
712 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000713 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000714 return 0;
715 }
716 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000717}
718
719
sewardjf8f819e2002-04-17 23:21:37 +0000720/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000721 CLEANUP STACKS
722 ------------------------------------------------ */
723
724void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
725 void (*__routine) (void *),
726 void *__arg)
727{
728 int res;
729 CleanupEntry cu;
730 ensure_valgrind("_pthread_cleanup_push");
731 cu.fn = __routine;
732 cu.arg = __arg;
733 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
734 VG_USERREQ__CLEANUP_PUSH,
735 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000736 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000737}
738
739
740void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
741 void (*__routine) (void *),
742 void *__arg)
743{
744 /* As _pthread_cleanup_push, but first save the thread's original
745 cancellation type in __buffer and set it to Deferred. */
746 int orig_ctype;
747 ensure_valgrind("_pthread_cleanup_push_defer");
748 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000749 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
750 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
751 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000752 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
753 VG_USERREQ__SET_CANCELTYPE,
754 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000755 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000756 *((int*)(__buffer)) = orig_ctype;
757 /* Now push the cleanup. */
758 _pthread_cleanup_push(NULL, __routine, __arg);
759}
760
761
762void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
763 int __execute)
764{
765 int res;
766 CleanupEntry cu;
767 ensure_valgrind("_pthread_cleanup_push");
768 cu.fn = cu.arg = NULL; /* paranoia */
769 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
770 VG_USERREQ__CLEANUP_POP,
771 &cu, 0, 0, 0);
772 if (res == 0) {
773 /* pop succeeded */
774 if (__execute) {
775 cu.fn ( cu.arg );
776 }
777 return;
778 }
779 if (res == -1) {
780 /* stack underflow */
781 return;
782 }
783 barf("_pthread_cleanup_pop");
784}
785
786
787void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
788 int __execute)
789{
790 int orig_ctype, fake_ctype;
791 /* As _pthread_cleanup_pop, but after popping/running the handler,
792 restore the thread's original cancellation type from the first
793 word of __buffer. */
794 _pthread_cleanup_pop(NULL, __execute);
795 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000796 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000797 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000798 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
799 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
800 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000801 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
802 VG_USERREQ__SET_CANCELTYPE,
803 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000804 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000805}
806
807
808/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000809 MUTEX ATTRIBUTES
810 ------------------------------------------------ */
811
sewardj5905fae2002-04-26 13:25:00 +0000812int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000813{
sewardjf8f819e2002-04-17 23:21:37 +0000814 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000815 return 0;
sewardje663cb92002-04-12 10:26:32 +0000816}
817
sewardj5905fae2002-04-26 13:25:00 +0000818int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000819{
820 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000821# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000822 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000823 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000824# endif
sewardja1679dd2002-05-10 22:31:40 +0000825# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000826 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000827# endif
sewardjf8f819e2002-04-17 23:21:37 +0000828 case PTHREAD_MUTEX_RECURSIVE_NP:
829 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000830 attr->__mutexkind = type;
831 return 0;
832 default:
sewardj4dced352002-06-04 22:54:20 +0000833 pthread_error("pthread_mutexattr_settype: "
834 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000835 return EINVAL;
836 }
837}
838
sewardj5905fae2002-04-26 13:25:00 +0000839int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000840{
841 return 0;
842}
843
844
845/* ---------------------------------------------------
846 MUTEXes
847 ------------------------------------------------ */
848
sewardj5905fae2002-04-26 13:25:00 +0000849int __pthread_mutex_init(pthread_mutex_t *mutex,
850 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000851{
sewardj604ec3c2002-04-18 22:38:41 +0000852 mutex->__m_count = 0;
853 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
854 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
855 if (mutexattr)
856 mutex->__m_kind = mutexattr->__mutexkind;
857 return 0;
sewardje663cb92002-04-12 10:26:32 +0000858}
859
sewardj439d45e2002-05-03 20:43:10 +0000860
sewardj5905fae2002-04-26 13:25:00 +0000861int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000862{
863 int res;
sewardj436e0582002-04-26 14:31:40 +0000864 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000865 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000866 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
867 VG_USERREQ__PTHREAD_MUTEX_LOCK,
868 mutex, 0, 0, 0);
869 return res;
sewardj439d45e2002-05-03 20:43:10 +0000870 } else {
871 if (moans-- > 0)
872 not_inside("pthread_mutex_lock");
873 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000874 }
875}
876
sewardj439d45e2002-05-03 20:43:10 +0000877
sewardj5905fae2002-04-26 13:25:00 +0000878int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000879{
880 int res;
sewardj436e0582002-04-26 14:31:40 +0000881 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000882 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000883 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
884 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
885 mutex, 0, 0, 0);
886 return res;
sewardj439d45e2002-05-03 20:43:10 +0000887 } else {
888 if (moans-- > 0)
889 not_inside("pthread_mutex_trylock");
890 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000891 }
892}
893
sewardj439d45e2002-05-03 20:43:10 +0000894
sewardj5905fae2002-04-26 13:25:00 +0000895int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000896{
897 int res;
sewardj436e0582002-04-26 14:31:40 +0000898 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000899 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000900 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
901 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
902 mutex, 0, 0, 0);
903 return res;
sewardj439d45e2002-05-03 20:43:10 +0000904 } else {
905 if (moans-- > 0)
906 not_inside("pthread_mutex_unlock");
907 return 0;
sewardje663cb92002-04-12 10:26:32 +0000908 }
909}
910
sewardj439d45e2002-05-03 20:43:10 +0000911
sewardj5905fae2002-04-26 13:25:00 +0000912int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000913{
sewardj604ec3c2002-04-18 22:38:41 +0000914 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
915 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +0000916 if (mutex->__m_count > 0) {
917 pthread_error("pthread_mutex_destroy: "
918 "mutex is still in use");
sewardj604ec3c2002-04-18 22:38:41 +0000919 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +0000920 }
921 mutex->__m_count = 0;
922 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
923 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
924 return 0;
sewardje663cb92002-04-12 10:26:32 +0000925}
926
927
sewardjf8f819e2002-04-17 23:21:37 +0000928/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000929 CONDITION VARIABLES
930 ------------------------------------------------ */
931
932/* LinuxThreads supports no attributes for conditions. Hence ... */
933
934int pthread_condattr_init(pthread_condattr_t *attr)
935{
936 return 0;
937}
938
sewardj0738a592002-04-20 13:59:33 +0000939int pthread_condattr_destroy(pthread_condattr_t *attr)
940{
941 return 0;
942}
sewardj6072c362002-04-19 14:40:57 +0000943
944int pthread_cond_init( pthread_cond_t *cond,
945 const pthread_condattr_t *cond_attr)
946{
947 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
948 return 0;
949}
950
sewardjf854f472002-04-21 12:19:41 +0000951int pthread_cond_destroy(pthread_cond_t *cond)
952{
953 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000954 static int moans = N_MOANS;
955 if (moans-- > 0)
956 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000957 return 0;
958}
sewardj6072c362002-04-19 14:40:57 +0000959
960/* ---------------------------------------------------
961 SCHEDULING
962 ------------------------------------------------ */
963
964/* This is completely bogus. */
965int pthread_getschedparam(pthread_t target_thread,
966 int *policy,
967 struct sched_param *param)
968{
sewardj436e0582002-04-26 14:31:40 +0000969 static int moans = N_MOANS;
970 if (moans-- > 0)
971 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000972 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +0000973# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +0000974 if (param) param->sched_priority = 0; /* who knows */
975# else
sewardj6072c362002-04-19 14:40:57 +0000976 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000977# endif
sewardj6072c362002-04-19 14:40:57 +0000978 return 0;
979}
980
981int pthread_setschedparam(pthread_t target_thread,
982 int policy,
983 const struct sched_param *param)
984{
sewardj436e0582002-04-26 14:31:40 +0000985 static int moans = N_MOANS;
986 if (moans-- > 0)
987 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000988 return 0;
989}
990
sewardj3b5d8862002-04-20 13:53:23 +0000991int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
992{
993 int res;
994 ensure_valgrind("pthread_cond_wait");
995 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
996 VG_USERREQ__PTHREAD_COND_WAIT,
997 cond, mutex, 0, 0);
998 return res;
999}
1000
sewardj5f07b662002-04-23 16:52:51 +00001001int pthread_cond_timedwait ( pthread_cond_t *cond,
1002 pthread_mutex_t *mutex,
1003 const struct timespec *abstime )
1004{
1005 int res;
1006 unsigned int ms_now, ms_end;
1007 struct timeval timeval_now;
1008 unsigned long long int ull_ms_now_after_1970;
1009 unsigned long long int ull_ms_end_after_1970;
1010
1011 ensure_valgrind("pthread_cond_timedwait");
1012 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1013 VG_USERREQ__READ_MILLISECOND_TIMER,
1014 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001015 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001016 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +00001017 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001018
1019 ull_ms_now_after_1970
1020 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
1021 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
1022 ull_ms_end_after_1970
1023 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
1024 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +00001025 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
1026 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +00001027 ms_end
1028 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
1029 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1030 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
1031 cond, mutex, ms_end, 0);
1032 return res;
1033}
1034
1035
sewardj3b5d8862002-04-20 13:53:23 +00001036int pthread_cond_signal(pthread_cond_t *cond)
1037{
1038 int res;
1039 ensure_valgrind("pthread_cond_signal");
1040 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1041 VG_USERREQ__PTHREAD_COND_SIGNAL,
1042 cond, 0, 0, 0);
1043 return res;
1044}
1045
1046int pthread_cond_broadcast(pthread_cond_t *cond)
1047{
1048 int res;
1049 ensure_valgrind("pthread_cond_broadcast");
1050 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1051 VG_USERREQ__PTHREAD_COND_BROADCAST,
1052 cond, 0, 0, 0);
1053 return res;
1054}
1055
sewardj6072c362002-04-19 14:40:57 +00001056
1057/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001058 CANCELLATION
1059 ------------------------------------------------ */
1060
sewardj853f55d2002-04-26 00:27:53 +00001061int pthread_setcancelstate(int state, int *oldstate)
1062{
sewardj20917d82002-05-28 01:36:45 +00001063 int res;
1064 ensure_valgrind("pthread_setcancelstate");
1065 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +00001066 && state != PTHREAD_CANCEL_DISABLE) {
1067 pthread_error("pthread_setcancelstate: "
1068 "invalid state");
sewardj20917d82002-05-28 01:36:45 +00001069 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001070 }
sewardj2d94c112002-06-03 01:25:54 +00001071 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1072 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001073 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1074 VG_USERREQ__SET_CANCELSTATE,
1075 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001076 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001077 if (oldstate)
1078 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001079 return 0;
1080}
1081
sewardje663cb92002-04-12 10:26:32 +00001082int pthread_setcanceltype(int type, int *oldtype)
1083{
sewardj20917d82002-05-28 01:36:45 +00001084 int res;
1085 ensure_valgrind("pthread_setcanceltype");
1086 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001087 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1088 pthread_error("pthread_setcanceltype: "
1089 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001090 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001091 }
sewardj2d94c112002-06-03 01:25:54 +00001092 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1093 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001094 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1095 VG_USERREQ__SET_CANCELTYPE,
1096 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001097 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001098 if (oldtype)
1099 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001100 return 0;
1101}
1102
sewardje663cb92002-04-12 10:26:32 +00001103int pthread_cancel(pthread_t thread)
1104{
1105 int res;
1106 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001107 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1108 VG_USERREQ__SET_CANCELPEND,
1109 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001110 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001111 return res;
1112}
1113
sewardjd140e442002-05-29 01:21:19 +00001114static __inline__
1115void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001116{
sewardj20917d82002-05-28 01:36:45 +00001117 int res;
njn25e49d8e72002-09-23 09:36:25 +00001118 ensure_valgrind("__my_pthread_testcancel");
sewardj20917d82002-05-28 01:36:45 +00001119 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1120 VG_USERREQ__TESTCANCEL,
1121 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001122 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001123}
1124
sewardjd140e442002-05-29 01:21:19 +00001125void pthread_testcancel ( void )
1126{
1127 __my_pthread_testcancel();
1128}
1129
sewardj20917d82002-05-28 01:36:45 +00001130
sewardjef037c72002-05-30 00:40:03 +00001131/* Not really sure what this is for. I suspect for doing the POSIX
1132 requirements for fork() and exec(). We do this internally anyway
1133 whenever those syscalls are observed, so this could be superfluous,
1134 but hey ...
1135*/
sewardj853f55d2002-04-26 00:27:53 +00001136void __pthread_kill_other_threads_np ( void )
1137{
sewardjef037c72002-05-30 00:40:03 +00001138 int res;
1139 ensure_valgrind("__pthread_kill_other_threads_np");
1140 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1141 VG_USERREQ__NUKE_OTHER_THREADS,
1142 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001143 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001144}
1145
sewardje663cb92002-04-12 10:26:32 +00001146
sewardjf8f819e2002-04-17 23:21:37 +00001147/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001148 SIGNALS
1149 ------------------------------------------------ */
1150
1151#include <signal.h>
1152
1153int pthread_sigmask(int how, const sigset_t *newmask,
1154 sigset_t *oldmask)
1155{
1156 int res;
1157
1158 /* A bit subtle, because the scheduler expects newmask and oldmask
1159 to be vki_sigset_t* rather than sigset_t*, and the two are
1160 different. Fortunately the first 64 bits of a sigset_t are
1161 exactly a vki_sigset_t, so we just pass the pointers through
1162 unmodified. Haaaack!
1163
1164 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001165 constants to VKI_ constants, so that the former do not have to
1166 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001167
1168 ensure_valgrind("pthread_sigmask");
1169
1170 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001171 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1172 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1173 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001174 default: pthread_error("pthread_sigmask: invalid how");
1175 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001176 }
1177
1178 /* Crude check */
1179 if (newmask == NULL)
1180 return EFAULT;
1181
1182 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1183 VG_USERREQ__PTHREAD_SIGMASK,
1184 how, newmask, oldmask, 0);
1185
1186 /* The scheduler tells us of any memory violations. */
1187 return res == 0 ? 0 : EFAULT;
1188}
1189
1190
1191int sigwait ( const sigset_t* set, int* sig )
1192{
1193 int res;
1194 ensure_valgrind("sigwait");
1195 /* As with pthread_sigmask we deliberately confuse sigset_t with
1196 vki_ksigset_t. */
1197 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1198 VG_USERREQ__SIGWAIT,
1199 set, sig, 0, 0);
1200 return res;
1201}
1202
1203
sewardj018f7622002-05-15 21:13:39 +00001204int pthread_kill(pthread_t thread, int signo)
1205{
1206 int res;
1207 ensure_valgrind("pthread_kill");
1208 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1209 VG_USERREQ__PTHREAD_KILL,
1210 thread, signo, 0, 0);
1211 return res;
1212}
1213
1214
sewardj3665ded2002-05-16 16:57:25 +00001215/* Copied verbatim from Linuxthreads */
1216/* Redefine raise() to send signal to calling thread only,
1217 as per POSIX 1003.1c */
1218int raise (int sig)
1219{
1220 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001221 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001222 return 0;
sewardj4dced352002-06-04 22:54:20 +00001223 } else {
sewardj3665ded2002-05-16 16:57:25 +00001224 errno = retcode;
1225 return -1;
1226 }
1227}
1228
1229
sewardj9a2224b2002-06-19 10:17:40 +00001230int pause ( void )
1231{
1232 unsigned int n_orig, n_now;
1233 struct vki_timespec nanosleep_interval;
1234 ensure_valgrind("pause");
1235
1236 /* This is surely a cancellation point. */
1237 __my_pthread_testcancel();
1238
1239 VALGRIND_MAGIC_SEQUENCE(n_orig, 0xFFFFFFFF /* default */,
1240 VG_USERREQ__GET_N_SIGS_RETURNED,
1241 0, 0, 0, 0);
1242 my_assert(n_orig != 0xFFFFFFFF);
1243
1244 while (1) {
1245 VALGRIND_MAGIC_SEQUENCE(n_now, 0xFFFFFFFF /* default */,
1246 VG_USERREQ__GET_N_SIGS_RETURNED,
1247 0, 0, 0, 0);
1248 my_assert(n_now != 0xFFFFFFFF);
1249 my_assert(n_now >= n_orig);
1250 if (n_now != n_orig) break;
1251
1252 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001253 nanosleep_interval.tv_nsec = 12 * 1000 * 1000; /* 12 milliseconds */
sewardj9a2224b2002-06-19 10:17:40 +00001254 /* It's critical here that valgrind's nanosleep implementation
1255 is nonblocking. */
1256 (void)my_do_syscall2(__NR_nanosleep,
1257 (int)(&nanosleep_interval), (int)NULL);
1258 }
1259
1260 * (__errno_location()) = EINTR;
1261 return -1;
1262}
1263
1264
sewardjb48e5002002-05-13 00:16:03 +00001265/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001266 THREAD-SPECIFICs
1267 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001268
sewardj00a66b12002-10-12 16:42:35 +00001269static
1270int key_is_valid (pthread_key_t key)
1271{
1272 int res;
1273 VALGRIND_MAGIC_SEQUENCE(res, 2 /* default */,
1274 VG_USERREQ__PTHREAD_KEY_VALIDATE,
1275 key, 0, 0, 0);
1276 my_assert(res != 2);
1277 return res;
1278}
1279
1280
1281/* Returns NULL if thread is invalid. Otherwise, if the thread
1282 already has a specifics area, return that. Otherwise allocate it
1283 one. */
1284static
1285void** get_or_allocate_specifics_ptr ( pthread_t thread )
1286{
1287 int res, i;
1288 void** specifics_ptr;
1289 ensure_valgrind("get_or_allocate_specifics_ptr");
1290
1291 /* Returns zero if the thread has no specific_ptr. One if thread
1292 is invalid. Otherwise, the specific_ptr value. This is
1293 allocated with my_malloc and so is aligned and cannot be
1294 confused with 1 or 3. */
1295 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
1296 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
1297 thread, 0, 0, 0);
1298 my_assert(specifics_ptr != (void**)3);
1299
1300 if (specifics_ptr == (void**)1)
1301 return NULL; /* invalid thread */
1302
1303 if (specifics_ptr != NULL)
1304 return specifics_ptr; /* already has a specifics ptr. */
1305
1306 /* None yet ... allocate a new one. Should never fail. */
1307 specifics_ptr = my_malloc( VG_N_THREAD_KEYS * sizeof(void*) );
1308 my_assert(specifics_ptr != NULL);
1309
1310 VALGRIND_MAGIC_SEQUENCE(res, -1 /* default */,
1311 VG_USERREQ__PTHREAD_SETSPECIFIC_PTR,
1312 specifics_ptr, 0, 0, 0);
1313 my_assert(res == 0);
1314
1315 /* POSIX sez: "Upon thread creation, the value NULL shall be
1316 associated with all defined keys in the new thread." This
1317 allocation is in effect a delayed allocation of the specific
1318 data for a thread, at its first-use. Hence we initialise it
1319 here. */
1320 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
1321 specifics_ptr[i] = NULL;
1322 }
1323
1324 return specifics_ptr;
1325}
1326
1327
sewardj5905fae2002-04-26 13:25:00 +00001328int __pthread_key_create(pthread_key_t *key,
1329 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001330{
sewardj00a66b12002-10-12 16:42:35 +00001331 void** specifics_ptr;
1332 int res, i;
sewardj5f07b662002-04-23 16:52:51 +00001333 ensure_valgrind("pthread_key_create");
sewardj00a66b12002-10-12 16:42:35 +00001334
1335 /* This writes *key if successful. It should never fail. */
1336 VALGRIND_MAGIC_SEQUENCE(res, 1 /* default */,
sewardj5f07b662002-04-23 16:52:51 +00001337 VG_USERREQ__PTHREAD_KEY_CREATE,
1338 key, destr_function, 0, 0);
sewardj00a66b12002-10-12 16:42:35 +00001339 my_assert(res == 0);
1340
1341 /* POSIX sez: "Upon key creation, the value NULL shall be
1342 associated with the new key in all active threads." */
1343 for (i = 0; i < VG_N_THREADS; i++) {
1344 specifics_ptr = get_or_allocate_specifics_ptr(i);
1345 /* we get NULL if i is an invalid thread. */
1346 if (specifics_ptr != NULL)
1347 specifics_ptr[*key] = NULL;
1348 }
1349
sewardj5f07b662002-04-23 16:52:51 +00001350 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001351}
1352
1353int pthread_key_delete(pthread_key_t key)
1354{
sewardj00a66b12002-10-12 16:42:35 +00001355 int res;
1356 ensure_valgrind("pthread_key_create");
1357 if (!key_is_valid(key))
1358 return EINVAL;
1359 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1360 VG_USERREQ__PTHREAD_KEY_DELETE,
1361 key, 0, 0, 0);
1362 my_assert(res == 0);
sewardj5e5fa512002-04-14 13:13:05 +00001363 return 0;
1364}
1365
sewardj5905fae2002-04-26 13:25:00 +00001366int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001367{
sewardj00a66b12002-10-12 16:42:35 +00001368 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001369 ensure_valgrind("pthread_setspecific");
sewardj00a66b12002-10-12 16:42:35 +00001370
1371 if (!key_is_valid(key))
1372 return EINVAL;
1373
1374 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1375 specifics_ptr[key] = (void*)pointer;
1376 return 0;
sewardj5e5fa512002-04-14 13:13:05 +00001377}
1378
sewardj5905fae2002-04-26 13:25:00 +00001379void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001380{
sewardj00a66b12002-10-12 16:42:35 +00001381 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001382 ensure_valgrind("pthread_getspecific");
sewardj00a66b12002-10-12 16:42:35 +00001383
1384 if (!key_is_valid(key))
1385 return NULL;
1386
1387 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1388 return specifics_ptr[key];
1389}
1390
1391
1392static
1393void ** __pthread_getspecific_addr(pthread_key_t key)
1394{
1395 void** specifics_ptr;
1396 ensure_valgrind("pthread_getspecific_addr");
1397
1398 if (!key_is_valid(key))
1399 return NULL;
1400
1401 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1402 return &(specifics_ptr[key]);
sewardj5e5fa512002-04-14 13:13:05 +00001403}
1404
sewardjf8f819e2002-04-17 23:21:37 +00001405
1406/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001407 ONCEry
1408 ------------------------------------------------ */
1409
1410static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1411
1412
sewardj5905fae2002-04-26 13:25:00 +00001413int __pthread_once ( pthread_once_t *once_control,
1414 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001415{
1416 int res;
1417 ensure_valgrind("pthread_once");
1418
sewardj68b2dd92002-05-10 21:03:56 +00001419 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001420
sewardj68b2dd92002-05-10 21:03:56 +00001421 if (res != 0) {
sewardj89d3d852002-04-24 19:21:39 +00001422 barf("pthread_once: Looks like your program's "
1423 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001424 }
sewardj89d3d852002-04-24 19:21:39 +00001425
1426 if (*once_control == 0) {
1427 *once_control = 1;
1428 init_routine();
1429 }
1430
sewardj68b2dd92002-05-10 21:03:56 +00001431 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001432
1433 return 0;
1434}
1435
1436
1437/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001438 MISC
1439 ------------------------------------------------ */
1440
sewardj2cb00342002-06-28 01:46:26 +00001441static pthread_mutex_t pthread_atfork_lock
1442 = PTHREAD_MUTEX_INITIALIZER;
1443
sewardj5905fae2002-04-26 13:25:00 +00001444int __pthread_atfork ( void (*prepare)(void),
1445 void (*parent)(void),
1446 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001447{
sewardj2cb00342002-06-28 01:46:26 +00001448 int n, res;
1449 ForkHandlerEntry entry;
1450
1451 ensure_valgrind("pthread_atfork");
1452 __pthread_mutex_lock(&pthread_atfork_lock);
1453
1454 /* Fetch old counter */
1455 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1456 VG_USERREQ__GET_FHSTACK_USED,
1457 0, 0, 0, 0);
1458 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1459 if (n == VG_N_FORKHANDLERSTACK-1)
1460 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1461 "increase and recompile");
1462
1463 /* Add entry */
1464 entry.prepare = *prepare;
1465 entry.parent = *parent;
1466 entry.child = *child;
1467 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1468 VG_USERREQ__SET_FHSTACK_ENTRY,
1469 n, &entry, 0, 0);
1470 my_assert(res == 0);
1471
1472 /* Bump counter */
1473 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1474 VG_USERREQ__SET_FHSTACK_USED,
1475 n+1, 0, 0, 0);
1476 my_assert(res == 0);
1477
1478 __pthread_mutex_unlock(&pthread_atfork_lock);
1479 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001480}
1481
1482
sewardjbb990782002-05-08 02:01:14 +00001483__attribute__((weak))
1484void __pthread_initialize ( void )
1485{
sewardjbea1caa2002-05-10 23:20:58 +00001486 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001487}
1488
1489
sewardj853f55d2002-04-26 00:27:53 +00001490/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001491 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001492 ------------------------------------------------ */
1493
sewardj3b13f0e2002-04-25 20:17:29 +00001494#include <resolv.h>
1495static int thread_specific_errno[VG_N_THREADS];
1496static int thread_specific_h_errno[VG_N_THREADS];
1497static struct __res_state
1498 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001499
sewardj3b13f0e2002-04-25 20:17:29 +00001500int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001501{
1502 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001503 /* ensure_valgrind("__errno_location"); */
1504 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001505 VG_USERREQ__PTHREAD_GET_THREADID,
1506 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001507 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001508 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001509 barf("__errno_location: invalid ThreadId");
1510 return & thread_specific_errno[tid];
1511}
1512
1513int* __h_errno_location ( void )
1514{
1515 int tid;
1516 /* ensure_valgrind("__h_errno_location"); */
1517 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1518 VG_USERREQ__PTHREAD_GET_THREADID,
1519 0, 0, 0, 0);
1520 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001521 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001522 barf("__h_errno_location: invalid ThreadId");
1523 return & thread_specific_h_errno[tid];
1524}
1525
sewardjb0ff1032002-08-06 09:02:53 +00001526
1527#undef _res
1528extern struct __res_state _res;
1529
sewardj3b13f0e2002-04-25 20:17:29 +00001530struct __res_state* __res_state ( void )
1531{
1532 int tid;
1533 /* ensure_valgrind("__res_state"); */
1534 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1535 VG_USERREQ__PTHREAD_GET_THREADID,
1536 0, 0, 0, 0);
1537 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001538 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001539 barf("__res_state: invalid ThreadId");
sewardjb0ff1032002-08-06 09:02:53 +00001540 if (tid == 1)
1541 return & _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001542 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001543}
1544
1545
sewardj5716dbb2002-04-26 03:28:18 +00001546/* ---------------------------------------------------
1547 LIBC-PRIVATE SPECIFIC DATA
1548 ------------------------------------------------ */
1549
1550/* Relies on assumption that initial private data is NULL. This
1551 should be fixed somehow. */
1552
njn25e49d8e72002-09-23 09:36:25 +00001553/* The allowable keys (indices) (all 3 of them).
sewardj5716dbb2002-04-26 03:28:18 +00001554 From sysdeps/pthread/bits/libc-tsd.h
1555*/
sewardjcb7f08a2002-10-02 09:41:49 +00001556/* as per glibc anoncvs HEAD of 20021001. */
sewardj5716dbb2002-04-26 03:28:18 +00001557enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1558 _LIBC_TSD_KEY_DL_ERROR,
njn25e49d8e72002-09-23 09:36:25 +00001559 _LIBC_TSD_KEY_RPC_VARS,
sewardjcb7f08a2002-10-02 09:41:49 +00001560 _LIBC_TSD_KEY_LOCALE,
1561 _LIBC_TSD_KEY_CTYPE_B,
1562 _LIBC_TSD_KEY_CTYPE_TOLOWER,
1563 _LIBC_TSD_KEY_CTYPE_TOUPPER,
sewardj5716dbb2002-04-26 03:28:18 +00001564 _LIBC_TSD_KEY_N };
1565
1566/* Auto-initialising subsystem. libc_specifics_inited is set
1567 after initialisation. libc_specifics_inited_mx guards it. */
1568static int libc_specifics_inited = 0;
1569static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1570
sewardj00a66b12002-10-12 16:42:35 +00001571
sewardj5716dbb2002-04-26 03:28:18 +00001572/* These are the keys we must initialise the first time. */
sewardjcb7f08a2002-10-02 09:41:49 +00001573static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N];
sewardj5716dbb2002-04-26 03:28:18 +00001574
sewardj00a66b12002-10-12 16:42:35 +00001575
sewardjcb7f08a2002-10-02 09:41:49 +00001576/* Initialise the keys, if they are not already initialised. */
sewardj5716dbb2002-04-26 03:28:18 +00001577static
1578void init_libc_tsd_keys ( void )
1579{
1580 int res, i;
1581 pthread_key_t k;
1582
sewardj08c7f012002-10-07 23:56:55 +00001583 /* Don't fall into deadlock if we get called again whilst we still
1584 hold the lock, via the __uselocale() call herein. */
1585 if (libc_specifics_inited != 0)
1586 return;
1587
1588 /* Take the lock. */
sewardj00a66b12002-10-12 16:42:35 +00001589 res = __pthread_mutex_lock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001590 if (res != 0) barf("init_libc_tsd_keys: lock");
1591
sewardj08c7f012002-10-07 23:56:55 +00001592 /* Now test again, to be sure there is no mistake. */
1593 if (libc_specifics_inited != 0) {
sewardj00a66b12002-10-12 16:42:35 +00001594 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj08c7f012002-10-07 23:56:55 +00001595 if (res != 0) barf("init_libc_tsd_keys: unlock(1)");
1596 return;
sewardj5716dbb2002-04-26 03:28:18 +00001597 }
1598
sewardj08c7f012002-10-07 23:56:55 +00001599 /* Actually do the initialisation. */
1600 /* printf("INIT libc specifics\n"); */
1601 for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
sewardj00a66b12002-10-12 16:42:35 +00001602 res = __pthread_key_create(&k, NULL);
sewardj08c7f012002-10-07 23:56:55 +00001603 if (res != 0) barf("init_libc_tsd_keys: create");
1604 libc_specifics_keys[i] = k;
1605 }
1606
1607 /* Signify init done. */
1608 libc_specifics_inited = 1;
1609
1610# ifdef GLIBC_2_3
1611 /* Set the initialising thread's locale to the global (default)
sewardj00a66b12002-10-12 16:42:35 +00001612 locale. A hack in support of glibc-2.3. This does the biz for
1613 the root thread. For all other threads we run this in
1614 thread_wrapper(), which does the real work of
1615 pthread_create(). */
1616 /* assert that we are the root thread. I don't know if this is
1617 really a valid assertion to make; if it breaks I'll reconsider
1618 it. */
1619 my_assert(pthread_self() == 1);
sewardj08c7f012002-10-07 23:56:55 +00001620 __uselocale(LC_GLOBAL_LOCALE);
1621# endif
1622
1623 /* Unlock and return. */
sewardj00a66b12002-10-12 16:42:35 +00001624 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001625 if (res != 0) barf("init_libc_tsd_keys: unlock");
1626}
1627
1628
1629static int
1630libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1631 const void * pointer )
1632{
sewardjcb7f08a2002-10-02 09:41:49 +00001633 int res;
sewardj5716dbb2002-04-26 03:28:18 +00001634 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardjcb7f08a2002-10-02 09:41:49 +00001635 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001636 barf("libc_internal_tsd_set: invalid key");
1637 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001638 res = __pthread_setspecific(libc_specifics_keys[key], pointer);
sewardj5716dbb2002-04-26 03:28:18 +00001639 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1640 return 0;
1641}
1642
1643static void *
1644libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1645{
sewardjcb7f08a2002-10-02 09:41:49 +00001646 void* v;
sewardj5716dbb2002-04-26 03:28:18 +00001647 /* printf("GET GET GET key %d\n", key); */
sewardjcb7f08a2002-10-02 09:41:49 +00001648 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001649 barf("libc_internal_tsd_get: invalid key");
1650 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001651 v = __pthread_getspecific(libc_specifics_keys[key]);
sewardj5716dbb2002-04-26 03:28:18 +00001652 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1653 return v;
1654}
1655
1656
sewardj70adeb22002-04-27 01:35:38 +00001657int (*__libc_internal_tsd_set)
1658 (enum __libc_tsd_key_t key, const void * pointer)
1659 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001660
sewardj70adeb22002-04-27 01:35:38 +00001661void* (*__libc_internal_tsd_get)
1662 (enum __libc_tsd_key_t key)
1663 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001664
1665
sewardj00a66b12002-10-12 16:42:35 +00001666#ifdef GLIBC_2_3
1667/* This one was first spotted be me in the glibc-2.2.93 sources. */
1668static void**
1669libc_internal_tsd_address ( enum __libc_tsd_key_t key )
1670{
1671 void** v;
1672 /* printf("ADDR ADDR ADDR key %d\n", key); */
1673 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
1674 barf("libc_internal_tsd_address: invalid key");
1675 init_libc_tsd_keys();
1676 v = __pthread_getspecific_addr(libc_specifics_keys[key]);
1677 return v;
1678}
1679
1680void ** (*__libc_internal_tsd_address)
1681 (enum __libc_tsd_key_t key)
1682 = libc_internal_tsd_address;
1683#endif
1684
1685
sewardje663cb92002-04-12 10:26:32 +00001686/* ---------------------------------------------------------------------
1687 These are here (I think) because they are deemed cancellation
1688 points by POSIX. For the moment we'll simply pass the call along
1689 to the corresponding thread-unaware (?) libc routine.
1690 ------------------------------------------------------------------ */
1691
sewardje663cb92002-04-12 10:26:32 +00001692#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001693#include <sys/types.h>
1694#include <sys/socket.h>
1695
sewardjd529a442002-05-04 19:49:21 +00001696#ifdef GLIBC_2_1
1697extern
1698int __sigaction
1699 (int signum,
1700 const struct sigaction *act,
1701 struct sigaction *oldact);
1702#else
sewardje663cb92002-04-12 10:26:32 +00001703extern
1704int __libc_sigaction
1705 (int signum,
1706 const struct sigaction *act,
1707 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001708#endif
sewardje663cb92002-04-12 10:26:32 +00001709int sigaction(int signum,
1710 const struct sigaction *act,
1711 struct sigaction *oldact)
1712{
sewardjd140e442002-05-29 01:21:19 +00001713 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001714# ifdef GLIBC_2_1
1715 return __sigaction(signum, act, oldact);
1716# else
sewardj45b4b372002-04-16 22:50:32 +00001717 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001718# endif
sewardje663cb92002-04-12 10:26:32 +00001719}
1720
1721
1722extern
1723int __libc_connect(int sockfd,
1724 const struct sockaddr *serv_addr,
1725 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001726__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001727int connect(int sockfd,
1728 const struct sockaddr *serv_addr,
1729 socklen_t addrlen)
1730{
sewardjd140e442002-05-29 01:21:19 +00001731 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001732 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001733}
1734
1735
1736extern
1737int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001738__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001739int fcntl(int fd, int cmd, long arg)
1740{
sewardjd140e442002-05-29 01:21:19 +00001741 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001742 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001743}
1744
1745
1746extern
1747ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001748__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001749ssize_t write(int fd, const void *buf, size_t count)
1750{
sewardjd140e442002-05-29 01:21:19 +00001751 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001752 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001753}
1754
1755
1756extern
1757ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001758__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001759ssize_t read(int fd, void *buf, size_t count)
1760{
sewardjd140e442002-05-29 01:21:19 +00001761 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001762 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001763}
1764
sewardjbe32e452002-04-24 20:29:58 +00001765
1766extern
sewardj853f55d2002-04-26 00:27:53 +00001767int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001768__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001769int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001770{
sewardjd140e442002-05-29 01:21:19 +00001771 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001772 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001773}
1774
sewardje663cb92002-04-12 10:26:32 +00001775
1776extern
sewardj853f55d2002-04-26 00:27:53 +00001777int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001778__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001779int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001780{
sewardjd140e442002-05-29 01:21:19 +00001781 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001782 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001783}
1784
1785
1786extern
1787int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001788__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001789int close(int fd)
1790{
sewardjd140e442002-05-29 01:21:19 +00001791 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001792 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001793}
1794
1795
1796extern
1797int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001798__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001799int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1800{
sewardjd140e442002-05-29 01:21:19 +00001801 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001802 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001803 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001804 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001805}
1806
1807
1808extern
sewardje663cb92002-04-12 10:26:32 +00001809pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001810__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001811pid_t waitpid(pid_t pid, int *status, int options)
1812{
sewardjd140e442002-05-29 01:21:19 +00001813 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001814 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001815}
1816
1817
1818extern
1819int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001820__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001821int nanosleep(const struct timespec *req, struct timespec *rem)
1822{
sewardjd140e442002-05-29 01:21:19 +00001823 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001824 return __libc_nanosleep(req, rem);
1825}
1826
sewardjbe32e452002-04-24 20:29:58 +00001827
sewardje663cb92002-04-12 10:26:32 +00001828extern
1829int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001830__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001831int fsync(int fd)
1832{
sewardjd140e442002-05-29 01:21:19 +00001833 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001834 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001835}
1836
sewardjbe32e452002-04-24 20:29:58 +00001837
sewardj70c75362002-04-13 04:18:32 +00001838extern
1839off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001840__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001841off_t lseek(int fildes, off_t offset, int whence)
1842{
sewardjd140e442002-05-29 01:21:19 +00001843 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001844 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001845}
1846
sewardjbe32e452002-04-24 20:29:58 +00001847
1848extern
1849__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001850__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001851__off64_t lseek64(int fildes, __off64_t offset, int whence)
1852{
sewardjd140e442002-05-29 01:21:19 +00001853 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001854 return __libc_lseek64(fildes, offset, whence);
1855}
1856
1857
sewardj726c4122002-05-16 23:39:10 +00001858extern
1859ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1860 __off64_t __offset);
1861ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1862 __off64_t __offset)
1863{
sewardjd140e442002-05-29 01:21:19 +00001864 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001865 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1866}
1867
1868
sewardja18e2102002-05-18 10:43:22 +00001869extern
1870ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1871 __off64_t __offset);
1872ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1873 __off64_t __offset)
1874{
sewardjd140e442002-05-29 01:21:19 +00001875 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001876 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1877}
1878
sewardj726c4122002-05-16 23:39:10 +00001879
sewardj39b93b12002-05-18 10:56:27 +00001880extern
1881ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1882__attribute__((weak))
1883ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1884{
sewardjd140e442002-05-29 01:21:19 +00001885 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001886 return __libc_pwrite(fd, buf, count, offset);
1887}
1888
1889
1890extern
1891ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1892__attribute__((weak))
1893ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1894{
sewardjd140e442002-05-29 01:21:19 +00001895 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001896 return __libc_pread(fd, buf, count, offset);
1897}
1898
1899
sewardj6af4b5d2002-04-16 04:40:49 +00001900extern
1901void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001902/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001903void longjmp(jmp_buf env, int val)
1904{
1905 __libc_longjmp(env, val);
1906}
1907
sewardjbe32e452002-04-24 20:29:58 +00001908
sewardj436c2db2002-06-18 09:07:54 +00001909extern void __libc_siglongjmp (sigjmp_buf env, int val)
1910 __attribute__ ((noreturn));
1911void siglongjmp(sigjmp_buf env, int val)
1912{
1913 kludged("siglongjmp (cleanup handlers are ignored)");
1914 __libc_siglongjmp(env, val);
1915}
1916
1917
sewardj6af4b5d2002-04-16 04:40:49 +00001918extern
1919int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001920__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001921int send(int s, const void *msg, size_t len, int flags)
1922{
sewardjd140e442002-05-29 01:21:19 +00001923 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001924 return __libc_send(s, msg, len, flags);
1925}
1926
sewardjbe32e452002-04-24 20:29:58 +00001927
sewardj1e8cdc92002-04-18 11:37:52 +00001928extern
1929int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001930__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001931int recv(int s, void *buf, size_t len, int flags)
1932{
sewardjd140e442002-05-29 01:21:19 +00001933 __my_pthread_testcancel();
sewardj1d6b3a22002-06-20 07:58:33 +00001934 wait_for_fd_to_be_readable_or_erring(s);
1935 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001936 return __libc_recv(s, buf, len, flags);
1937}
1938
sewardjbe32e452002-04-24 20:29:58 +00001939
sewardj3665ded2002-05-16 16:57:25 +00001940extern
1941int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1942__attribute__((weak))
1943int sendmsg(int s, const struct msghdr *msg, int flags)
1944{
sewardjd140e442002-05-29 01:21:19 +00001945 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001946 return __libc_sendmsg(s, msg, flags);
1947}
1948
1949
sewardj796d6a22002-04-24 02:28:34 +00001950extern
sewardj59da27a2002-06-06 08:33:54 +00001951int __libc_recvmsg(int s, struct msghdr *msg, int flags);
1952__attribute__((weak))
1953int recvmsg(int s, struct msghdr *msg, int flags)
1954{
1955 __my_pthread_testcancel();
1956 return __libc_recvmsg(s, msg, flags);
1957}
1958
1959
1960extern
sewardj436e0582002-04-26 14:31:40 +00001961int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1962 struct sockaddr *from, socklen_t *fromlen);
1963__attribute__((weak))
1964int recvfrom(int s, void *buf, size_t len, int flags,
1965 struct sockaddr *from, socklen_t *fromlen)
1966{
sewardjd140e442002-05-29 01:21:19 +00001967 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00001968 wait_for_fd_to_be_readable_or_erring(s);
1969 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001970 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1971}
1972
1973
1974extern
sewardj796d6a22002-04-24 02:28:34 +00001975int __libc_sendto(int s, const void *msg, size_t len, int flags,
1976 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001977__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001978int sendto(int s, const void *msg, size_t len, int flags,
1979 const struct sockaddr *to, socklen_t tolen)
1980{
sewardjd140e442002-05-29 01:21:19 +00001981 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001982 return __libc_sendto(s, msg, len, flags, to, tolen);
1983}
1984
sewardjbe32e452002-04-24 20:29:58 +00001985
sewardj369b1702002-04-24 13:28:15 +00001986extern
1987int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001988__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001989int system(const char* str)
1990{
sewardjd140e442002-05-29 01:21:19 +00001991 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001992 return __libc_system(str);
1993}
1994
sewardjbe32e452002-04-24 20:29:58 +00001995
sewardjab0b1c32002-04-24 19:26:47 +00001996extern
1997pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001998__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001999pid_t wait(int *status)
2000{
sewardjd140e442002-05-29 01:21:19 +00002001 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00002002 return __libc_wait(status);
2003}
2004
sewardj45b4b372002-04-16 22:50:32 +00002005
sewardj67f1d582002-05-24 02:11:32 +00002006extern
2007int __libc_msync(const void *start, size_t length, int flags);
2008__attribute__((weak))
2009int msync(const void *start, size_t length, int flags)
2010{
sewardjd140e442002-05-29 01:21:19 +00002011 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00002012 return __libc_msync(start, length, flags);
2013}
2014
sewardj5905fae2002-04-26 13:25:00 +00002015
sewardj2cb00342002-06-28 01:46:26 +00002016/*--- fork and its helper ---*/
2017
2018static
2019void run_fork_handlers ( int what )
2020{
2021 ForkHandlerEntry entry;
2022 int n_h, n_handlers, i, res;
2023
2024 my_assert(what == 0 || what == 1 || what == 2);
2025
2026 /* Fetch old counter */
2027 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2028 VG_USERREQ__GET_FHSTACK_USED,
2029 0, 0, 0, 0);
2030 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2031
2032 /* Prepare handlers (what == 0) are called in opposite order of
2033 calls to pthread_atfork. Parent and child handlers are called
2034 in the same order as calls to pthread_atfork. */
2035 if (what == 0)
2036 n_h = n_handlers - 1;
2037 else
2038 n_h = 0;
2039
2040 for (i = 0; i < n_handlers; i++) {
2041 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2042 VG_USERREQ__GET_FHSTACK_ENTRY,
2043 n_h, &entry, 0, 0);
2044 my_assert(res == 0);
2045 switch (what) {
2046 case 0: if (entry.prepare) entry.prepare();
2047 n_h--; break;
2048 case 1: if (entry.parent) entry.parent();
2049 n_h++; break;
2050 case 2: if (entry.child) entry.child();
2051 n_h++; break;
2052 default: barf("run_fork_handlers: invalid what");
2053 }
2054 }
2055
2056 if (what != 0 /* prepare */) {
2057 /* Empty out the stack. */
2058 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2059 VG_USERREQ__SET_FHSTACK_USED,
2060 0, 0, 0, 0);
2061 my_assert(res == 0);
2062 }
2063}
2064
2065extern
2066pid_t __libc_fork(void);
2067pid_t __fork(void)
2068{
2069 pid_t pid;
2070 __my_pthread_testcancel();
2071 __pthread_mutex_lock(&pthread_atfork_lock);
2072
2073 run_fork_handlers(0 /* prepare */);
2074 pid = __libc_fork();
2075 if (pid == 0) {
2076 /* I am the child */
2077 run_fork_handlers(2 /* child */);
2078 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2079 } else {
2080 /* I am the parent */
2081 run_fork_handlers(1 /* parent */);
2082 __pthread_mutex_unlock(&pthread_atfork_lock);
2083 }
2084 return pid;
2085}
2086
2087
njn25e49d8e72002-09-23 09:36:25 +00002088pid_t __vfork(void)
2089{
2090 return __fork();
2091}
sewardj2cb00342002-06-28 01:46:26 +00002092
2093
sewardj3b13f0e2002-04-25 20:17:29 +00002094/* ---------------------------------------------------------------------
2095 Nonblocking implementations of select() and poll(). This stuff will
2096 surely rot your mind.
2097 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00002098
sewardj08a4c3f2002-04-13 03:45:44 +00002099/*--------------------------------------------------*/
2100
2101#include "vg_kerneliface.h"
2102
2103static
2104__inline__
2105int is_kerror ( int res )
2106{
2107 if (res >= -4095 && res <= -1)
2108 return 1;
2109 else
2110 return 0;
2111}
2112
2113
2114static
2115int my_do_syscall1 ( int syscallno, int arg1 )
2116{
2117 int __res;
2118 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2119 : "=a" (__res)
2120 : "0" (syscallno),
2121 "d" (arg1) );
2122 return __res;
2123}
2124
2125static
2126int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00002127 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00002128{
2129 int __res;
2130 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2131 : "=a" (__res)
2132 : "0" (syscallno),
2133 "d" (arg1),
2134 "c" (arg2) );
2135 return __res;
2136}
2137
2138static
sewardjf854f472002-04-21 12:19:41 +00002139int my_do_syscall3 ( int syscallno,
2140 int arg1, int arg2, int arg3 )
2141{
2142 int __res;
2143 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
2144 : "=a" (__res)
2145 : "0" (syscallno),
2146 "S" (arg1),
2147 "c" (arg2),
2148 "d" (arg3) );
2149 return __res;
2150}
2151
2152static
sewardj08a4c3f2002-04-13 03:45:44 +00002153int do_syscall_select( int n,
2154 vki_fd_set* readfds,
2155 vki_fd_set* writefds,
2156 vki_fd_set* exceptfds,
2157 struct vki_timeval * timeout )
2158{
2159 int res;
2160 int args[5];
2161 args[0] = n;
2162 args[1] = (int)readfds;
2163 args[2] = (int)writefds;
2164 args[3] = (int)exceptfds;
2165 args[4] = (int)timeout;
2166 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00002167 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00002168}
2169
2170
2171/* This is a wrapper round select(), which makes it thread-safe,
2172 meaning that only this thread will block, rather than the entire
2173 process. This wrapper in turn depends on nanosleep() not to block
2174 the entire process, but I think (hope? suspect?) that POSIX
2175 pthreads guarantees that to be the case.
2176
2177 Basic idea is: modify the timeout parameter to select so that it
2178 returns immediately. Poll like this until select returns non-zero,
2179 indicating something interesting happened, or until our time is up.
njn25e49d8e72002-09-23 09:36:25 +00002180 Space out the polls with nanosleeps of say 11 milliseconds, which
sewardj08a4c3f2002-04-13 03:45:44 +00002181 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00002182
2183 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00002184 * (checked via my_assert) types fd_set and vki_fd_set are identical.
2185 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00002186 * (unchecked) libc error numbers (EINTR etc) are the negation of the
2187 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00002188*/
sewardj08a4c3f2002-04-13 03:45:44 +00002189
sewardj5905fae2002-04-26 13:25:00 +00002190/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00002191int select ( int n,
2192 fd_set *rfds,
2193 fd_set *wfds,
2194 fd_set *xfds,
2195 struct timeval *timeout )
2196{
sewardj5f07b662002-04-23 16:52:51 +00002197 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00002198 int res;
2199 fd_set rfds_copy;
2200 fd_set wfds_copy;
2201 fd_set xfds_copy;
2202 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00002203 struct vki_timeval zero_timeout;
2204 struct vki_timespec nanosleep_interval;
2205
sewardjd140e442002-05-29 01:21:19 +00002206 __my_pthread_testcancel();
2207
sewardj5f07b662002-04-23 16:52:51 +00002208 /* gcc's complains about ms_end being used uninitialised -- classic
2209 case it can't understand, where ms_end is both defined and used
2210 only if timeout != NULL. Hence ... */
2211 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00002212
2213 /* We assume that the kernel and libc data layouts are identical
2214 for the following types. These asserts provide a crude
2215 check. */
2216 if (sizeof(fd_set) != sizeof(vki_fd_set)
2217 || sizeof(struct timeval) != sizeof(struct vki_timeval))
2218 barf("valgrind's hacky non-blocking select(): data sizes error");
2219
sewardj5f07b662002-04-23 16:52:51 +00002220 /* Detect the current time and simultaneously find out if we are
2221 running on Valgrind. */
2222 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2223 VG_USERREQ__READ_MILLISECOND_TIMER,
2224 0, 0, 0, 0);
2225
2226 /* If a zero timeout specified, this call is harmless. Also go
2227 this route if we're not running on Valgrind, for whatever
2228 reason. */
2229 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
2230 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00002231 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00002232 (vki_fd_set*)wfds,
2233 (vki_fd_set*)xfds,
2234 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00002235 if (is_kerror(res)) {
2236 * (__errno_location()) = -res;
2237 return -1;
2238 } else {
2239 return res;
2240 }
2241 }
sewardj08a4c3f2002-04-13 03:45:44 +00002242
sewardj5f07b662002-04-23 16:52:51 +00002243 /* If a timeout was specified, set ms_end to be the end millisecond
2244 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00002245 if (timeout) {
2246 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00002247 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00002248 ms_end = ms_now;
2249 ms_end += (timeout->tv_usec / 1000);
2250 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00002251 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00002252 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00002253 }
2254
2255 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
2256
2257 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00002258 NULL, in which case ms_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002259
sewardj08a4c3f2002-04-13 03:45:44 +00002260 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002261
2262 /* First, do a return-immediately select(). */
sewardj08a4c3f2002-04-13 03:45:44 +00002263
2264 /* These could be trashed each time round the loop, so restore
2265 them each time. */
2266 if (rfds) rfds_copy = *rfds;
2267 if (wfds) wfds_copy = *wfds;
2268 if (xfds) xfds_copy = *xfds;
2269
2270 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
2271
2272 res = do_syscall_select( n,
2273 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
2274 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
2275 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
2276 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00002277 if (is_kerror(res)) {
2278 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00002279 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00002280 * (__errno_location()) = -res;
2281 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00002282 }
2283 if (res > 0) {
2284 /* one or more fds is ready. Copy out resulting sets and
2285 return. */
2286 if (rfds) *rfds = rfds_copy;
2287 if (wfds) *wfds = wfds_copy;
2288 if (xfds) *xfds = xfds_copy;
2289 return res;
2290 }
sewardj05bb2c92002-06-26 00:47:17 +00002291
2292 /* Nothing interesting happened, so we go to sleep for a
2293 while. */
2294
sewardj08a4c3f2002-04-13 03:45:44 +00002295 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
2296 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00002297 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002298 nanosleep_interval.tv_nsec = 11 * 1000 * 1000; /* 11 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00002299 /* It's critical here that valgrind's nanosleep implementation
2300 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00002301 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00002302 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00002303 if (res == -VKI_EINTR) {
2304 /* The nanosleep was interrupted by a signal. So we do the
2305 same. */
2306 * (__errno_location()) = EINTR;
2307 return -1;
2308 }
sewardj05bb2c92002-06-26 00:47:17 +00002309
2310 /* Sleeping finished. If a finite timeout, check to see if it
2311 has expired yet. */
2312 if (timeout) {
2313 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2314 VG_USERREQ__READ_MILLISECOND_TIMER,
2315 0, 0, 0, 0);
2316 my_assert(ms_now != 0xFFFFFFFF);
2317 if (ms_now >= ms_end) {
2318 /* timeout; nothing interesting happened. */
2319 if (rfds) FD_ZERO(rfds);
2320 if (wfds) FD_ZERO(wfds);
2321 if (xfds) FD_ZERO(xfds);
2322 return 0;
2323 }
2324 }
2325
sewardjf854f472002-04-21 12:19:41 +00002326 }
2327}
2328
2329
2330
2331
2332#include <sys/poll.h>
2333
sewardj3e909ce2002-06-03 13:27:15 +00002334#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00002335typedef unsigned long int nfds_t;
2336#endif
2337
sewardj705d3cb2002-05-23 13:13:12 +00002338
sewardj5905fae2002-04-26 13:25:00 +00002339/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00002340int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2341{
sewardj5f07b662002-04-23 16:52:51 +00002342 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00002343 int res, i;
sewardjf854f472002-04-21 12:19:41 +00002344 struct vki_timespec nanosleep_interval;
2345
sewardjd140e442002-05-29 01:21:19 +00002346 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00002347 ensure_valgrind("poll");
2348
sewardj5f07b662002-04-23 16:52:51 +00002349 /* Detect the current time and simultaneously find out if we are
2350 running on Valgrind. */
2351 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2352 VG_USERREQ__READ_MILLISECOND_TIMER,
2353 0, 0, 0, 0);
2354
sewardjf854f472002-04-21 12:19:41 +00002355 if (/* CHECK SIZES FOR struct pollfd */
2356 sizeof(struct timeval) != sizeof(struct vki_timeval))
2357 barf("valgrind's hacky non-blocking poll(): data sizes error");
2358
sewardj5f07b662002-04-23 16:52:51 +00002359 /* dummy initialisation to keep gcc -Wall happy */
2360 ms_end = 0;
2361
2362 /* If a zero timeout specified, this call is harmless. Also do
2363 this if not running on Valgrind. */
2364 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00002365 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
2366 if (is_kerror(res)) {
2367 * (__errno_location()) = -res;
2368 return -1;
2369 } else {
2370 return res;
2371 }
2372 }
2373
sewardj5f07b662002-04-23 16:52:51 +00002374 /* If a timeout was specified, set ms_end to be the end wallclock
2375 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002376 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002377 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002378 }
2379
2380 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2381
2382 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2383 in which case t_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002384
sewardj2d94c112002-06-03 01:25:54 +00002385 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002386
sewardjf854f472002-04-21 12:19:41 +00002387 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002388
2389 /* Do a return-immediately poll. */
2390
2391 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2392 if (is_kerror(res)) {
2393 /* Some kind of error. Set errno and return. */
2394 * (__errno_location()) = -res;
2395 return -1;
2396 }
2397 if (res > 0) {
2398 /* One or more fds is ready. Return now. */
2399 return res;
2400 }
2401
2402 /* Nothing interesting happened, so we go to sleep for a
2403 while. */
2404
2405 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2406 /* nanosleep and go round again */
2407 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002408 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
sewardj05bb2c92002-06-26 00:47:17 +00002409 /* It's critical here that valgrind's nanosleep implementation
2410 is nonblocking. */
2411 (void)my_do_syscall2(__NR_nanosleep,
2412 (int)(&nanosleep_interval), (int)NULL);
2413
2414 /* Sleeping finished. If a finite timeout, check to see if it
2415 has expired yet. */
sewardjf854f472002-04-21 12:19:41 +00002416 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002417 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2418 VG_USERREQ__READ_MILLISECOND_TIMER,
2419 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002420 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002421 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002422 /* timeout; nothing interesting happened. */
2423 for (i = 0; i < __nfds; i++)
2424 __fds[i].revents = 0;
2425 return 0;
2426 }
2427 }
2428
sewardj08a4c3f2002-04-13 03:45:44 +00002429 }
2430}
sewardj3b13f0e2002-04-25 20:17:29 +00002431
2432
sewardj705d3cb2002-05-23 13:13:12 +00002433/* Helper function used to make accept() non-blocking. Idea is to use
2434 the above nonblocking poll() to make this thread ONLY wait for the
2435 specified fd to become ready, and then return. */
sewardjd1c1cf22002-06-26 00:13:36 +00002436
2437/* Sigh -- a hack. We're not supposed to include this file directly;
2438 should do it via /usr/include/fcntl.h, but that introduces a
2439 varargs prototype for fcntl itself, which we can't mimic. */
2440#define _FCNTL_H
2441#include <bits/fcntl.h>
2442
sewardj705d3cb2002-05-23 13:13:12 +00002443static void wait_for_fd_to_be_readable_or_erring ( int fd )
2444{
2445 struct pollfd pfd;
sewardjd1c1cf22002-06-26 00:13:36 +00002446 int res;
2447
sewardj6e6cbaa2002-05-24 02:12:52 +00002448 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardjd1c1cf22002-06-26 00:13:36 +00002449
2450 /* First check to see if the fd is nonblocking, and/or invalid. In
2451 either case return immediately. */
2452 res = __libc_fcntl(fd, F_GETFL, 0);
2453 if (res == -1) return; /* fd is invalid somehow */
2454 if (res & O_NONBLOCK) return; /* fd is nonblocking */
2455
2456 /* Ok, we'd better wait with poll. */
sewardj705d3cb2002-05-23 13:13:12 +00002457 pfd.fd = fd;
2458 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2459 /* ... but not POLLOUT, you may notice. */
2460 pfd.revents = 0;
2461 (void)poll(&pfd, 1, -1 /* forever */);
2462}
2463
2464
sewardj3b13f0e2002-04-25 20:17:29 +00002465/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002466 Hacky implementation of semaphores.
2467 ------------------------------------------------------------------ */
2468
2469#include <semaphore.h>
2470
2471/* This is a terrible way to do the remapping. Plan is to import an
2472 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002473
2474typedef
2475 struct {
2476 pthread_mutex_t se_mx;
2477 pthread_cond_t se_cv;
2478 int count;
2479 }
2480 vg_sem_t;
2481
2482static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2483
2484static int se_remap_used = 0;
2485static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2486static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2487
2488static vg_sem_t* se_remap ( sem_t* orig )
2489{
2490 int res, i;
2491 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002492 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002493
2494 for (i = 0; i < se_remap_used; i++) {
2495 if (se_remap_orig[i] == orig)
2496 break;
2497 }
2498 if (i == se_remap_used) {
2499 if (se_remap_used == VG_N_SEMAPHORES) {
2500 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002501 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002502 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002503 }
2504 se_remap_used++;
2505 se_remap_orig[i] = orig;
2506 /* printf("allocated semaphore %d\n", i); */
2507 }
2508 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002509 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002510 return &se_remap_new[i];
2511}
2512
2513
2514int sem_init(sem_t *sem, int pshared, unsigned int value)
2515{
2516 int res;
2517 vg_sem_t* vg_sem;
2518 ensure_valgrind("sem_init");
2519 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002520 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002521 errno = ENOSYS;
2522 return -1;
2523 }
2524 vg_sem = se_remap(sem);
2525 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002526 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002527 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002528 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002529 vg_sem->count = value;
2530 return 0;
2531}
2532
2533
2534int sem_wait ( sem_t* sem )
2535{
2536 int res;
2537 vg_sem_t* vg_sem;
2538 ensure_valgrind("sem_wait");
2539 vg_sem = se_remap(sem);
2540 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002541 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002542 while (vg_sem->count == 0) {
2543 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002544 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002545 }
2546 vg_sem->count--;
2547 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002548 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002549 return 0;
2550}
2551
2552int sem_post ( sem_t* sem )
2553{
2554 int res;
2555 vg_sem_t* vg_sem;
2556 ensure_valgrind("sem_post");
2557 vg_sem = se_remap(sem);
2558 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002559 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002560 if (vg_sem->count == 0) {
2561 vg_sem->count++;
2562 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002563 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002564 } else {
2565 vg_sem->count++;
2566 }
2567 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002568 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002569 return 0;
2570}
2571
2572
2573int sem_trywait ( sem_t* sem )
2574{
2575 int ret, res;
2576 vg_sem_t* vg_sem;
2577 ensure_valgrind("sem_trywait");
2578 vg_sem = se_remap(sem);
2579 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002580 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002581 if (vg_sem->count > 0) {
2582 vg_sem->count--;
2583 ret = 0;
2584 } else {
2585 ret = -1;
2586 errno = EAGAIN;
2587 }
2588 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002589 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002590 return ret;
2591}
2592
2593
2594int sem_getvalue(sem_t* sem, int * sval)
2595{
2596 vg_sem_t* vg_sem;
2597 ensure_valgrind("sem_trywait");
2598 vg_sem = se_remap(sem);
2599 *sval = vg_sem->count;
2600 return 0;
2601}
2602
2603
2604int sem_destroy(sem_t * sem)
2605{
2606 kludged("sem_destroy");
2607 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2608 return 0;
2609}
2610
sewardj9ad92d92002-10-16 19:45:06 +00002611
2612int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2613{
2614 int res;
2615 vg_sem_t* vg_sem;
2616 ensure_valgrind("sem_timedwait");
2617 vg_sem = se_remap(sem);
2618 res = __pthread_mutex_lock(&vg_sem->se_mx);
2619 my_assert(res == 0);
2620 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
2621 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
2622 }
2623 if ( vg_sem->count > 0 ) {
2624 vg_sem->count--;
2625 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2626 my_assert(res == 0 );
2627 return 0;
2628 } else {
2629 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2630 my_assert(res == 0 );
2631 *(__errno_location()) = ETIMEDOUT;
2632 return -1;
2633 }
2634}
2635
sewardj8f253ff2002-05-19 00:13:34 +00002636
2637/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002638 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002639 ------------------------------------------------------------------ */
2640
sewardj2d8b3f02002-06-01 14:14:19 +00002641typedef
2642 struct {
2643 int initted; /* != 0 --> in use; sanity check only */
2644 int prefer_w; /* != 0 --> prefer writer */
2645 int nwait_r; /* # of waiting readers */
2646 int nwait_w; /* # of waiting writers */
2647 pthread_cond_t cv_r; /* for signalling readers */
2648 pthread_cond_t cv_w; /* for signalling writers */
2649 pthread_mutex_t mx;
2650 int status;
2651 /* allowed range for status: >= -1. -1 means 1 writer currently
2652 active, >= 0 means N readers currently active. */
2653 }
2654 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002655
2656
2657static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2658
2659static int rw_remap_used = 0;
2660static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2661static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2662
sewardj2d8b3f02002-06-01 14:14:19 +00002663
2664static
2665void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2666{
2667 int res = 0;
2668 vg_rwl->initted = 1;
2669 vg_rwl->prefer_w = 1;
2670 vg_rwl->nwait_r = 0;
2671 vg_rwl->nwait_w = 0;
2672 vg_rwl->status = 0;
2673 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2674 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2675 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002676 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002677}
2678
2679
sewardja1ac5cb2002-05-27 13:00:05 +00002680/* Take the address of a LinuxThreads rwlock_t and return the shadow
2681 address of our version. Further, if the LinuxThreads version
2682 appears to have been statically initialised, do the same to the one
2683 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2684 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2685 uninitialised and non-zero meaning initialised.
2686*/
2687static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2688{
2689 int res, i;
2690 vg_rwlock_t* vg_rwl;
2691 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002692 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002693
2694 for (i = 0; i < rw_remap_used; i++) {
2695 if (rw_remap_orig[i] == orig)
2696 break;
2697 }
2698 if (i == rw_remap_used) {
2699 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002700 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002701 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002702 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2703 }
2704 rw_remap_used++;
2705 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002706 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002707 if (0) printf("allocated rwlock %d\n", i);
2708 }
2709 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002710 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002711 vg_rwl = &rw_remap_new[i];
2712
sewardj2d8b3f02002-06-01 14:14:19 +00002713 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002714 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002715 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002716 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002717 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002718 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002719 }
2720
2721 return vg_rwl;
2722}
2723
2724
sewardja1ac5cb2002-05-27 13:00:05 +00002725int pthread_rwlock_init ( pthread_rwlock_t* orig,
2726 const pthread_rwlockattr_t* attr )
2727{
sewardja1ac5cb2002-05-27 13:00:05 +00002728 vg_rwlock_t* rwl;
2729 if (0) printf ("pthread_rwlock_init\n");
2730 /* Force the remapper to initialise the shadow. */
2731 orig->__rw_readers = 0;
2732 /* Install the lock preference; the remapper needs to know it. */
2733 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2734 if (attr)
2735 orig->__rw_kind = attr->__lockkind;
2736 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002737 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002738}
2739
sewardj2d8b3f02002-06-01 14:14:19 +00002740
2741static
2742void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002743{
sewardj2d8b3f02002-06-01 14:14:19 +00002744 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2745 rwl->nwait_r--;
2746 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002747}
2748
sewardj2d8b3f02002-06-01 14:14:19 +00002749
sewardja1ac5cb2002-05-27 13:00:05 +00002750int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2751{
2752 int res;
2753 vg_rwlock_t* rwl;
2754 if (0) printf ("pthread_rwlock_rdlock\n");
2755 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002756 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002757 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002758 if (!rwl->initted) {
2759 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002760 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002761 return EINVAL;
2762 }
2763 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002764 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002765 rwl->nwait_r++;
2766 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2767 while (1) {
2768 if (rwl->status == 0) break;
2769 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002770 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002771 }
2772 pthread_cleanup_pop(0);
2773 rwl->nwait_r--;
2774 }
sewardj2d94c112002-06-03 01:25:54 +00002775 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002776 rwl->status++;
2777 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002778 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002779 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002780}
2781
sewardj2d8b3f02002-06-01 14:14:19 +00002782
sewardja1ac5cb2002-05-27 13:00:05 +00002783int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2784{
2785 int res;
2786 vg_rwlock_t* rwl;
2787 if (0) printf ("pthread_rwlock_tryrdlock\n");
2788 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002789 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002790 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002791 if (!rwl->initted) {
2792 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002793 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002794 return EINVAL;
2795 }
2796 if (rwl->status == -1) {
2797 /* Writer active; we have to give up. */
2798 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002799 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002800 return EBUSY;
2801 }
2802 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002803 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002804 rwl->status++;
2805 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002806 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002807 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002808}
2809
sewardj2d8b3f02002-06-01 14:14:19 +00002810
2811static
2812void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2813{
2814 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2815 rwl->nwait_w--;
2816 pthread_mutex_unlock (&rwl->mx);
2817}
2818
2819
sewardja1ac5cb2002-05-27 13:00:05 +00002820int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2821{
2822 int res;
2823 vg_rwlock_t* rwl;
2824 if (0) printf ("pthread_rwlock_wrlock\n");
2825 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002826 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002827 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002828 if (!rwl->initted) {
2829 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002830 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002831 return EINVAL;
2832 }
2833 if (rwl->status != 0) {
2834 rwl->nwait_w++;
2835 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2836 while (1) {
2837 if (rwl->status == 0) break;
2838 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002839 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002840 }
2841 pthread_cleanup_pop(0);
2842 rwl->nwait_w--;
2843 }
sewardj2d94c112002-06-03 01:25:54 +00002844 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002845 rwl->status = -1;
2846 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002847 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002848 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002849}
2850
sewardj2d8b3f02002-06-01 14:14:19 +00002851
sewardja1ac5cb2002-05-27 13:00:05 +00002852int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2853{
2854 int res;
2855 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002856 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002857 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002858 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002859 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002860 if (!rwl->initted) {
2861 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002862 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002863 return EINVAL;
2864 }
2865 if (rwl->status != 0) {
2866 /* Reader(s) or a writer active; we have to give up. */
2867 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002868 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002869 return EBUSY;
2870 }
2871 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002872 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002873 rwl->status = -1;
2874 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002875 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002876 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002877}
2878
sewardj2d8b3f02002-06-01 14:14:19 +00002879
sewardja1ac5cb2002-05-27 13:00:05 +00002880int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2881{
2882 int res;
2883 vg_rwlock_t* rwl;
2884 if (0) printf ("pthread_rwlock_unlock\n");
2885 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002886 rwl = rw_remap ( orig );
2887 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002888 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002889 if (!rwl->initted) {
2890 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002891 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002892 return EINVAL;
2893 }
2894 if (rwl->status == 0) {
2895 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002896 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002897 return EPERM;
2898 }
sewardj2d94c112002-06-03 01:25:54 +00002899 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002900 if (rwl->status == -1) {
2901 rwl->status = 0;
2902 } else {
sewardj2d94c112002-06-03 01:25:54 +00002903 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002904 rwl->status--;
2905 }
2906
sewardj2d94c112002-06-03 01:25:54 +00002907 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002908
2909 if (rwl->prefer_w) {
2910
2911 /* Favour waiting writers, if any. */
2912 if (rwl->nwait_w > 0) {
2913 /* Writer(s) are waiting. */
2914 if (rwl->status == 0) {
2915 /* We can let a writer in. */
2916 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002917 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002918 } else {
2919 /* There are still readers active. Do nothing; eventually
2920 they will disappear, at which point a writer will be
2921 admitted. */
2922 }
2923 }
2924 else
2925 /* No waiting writers. */
2926 if (rwl->nwait_r > 0) {
2927 /* Let in a waiting reader. */
2928 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002929 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002930 }
2931
2932 } else {
2933
2934 /* Favour waiting readers, if any. */
2935 if (rwl->nwait_r > 0) {
2936 /* Reader(s) are waiting; let one in. */
2937 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002938 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002939 }
2940 else
2941 /* No waiting readers. */
2942 if (rwl->nwait_w > 0 && rwl->status == 0) {
2943 /* We have waiting writers and no active readers; let a
2944 writer in. */
2945 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002946 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002947 }
2948 }
2949
2950 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002951 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002952 return 0;
2953}
2954
2955
2956int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2957{
2958 int res;
2959 vg_rwlock_t* rwl;
2960 if (0) printf ("pthread_rwlock_destroy\n");
2961 rwl = rw_remap ( orig );
2962 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002963 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002964 if (!rwl->initted) {
2965 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002966 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002967 return EINVAL;
2968 }
2969 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2970 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002971 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002972 return EBUSY;
2973 }
2974 rwl->initted = 0;
2975 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002976 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002977 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002978}
2979
2980
sewardj47e4e312002-06-18 09:24:34 +00002981/* Copied directly from LinuxThreads. */
2982int
2983pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
2984{
2985 attr->__lockkind = 0;
2986 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
2987
2988 return 0;
2989}
2990
sewardjfe18eb82002-07-13 12:58:44 +00002991/* Copied directly from LinuxThreads. */
2992int
2993pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
2994{
2995 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
2996 return EINVAL;
2997
2998 /* For now it is not possible to shared a conditional variable. */
2999 if (pshared != PTHREAD_PROCESS_PRIVATE)
3000 return ENOSYS;
3001
3002 attr->__pshared = pshared;
3003
3004 return 0;
3005}
3006
sewardj47e4e312002-06-18 09:24:34 +00003007
sewardja1ac5cb2002-05-27 13:00:05 +00003008/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00003009 B'stard.
3010 ------------------------------------------------------------------ */
3011
3012# define strong_alias(name, aliasname) \
3013 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
3014
sewardj5905fae2002-04-26 13:25:00 +00003015# define weak_alias(name, aliasname) \
3016 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00003017
sewardj5905fae2002-04-26 13:25:00 +00003018strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
3019strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
3020strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
3021strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
3022 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
3023strong_alias(__pthread_mutex_init, pthread_mutex_init)
3024strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
3025strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
3026strong_alias(__pthread_once, pthread_once)
3027strong_alias(__pthread_atfork, pthread_atfork)
3028strong_alias(__pthread_key_create, pthread_key_create)
3029strong_alias(__pthread_getspecific, pthread_getspecific)
3030strong_alias(__pthread_setspecific, pthread_setspecific)
3031
sewardjd529a442002-05-04 19:49:21 +00003032#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00003033strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00003034#endif
3035
sewardj5905fae2002-04-26 13:25:00 +00003036strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00003037strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00003038strong_alias(lseek, __lseek)
3039strong_alias(open, __open)
3040strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00003041strong_alias(read, __read)
3042strong_alias(wait, __wait)
3043strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00003044strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00003045strong_alias(send, __send)
3046
sewardj726c4122002-05-16 23:39:10 +00003047weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00003048weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00003049weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00003050weak_alias(__vfork, vfork)
sewardj7f6456d2002-05-21 00:51:21 +00003051
sewardjf0b06452002-06-04 08:38:04 +00003052weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00003053
3054/*--------------------------------------------------*/
3055
sewardj5905fae2002-04-26 13:25:00 +00003056weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00003057weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00003058weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00003059
sewardja1ac5cb2002-05-27 13:00:05 +00003060weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
3061weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
3062weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
3063weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
3064
sewardj060b04f2002-04-26 21:01:13 +00003065
sewardj3b13f0e2002-04-25 20:17:29 +00003066/* I've no idea what these are, but they get called quite a lot.
3067 Anybody know? */
3068
3069#undef _IO_flockfile
3070void _IO_flockfile ( _IO_FILE * file )
3071{
sewardj853f55d2002-04-26 00:27:53 +00003072 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003073}
sewardj5905fae2002-04-26 13:25:00 +00003074weak_alias(_IO_flockfile, flockfile);
3075
sewardj3b13f0e2002-04-25 20:17:29 +00003076
3077#undef _IO_funlockfile
3078void _IO_funlockfile ( _IO_FILE * file )
3079{
sewardj853f55d2002-04-26 00:27:53 +00003080 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003081}
sewardj5905fae2002-04-26 13:25:00 +00003082weak_alias(_IO_funlockfile, funlockfile);
3083
sewardj3b13f0e2002-04-25 20:17:29 +00003084
sewardjd4f2c712002-04-30 10:20:10 +00003085/* This doesn't seem to be needed to simulate libpthread.so's external
3086 interface, but many people complain about its absence. */
3087
3088strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
3089weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00003090
3091
3092/*--------------------------------------------------------------------*/
3093/*--- end vg_libpthread.c ---*/
3094/*--------------------------------------------------------------------*/