blob: d98b73076a8e0510535c06653fa7f8beb23a794f [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/*
8 This file is part of Valgrind, an x86 protected-mode emulator
9 designed for debugging and profiling binaries on x86-Unixes.
10
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
29 The GNU General Public License is contained in the file LICENSE.
30*/
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
sewardj705d3cb2002-05-23 13:13:12 +000069
70/* ---------------------------------------------------------------------
71 Forwardses.
72 ------------------------------------------------------------------ */
73
74static void wait_for_fd_to_be_readable_or_erring ( int fd );
75
76
sewardje663cb92002-04-12 10:26:32 +000077/* ---------------------------------------------------------------------
78 Helpers. We have to be pretty self-sufficient.
79 ------------------------------------------------------------------ */
80
sewardj436e0582002-04-26 14:31:40 +000081/* Number of times any given error message is printed. */
82#define N_MOANS 3
83
sewardj45b4b372002-04-16 22:50:32 +000084/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
85 Returns 0 (none) if not running on Valgrind. */
86static
87int get_pt_trace_level ( void )
88{
89 int res;
90 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
91 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
92 0, 0, 0, 0);
93 return res;
94}
95
96
sewardje663cb92002-04-12 10:26:32 +000097static
98void myexit ( int arg )
99{
sewardj45b4b372002-04-16 22:50:32 +0000100 int __res;
sewardje663cb92002-04-12 10:26:32 +0000101 __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
102 : "=a" (__res)
103 : "0" (__NR_exit),
104 "c" (arg) );
sewardj45b4b372002-04-16 22:50:32 +0000105 /* We don't bother to mention the fact that this asm trashes %ebx,
106 since it won't return. If you ever do let it return ... fix
107 this! */
sewardje663cb92002-04-12 10:26:32 +0000108}
109
110
sewardj68b2dd92002-05-10 21:03:56 +0000111/* We need this guy -- it's in valgrind.so. */
112extern void VG_(startup) ( void );
113
114
115/* Just start up Valgrind if it's not already going. VG_(startup)()
116 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000117static __inline__
sewardje663cb92002-04-12 10:26:32 +0000118void ensure_valgrind ( char* caller )
119{
sewardj68b2dd92002-05-10 21:03:56 +0000120 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000121}
122
sewardjbea1caa2002-05-10 23:20:58 +0000123/* While we're at it ... hook our own startup function into this
124 game. */
125__asm__ (
126 ".section .init\n"
127 "\tcall vgPlain_startup"
128);
129
sewardje663cb92002-04-12 10:26:32 +0000130
131static
sewardj3b5d8862002-04-20 13:53:23 +0000132__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +0000133void barf ( char* str )
134{
135 char buf[100];
136 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000137 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000138 strcat(buf, str);
139 strcat(buf, "\n\n");
140 write(2, buf, strlen(buf));
141 myexit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000142 /* We have to persuade gcc into believing this doesn't return. */
143 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000144}
145
146
sewardj2a3d28c2002-04-14 13:27:00 +0000147static void ignored ( char* msg )
148{
sewardj436e0582002-04-26 14:31:40 +0000149 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000150 char* ig = "valgrind's libpthread.so: IGNORED call to: ";
sewardj45b4b372002-04-16 22:50:32 +0000151 write(2, ig, strlen(ig));
152 write(2, msg, strlen(msg));
153 ig = "\n";
154 write(2, ig, strlen(ig));
155 }
sewardj2a3d28c2002-04-14 13:27:00 +0000156}
157
sewardj30671ff2002-04-21 00:13:57 +0000158static void kludged ( char* msg )
159{
sewardj436e0582002-04-26 14:31:40 +0000160 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000161 char* ig = "valgrind's libpthread.so: KLUDGED call to: ";
162 write(2, ig, strlen(ig));
163 write(2, msg, strlen(msg));
164 ig = "\n";
165 write(2, ig, strlen(ig));
166 }
167}
168
169static void not_inside ( char* msg )
170{
sewardj68b2dd92002-05-10 21:03:56 +0000171 VG_(startup)();
sewardj30671ff2002-04-21 00:13:57 +0000172}
173
sewardj3b13f0e2002-04-25 20:17:29 +0000174void vgPlain_unimp ( char* what )
175{
sewardj439d45e2002-05-03 20:43:10 +0000176 char* ig = "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ";
sewardj3b13f0e2002-04-25 20:17:29 +0000177 write(2, ig, strlen(ig));
178 write(2, what, strlen(what));
179 ig = "\n";
180 write(2, ig, strlen(ig));
181 barf("Please report this bug to me at: jseward@acm.org");
182}
183
sewardje663cb92002-04-12 10:26:32 +0000184
185/* ---------------------------------------------------------------------
186 Pass pthread_ calls to Valgrind's request mechanism.
187 ------------------------------------------------------------------ */
188
sewardjf8f819e2002-04-17 23:21:37 +0000189#include <stdio.h>
190#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000191#include <assert.h>
192#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000193
sewardja1ac5cb2002-05-27 13:00:05 +0000194
sewardjf8f819e2002-04-17 23:21:37 +0000195/* ---------------------------------------------------
196 THREAD ATTRIBUTES
197 ------------------------------------------------ */
198
sewardj6af4b5d2002-04-16 04:40:49 +0000199int pthread_attr_init(pthread_attr_t *attr)
200{
sewardj7989d0c2002-05-28 11:00:01 +0000201 /* Just initialise the fields which we might look at. */
202 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj6af4b5d2002-04-16 04:40:49 +0000203 return 0;
204}
205
206int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
207{
sewardj7989d0c2002-05-28 11:00:01 +0000208 if (detachstate != PTHREAD_CREATE_JOINABLE
209 && detachstate != PTHREAD_CREATE_DETACHED)
210 return EINVAL;
211 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000212 return 0;
213}
214
sewardj30671ff2002-04-21 00:13:57 +0000215int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
216{
sewardj436e0582002-04-26 14:31:40 +0000217 static int moans = N_MOANS;
218 if (moans-- > 0)
219 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000220 return 0;
221}
sewardj6af4b5d2002-04-16 04:40:49 +0000222
sewardj0286dd52002-05-16 20:51:15 +0000223__attribute__((weak))
224int pthread_attr_setstacksize (pthread_attr_t *__attr,
225 size_t __stacksize)
226{
sewardja18e2102002-05-18 10:43:22 +0000227 size_t limit;
sewardj0286dd52002-05-16 20:51:15 +0000228 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000229 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
230 - 1000; /* paranoia */
231 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000232 return 0;
233 barf("pthread_attr_setstacksize: "
234 "requested size >= VG_PTHREAD_STACK_SIZE\n "
235 "edit vg_include.h and rebuild.");
236}
237
238
sewardj30671ff2002-04-21 00:13:57 +0000239/* This is completely bogus. */
240int pthread_attr_getschedparam(const pthread_attr_t *attr,
241 struct sched_param *param)
242{
sewardj436e0582002-04-26 14:31:40 +0000243 static int moans = N_MOANS;
244 if (moans-- > 0)
245 kludged("pthread_attr_getschedparam");
sewardj72d58482002-04-24 02:20:20 +0000246# ifdef GLIBC_2_1
247 if (param) param->sched_priority = 0; /* who knows */
248# else
sewardj30671ff2002-04-21 00:13:57 +0000249 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000250# endif
sewardj30671ff2002-04-21 00:13:57 +0000251 return 0;
252}
253
254int pthread_attr_setschedparam(pthread_attr_t *attr,
255 const struct sched_param *param)
256{
sewardj436e0582002-04-26 14:31:40 +0000257 static int moans = N_MOANS;
258 if (moans-- > 0)
259 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000260 return 0;
261}
262
263int pthread_attr_destroy(pthread_attr_t *attr)
264{
sewardj436e0582002-04-26 14:31:40 +0000265 static int moans = N_MOANS;
266 if (moans-- > 0)
267 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000268 return 0;
269}
sewardjf8f819e2002-04-17 23:21:37 +0000270
sewardj20917d82002-05-28 01:36:45 +0000271/* ---------------------------------------------------
272 Helper functions for running a thread
273 and for clearing up afterwards.
274 ------------------------------------------------ */
275
276/* All exiting threads eventually pass through here, bearing the
277 return value, or PTHREAD_CANCELED, in ret_val. */
278static
279__attribute__((noreturn))
280void thread_exit_wrapper ( void* ret_val )
281{
sewardj870497a2002-05-29 01:06:47 +0000282 int detached, res;
283 CleanupEntry cu;
284 pthread_key_t key;
285
sewardj20917d82002-05-28 01:36:45 +0000286 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000287 while (1) {
288 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
289 VG_USERREQ__CLEANUP_POP,
290 &cu, 0, 0, 0);
291 if (res == -1) break; /* stack empty */
292 assert(res == 0);
293 if (0) printf("running exit cleanup handler");
294 cu.fn ( cu.arg );
295 }
296
sewardj870497a2002-05-29 01:06:47 +0000297 /* Run this thread's key finalizers. Really this should be run
298 PTHREAD_DESTRUCTOR_ITERATIONS times. */
299 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
300 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
301 VG_USERREQ__GET_KEY_D_AND_S,
302 key, &cu, 0, 0 );
303 if (res == 0) {
304 /* valid key */
305 if (cu.fn && cu.arg)
306 cu.fn /* destructor for key */
307 ( cu.arg /* specific for key for this thread */ );
308 continue;
309 }
310 assert(res == -1);
311 }
sewardj20917d82002-05-28 01:36:45 +0000312
313 /* Decide on my final disposition. */
314 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
315 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000316 2 /* get */, pthread_self(), 0, 0);
sewardj20917d82002-05-28 01:36:45 +0000317 assert(detached == 0 || detached == 1);
318
319 if (detached) {
320 /* Detached; I just quit right now. */
321 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
322 VG_USERREQ__QUIT, 0, 0, 0, 0);
323 } else {
324 /* Not detached; so I wait for a joiner. */
325 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
326 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
327 }
328 /* NOTREACHED */
329 barf("thread_exit_wrapper: still alive?!");
330}
331
332
333/* This function is a wrapper function for running a thread. It runs
334 the root function specified in pthread_create, and then, should the
335 root function return a value, it arranges to run the thread's
336 cleanup handlers and exit correctly. */
337
338/* Struct used to convey info from pthread_create to
339 thread_wrapper. */
340typedef
341 struct {
342 pthread_attr_t* attr;
343 void* (*root_fn) ( void* );
344 void* arg;
345 }
346 NewThreadInfo;
347
348
349/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
350 not return. Note that this runs in the new thread, not the
351 parent. */
352static
353__attribute__((noreturn))
354void thread_wrapper ( NewThreadInfo* info )
355{
356 int res;
357 pthread_attr_t* attr;
358 void* (*root_fn) ( void* );
359 void* arg;
360 void* ret_val;
361
362 attr = info->attr;
363 root_fn = info->root_fn;
364 arg = info->arg;
365
sewardj20917d82002-05-28 01:36:45 +0000366 /* Free up the arg block that pthread_create malloced. */
367 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
368 VG_USERREQ__FREE, info, 0, 0, 0);
369 assert(res == 0);
370
sewardj7989d0c2002-05-28 11:00:01 +0000371 /* Minimally observe the attributes supplied. */
372 if (attr) {
373 assert(attr->__detachstate == PTHREAD_CREATE_DETACHED
374 || attr->__detachstate == PTHREAD_CREATE_JOINABLE);
375 if (attr->__detachstate == PTHREAD_CREATE_DETACHED)
376 pthread_detach(pthread_self());
377 }
378
sewardj20917d82002-05-28 01:36:45 +0000379 /* The root function might not return. But if it does we simply
380 move along to thread_exit_wrapper. All other ways out for the
381 thread (cancellation, or calling pthread_exit) lead there
382 too. */
383 ret_val = root_fn(arg);
384 thread_exit_wrapper(ret_val);
385 /* NOTREACHED */
386}
387
388
sewardjf8f819e2002-04-17 23:21:37 +0000389/* ---------------------------------------------------
390 THREADs
391 ------------------------------------------------ */
392
sewardjff42d1d2002-05-22 13:17:31 +0000393__attribute__((weak))
394int pthread_yield ( void )
395{
396 int res;
397 ensure_valgrind("pthread_yield");
398 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
399 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
400 return 0;
401}
402
403
sewardj6072c362002-04-19 14:40:57 +0000404int pthread_equal(pthread_t thread1, pthread_t thread2)
405{
406 return thread1 == thread2 ? 1 : 0;
407}
408
409
sewardj20917d82002-05-28 01:36:45 +0000410/* Bundle up the args into a malloc'd block and create a new thread
411 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000412int
413pthread_create (pthread_t *__restrict __thread,
414 __const pthread_attr_t *__restrict __attr,
415 void *(*__start_routine) (void *),
416 void *__restrict __arg)
417{
sewardj20917d82002-05-28 01:36:45 +0000418 int tid_child;
419 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000420
sewardj20917d82002-05-28 01:36:45 +0000421 ensure_valgrind("pthread_create");
422
423 /* Allocate space for the arg block. thread_wrapper will free
424 it. */
425 VALGRIND_MAGIC_SEQUENCE(info, NULL /* default */,
426 VG_USERREQ__MALLOC,
427 sizeof(NewThreadInfo), 0, 0, 0);
428 assert(info != NULL);
429
430 info->attr = (pthread_attr_t*)__attr;
431 info->root_fn = __start_routine;
432 info->arg = __arg;
433 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
434 VG_USERREQ__APPLY_IN_NEW_THREAD,
435 &thread_wrapper, info, 0, 0);
436 assert(tid_child != VG_INVALID_THREADID);
437
438 if (__thread)
439 *__thread = tid_child;
440 return 0; /* success */
441}
sewardje663cb92002-04-12 10:26:32 +0000442
443
444int
445pthread_join (pthread_t __th, void **__thread_return)
446{
447 int res;
448 ensure_valgrind("pthread_join");
449 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
450 VG_USERREQ__PTHREAD_JOIN,
451 __th, __thread_return, 0, 0);
452 return res;
453}
454
455
sewardj3b5d8862002-04-20 13:53:23 +0000456void pthread_exit(void *retval)
457{
sewardj3b5d8862002-04-20 13:53:23 +0000458 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000459 /* Simple! */
460 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000461}
462
sewardje663cb92002-04-12 10:26:32 +0000463
sewardj3b13f0e2002-04-25 20:17:29 +0000464pthread_t pthread_self(void)
sewardje663cb92002-04-12 10:26:32 +0000465{
466 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000467 ensure_valgrind("pthread_self");
sewardj439d45e2002-05-03 20:43:10 +0000468 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardje663cb92002-04-12 10:26:32 +0000469 VG_USERREQ__PTHREAD_GET_THREADID,
470 0, 0, 0, 0);
sewardj439d45e2002-05-03 20:43:10 +0000471 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000472 barf("pthread_self: invalid ThreadId");
473 return tid;
sewardje663cb92002-04-12 10:26:32 +0000474}
475
476
sewardj853f55d2002-04-26 00:27:53 +0000477int pthread_detach(pthread_t th)
478{
sewardj20917d82002-05-28 01:36:45 +0000479 int res;
480 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000481 /* First we enquire as to the current detach state. */
482 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000483 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000484 2 /* get */, th, 0, 0);
485 if (res == -1) /* not found */
486 return ESRCH;
487 if (res == 1) /* already detached */
488 return EINVAL;
489 if (res == 0) {
490 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
491 VG_USERREQ__SET_OR_GET_DETACH,
492 1 /* set */, th, 0, 0);
493 assert(res == 0);
494 return 0;
495 }
496 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000497}
498
499
sewardjf8f819e2002-04-17 23:21:37 +0000500/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000501 CLEANUP STACKS
502 ------------------------------------------------ */
503
504void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
505 void (*__routine) (void *),
506 void *__arg)
507{
508 int res;
509 CleanupEntry cu;
510 ensure_valgrind("_pthread_cleanup_push");
511 cu.fn = __routine;
512 cu.arg = __arg;
513 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
514 VG_USERREQ__CLEANUP_PUSH,
515 &cu, 0, 0, 0);
516 assert(res == 0);
517}
518
519
520void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
521 void (*__routine) (void *),
522 void *__arg)
523{
524 /* As _pthread_cleanup_push, but first save the thread's original
525 cancellation type in __buffer and set it to Deferred. */
526 int orig_ctype;
527 ensure_valgrind("_pthread_cleanup_push_defer");
528 /* Set to Deferred, and put the old cancellation type in res. */
529 assert(-1 != PTHREAD_CANCEL_DEFERRED);
530 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
531 assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
532 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
533 VG_USERREQ__SET_CANCELTYPE,
534 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
535 assert(orig_ctype != -1);
536 *((int*)(__buffer)) = orig_ctype;
537 /* Now push the cleanup. */
538 _pthread_cleanup_push(NULL, __routine, __arg);
539}
540
541
542void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
543 int __execute)
544{
545 int res;
546 CleanupEntry cu;
547 ensure_valgrind("_pthread_cleanup_push");
548 cu.fn = cu.arg = NULL; /* paranoia */
549 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
550 VG_USERREQ__CLEANUP_POP,
551 &cu, 0, 0, 0);
552 if (res == 0) {
553 /* pop succeeded */
554 if (__execute) {
555 cu.fn ( cu.arg );
556 }
557 return;
558 }
559 if (res == -1) {
560 /* stack underflow */
561 return;
562 }
563 barf("_pthread_cleanup_pop");
564}
565
566
567void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
568 int __execute)
569{
570 int orig_ctype, fake_ctype;
571 /* As _pthread_cleanup_pop, but after popping/running the handler,
572 restore the thread's original cancellation type from the first
573 word of __buffer. */
574 _pthread_cleanup_pop(NULL, __execute);
575 orig_ctype = *((int*)(__buffer));
576 assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
577 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
578 assert(-1 != PTHREAD_CANCEL_DEFERRED);
579 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
580 assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
581 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
582 VG_USERREQ__SET_CANCELTYPE,
583 orig_ctype, 0, 0, 0);
584 assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
585}
586
587
588/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000589 MUTEX ATTRIBUTES
590 ------------------------------------------------ */
591
sewardj5905fae2002-04-26 13:25:00 +0000592int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000593{
sewardjf8f819e2002-04-17 23:21:37 +0000594 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000595 return 0;
sewardje663cb92002-04-12 10:26:32 +0000596}
597
sewardj5905fae2002-04-26 13:25:00 +0000598int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000599{
600 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000601# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000602 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000603 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000604# endif
sewardja1679dd2002-05-10 22:31:40 +0000605# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000606 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000607# endif
sewardjf8f819e2002-04-17 23:21:37 +0000608 case PTHREAD_MUTEX_RECURSIVE_NP:
609 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000610 attr->__mutexkind = type;
611 return 0;
612 default:
613 return EINVAL;
614 }
615}
616
sewardj5905fae2002-04-26 13:25:00 +0000617int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000618{
619 return 0;
620}
621
622
623/* ---------------------------------------------------
624 MUTEXes
625 ------------------------------------------------ */
626
sewardj5905fae2002-04-26 13:25:00 +0000627int __pthread_mutex_init(pthread_mutex_t *mutex,
628 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000629{
sewardj604ec3c2002-04-18 22:38:41 +0000630 mutex->__m_count = 0;
631 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
632 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
633 if (mutexattr)
634 mutex->__m_kind = mutexattr->__mutexkind;
635 return 0;
sewardje663cb92002-04-12 10:26:32 +0000636}
637
sewardj439d45e2002-05-03 20:43:10 +0000638
sewardj5905fae2002-04-26 13:25:00 +0000639int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000640{
641 int res;
sewardj436e0582002-04-26 14:31:40 +0000642 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000643 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000644 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
645 VG_USERREQ__PTHREAD_MUTEX_LOCK,
646 mutex, 0, 0, 0);
647 return res;
sewardj439d45e2002-05-03 20:43:10 +0000648 } else {
649 if (moans-- > 0)
650 not_inside("pthread_mutex_lock");
651 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000652 }
653}
654
sewardj439d45e2002-05-03 20:43:10 +0000655
sewardj5905fae2002-04-26 13:25:00 +0000656int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000657{
658 int res;
sewardj436e0582002-04-26 14:31:40 +0000659 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000660 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000661 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
662 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
663 mutex, 0, 0, 0);
664 return res;
sewardj439d45e2002-05-03 20:43:10 +0000665 } else {
666 if (moans-- > 0)
667 not_inside("pthread_mutex_trylock");
668 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000669 }
670}
671
sewardj439d45e2002-05-03 20:43:10 +0000672
sewardj5905fae2002-04-26 13:25:00 +0000673int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000674{
675 int res;
sewardj436e0582002-04-26 14:31:40 +0000676 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000677 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000678 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
679 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
680 mutex, 0, 0, 0);
681 return res;
sewardj439d45e2002-05-03 20:43:10 +0000682 } else {
683 if (moans-- > 0)
684 not_inside("pthread_mutex_unlock");
685 return 0;
sewardje663cb92002-04-12 10:26:32 +0000686 }
687}
688
sewardj439d45e2002-05-03 20:43:10 +0000689
sewardj5905fae2002-04-26 13:25:00 +0000690int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000691{
sewardj604ec3c2002-04-18 22:38:41 +0000692 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
693 need to involve it. */
694 if (mutex->__m_count > 0)
695 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000696 mutex->__m_count = 0;
697 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
698 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000699 return 0;
sewardje663cb92002-04-12 10:26:32 +0000700}
701
702
sewardjf8f819e2002-04-17 23:21:37 +0000703/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000704 CONDITION VARIABLES
705 ------------------------------------------------ */
706
707/* LinuxThreads supports no attributes for conditions. Hence ... */
708
709int pthread_condattr_init(pthread_condattr_t *attr)
710{
711 return 0;
712}
713
sewardj0738a592002-04-20 13:59:33 +0000714int pthread_condattr_destroy(pthread_condattr_t *attr)
715{
716 return 0;
717}
sewardj6072c362002-04-19 14:40:57 +0000718
719int pthread_cond_init( pthread_cond_t *cond,
720 const pthread_condattr_t *cond_attr)
721{
722 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
723 return 0;
724}
725
sewardjf854f472002-04-21 12:19:41 +0000726int pthread_cond_destroy(pthread_cond_t *cond)
727{
728 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000729 static int moans = N_MOANS;
730 if (moans-- > 0)
731 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000732 return 0;
733}
sewardj6072c362002-04-19 14:40:57 +0000734
735/* ---------------------------------------------------
736 SCHEDULING
737 ------------------------------------------------ */
738
739/* This is completely bogus. */
740int pthread_getschedparam(pthread_t target_thread,
741 int *policy,
742 struct sched_param *param)
743{
sewardj436e0582002-04-26 14:31:40 +0000744 static int moans = N_MOANS;
745 if (moans-- > 0)
746 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000747 if (policy) *policy = SCHED_OTHER;
sewardj2a1dcce2002-04-22 12:45:25 +0000748# ifdef GLIBC_2_1
749 if (param) param->sched_priority = 0; /* who knows */
750# else
sewardj6072c362002-04-19 14:40:57 +0000751 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000752# endif
sewardj6072c362002-04-19 14:40:57 +0000753 return 0;
754}
755
756int pthread_setschedparam(pthread_t target_thread,
757 int policy,
758 const struct sched_param *param)
759{
sewardj436e0582002-04-26 14:31:40 +0000760 static int moans = N_MOANS;
761 if (moans-- > 0)
762 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000763 return 0;
764}
765
sewardj3b5d8862002-04-20 13:53:23 +0000766int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
767{
768 int res;
769 ensure_valgrind("pthread_cond_wait");
770 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
771 VG_USERREQ__PTHREAD_COND_WAIT,
772 cond, mutex, 0, 0);
773 return res;
774}
775
sewardj5f07b662002-04-23 16:52:51 +0000776int pthread_cond_timedwait ( pthread_cond_t *cond,
777 pthread_mutex_t *mutex,
778 const struct timespec *abstime )
779{
780 int res;
781 unsigned int ms_now, ms_end;
782 struct timeval timeval_now;
783 unsigned long long int ull_ms_now_after_1970;
784 unsigned long long int ull_ms_end_after_1970;
785
786 ensure_valgrind("pthread_cond_timedwait");
787 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
788 VG_USERREQ__READ_MILLISECOND_TIMER,
789 0, 0, 0, 0);
790 assert(ms_now != 0xFFFFFFFF);
791 res = gettimeofday(&timeval_now, NULL);
792 assert(res == 0);
793
794 ull_ms_now_after_1970
795 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
796 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
797 ull_ms_end_after_1970
798 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
799 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
800 assert(ull_ms_end_after_1970 >= ull_ms_now_after_1970);
801 ms_end
802 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
803 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
804 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
805 cond, mutex, ms_end, 0);
806 return res;
807}
808
809
sewardj3b5d8862002-04-20 13:53:23 +0000810int pthread_cond_signal(pthread_cond_t *cond)
811{
812 int res;
813 ensure_valgrind("pthread_cond_signal");
814 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
815 VG_USERREQ__PTHREAD_COND_SIGNAL,
816 cond, 0, 0, 0);
817 return res;
818}
819
820int pthread_cond_broadcast(pthread_cond_t *cond)
821{
822 int res;
823 ensure_valgrind("pthread_cond_broadcast");
824 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
825 VG_USERREQ__PTHREAD_COND_BROADCAST,
826 cond, 0, 0, 0);
827 return res;
828}
829
sewardj6072c362002-04-19 14:40:57 +0000830
831/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000832 CANCELLATION
833 ------------------------------------------------ */
834
sewardj853f55d2002-04-26 00:27:53 +0000835int pthread_setcancelstate(int state, int *oldstate)
836{
sewardj20917d82002-05-28 01:36:45 +0000837 int res;
838 ensure_valgrind("pthread_setcancelstate");
839 if (state != PTHREAD_CANCEL_ENABLE
840 && state != PTHREAD_CANCEL_DISABLE)
841 return EINVAL;
842 assert(-1 != PTHREAD_CANCEL_ENABLE);
843 assert(-1 != PTHREAD_CANCEL_DISABLE);
844 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
845 VG_USERREQ__SET_CANCELSTATE,
846 state, 0, 0, 0);
847 assert(res != -1);
848 if (oldstate)
849 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +0000850 return 0;
851}
852
sewardje663cb92002-04-12 10:26:32 +0000853int pthread_setcanceltype(int type, int *oldtype)
854{
sewardj20917d82002-05-28 01:36:45 +0000855 int res;
856 ensure_valgrind("pthread_setcanceltype");
857 if (type != PTHREAD_CANCEL_DEFERRED
858 && type != PTHREAD_CANCEL_ASYNCHRONOUS)
859 return EINVAL;
860 assert(-1 != PTHREAD_CANCEL_DEFERRED);
861 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
862 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
863 VG_USERREQ__SET_CANCELTYPE,
864 type, 0, 0, 0);
865 assert(res != -1);
866 if (oldtype)
867 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +0000868 return 0;
869}
870
sewardje663cb92002-04-12 10:26:32 +0000871int pthread_cancel(pthread_t thread)
872{
873 int res;
874 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +0000875 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
876 VG_USERREQ__SET_CANCELPEND,
877 thread, &thread_exit_wrapper, 0, 0);
878 assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +0000879 return res;
880}
881
sewardj20917d82002-05-28 01:36:45 +0000882__inline__
sewardj853f55d2002-04-26 00:27:53 +0000883void pthread_testcancel(void)
884{
sewardj20917d82002-05-28 01:36:45 +0000885 int res;
886 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
887 VG_USERREQ__TESTCANCEL,
888 0, 0, 0, 0);
889 assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +0000890}
891
sewardj20917d82002-05-28 01:36:45 +0000892
sewardj853f55d2002-04-26 00:27:53 +0000893/*-------------------*/
894static pthread_mutex_t massacre_mx = PTHREAD_MUTEX_INITIALIZER;
895
896void __pthread_kill_other_threads_np ( void )
897{
898 int i, res, me;
sewardj68b2dd92002-05-10 21:03:56 +0000899 __pthread_mutex_lock(&massacre_mx);
sewardj853f55d2002-04-26 00:27:53 +0000900 me = pthread_self();
901 for (i = 1; i < VG_N_THREADS; i++) {
902 if (i == me) continue;
903 res = pthread_cancel(i);
sewardj436e0582002-04-26 14:31:40 +0000904 if (0 && res == 0)
sewardj853f55d2002-04-26 00:27:53 +0000905 printf("----------- NUKED %d\n", i);
906 }
sewardj68b2dd92002-05-10 21:03:56 +0000907 __pthread_mutex_unlock(&massacre_mx);
sewardj853f55d2002-04-26 00:27:53 +0000908}
909
sewardje663cb92002-04-12 10:26:32 +0000910
sewardjf8f819e2002-04-17 23:21:37 +0000911/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +0000912 SIGNALS
913 ------------------------------------------------ */
914
915#include <signal.h>
916
917int pthread_sigmask(int how, const sigset_t *newmask,
918 sigset_t *oldmask)
919{
920 int res;
921
922 /* A bit subtle, because the scheduler expects newmask and oldmask
923 to be vki_sigset_t* rather than sigset_t*, and the two are
924 different. Fortunately the first 64 bits of a sigset_t are
925 exactly a vki_sigset_t, so we just pass the pointers through
926 unmodified. Haaaack!
927
928 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +0000929 constants to VKI_ constants, so that the former do not have to
930 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +0000931
932 ensure_valgrind("pthread_sigmask");
933
934 switch (how) {
sewardj018f7622002-05-15 21:13:39 +0000935 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
936 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
937 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardjb48e5002002-05-13 00:16:03 +0000938 default: return EINVAL;
939 }
940
941 /* Crude check */
942 if (newmask == NULL)
943 return EFAULT;
944
945 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
946 VG_USERREQ__PTHREAD_SIGMASK,
947 how, newmask, oldmask, 0);
948
949 /* The scheduler tells us of any memory violations. */
950 return res == 0 ? 0 : EFAULT;
951}
952
953
954int sigwait ( const sigset_t* set, int* sig )
955{
956 int res;
957 ensure_valgrind("sigwait");
958 /* As with pthread_sigmask we deliberately confuse sigset_t with
959 vki_ksigset_t. */
960 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
961 VG_USERREQ__SIGWAIT,
962 set, sig, 0, 0);
963 return res;
964}
965
966
sewardj018f7622002-05-15 21:13:39 +0000967int pthread_kill(pthread_t thread, int signo)
968{
969 int res;
970 ensure_valgrind("pthread_kill");
971 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
972 VG_USERREQ__PTHREAD_KILL,
973 thread, signo, 0, 0);
974 return res;
975}
976
977
sewardj3665ded2002-05-16 16:57:25 +0000978/* Copied verbatim from Linuxthreads */
979/* Redefine raise() to send signal to calling thread only,
980 as per POSIX 1003.1c */
981int raise (int sig)
982{
983 int retcode = pthread_kill(pthread_self(), sig);
984 if (retcode == 0)
985 return 0;
986 else {
987 errno = retcode;
988 return -1;
989 }
990}
991
992
sewardjb48e5002002-05-13 00:16:03 +0000993/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000994 THREAD-SPECIFICs
995 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000996
sewardj5905fae2002-04-26 13:25:00 +0000997int __pthread_key_create(pthread_key_t *key,
998 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +0000999{
sewardj5f07b662002-04-23 16:52:51 +00001000 int res;
1001 ensure_valgrind("pthread_key_create");
1002 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1003 VG_USERREQ__PTHREAD_KEY_CREATE,
1004 key, destr_function, 0, 0);
1005 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001006}
1007
1008int pthread_key_delete(pthread_key_t key)
1009{
sewardj436e0582002-04-26 14:31:40 +00001010 static int moans = N_MOANS;
1011 if (moans-- > 0)
1012 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +00001013 return 0;
1014}
1015
sewardj5905fae2002-04-26 13:25:00 +00001016int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001017{
sewardj5f07b662002-04-23 16:52:51 +00001018 int res;
1019 ensure_valgrind("pthread_setspecific");
1020 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1021 VG_USERREQ__PTHREAD_SETSPECIFIC,
1022 key, pointer, 0, 0);
1023 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001024}
1025
sewardj5905fae2002-04-26 13:25:00 +00001026void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001027{
sewardj5f07b662002-04-23 16:52:51 +00001028 int res;
1029 ensure_valgrind("pthread_getspecific");
1030 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1031 VG_USERREQ__PTHREAD_GETSPECIFIC,
1032 key, 0 , 0, 0);
1033 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001034}
1035
sewardjf8f819e2002-04-17 23:21:37 +00001036
1037/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001038 ONCEry
1039 ------------------------------------------------ */
1040
1041static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1042
1043
sewardj5905fae2002-04-26 13:25:00 +00001044int __pthread_once ( pthread_once_t *once_control,
1045 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001046{
1047 int res;
1048 ensure_valgrind("pthread_once");
1049
sewardj68b2dd92002-05-10 21:03:56 +00001050 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001051
sewardj68b2dd92002-05-10 21:03:56 +00001052 if (res != 0) {
1053 printf("res = %d\n",res);
sewardj89d3d852002-04-24 19:21:39 +00001054 barf("pthread_once: Looks like your program's "
1055 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001056 }
sewardj89d3d852002-04-24 19:21:39 +00001057
1058 if (*once_control == 0) {
1059 *once_control = 1;
1060 init_routine();
1061 }
1062
sewardj68b2dd92002-05-10 21:03:56 +00001063 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001064
1065 return 0;
1066}
1067
1068
1069/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001070 MISC
1071 ------------------------------------------------ */
1072
sewardj5905fae2002-04-26 13:25:00 +00001073int __pthread_atfork ( void (*prepare)(void),
1074 void (*parent)(void),
1075 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001076{
sewardj436e0582002-04-26 14:31:40 +00001077 static int moans = N_MOANS;
1078 if (moans-- > 0)
1079 ignored("pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +00001080 return 0;
1081}
1082
1083
sewardjbb990782002-05-08 02:01:14 +00001084__attribute__((weak))
1085void __pthread_initialize ( void )
1086{
sewardjbea1caa2002-05-10 23:20:58 +00001087 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001088}
1089
1090
sewardj853f55d2002-04-26 00:27:53 +00001091/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001092 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001093 ------------------------------------------------ */
1094
sewardj3b13f0e2002-04-25 20:17:29 +00001095#include <resolv.h>
1096static int thread_specific_errno[VG_N_THREADS];
1097static int thread_specific_h_errno[VG_N_THREADS];
1098static struct __res_state
1099 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001100
sewardj3b13f0e2002-04-25 20:17:29 +00001101int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001102{
1103 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001104 /* ensure_valgrind("__errno_location"); */
1105 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001106 VG_USERREQ__PTHREAD_GET_THREADID,
1107 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001108 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001109 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001110 barf("__errno_location: invalid ThreadId");
1111 return & thread_specific_errno[tid];
1112}
1113
1114int* __h_errno_location ( void )
1115{
1116 int tid;
1117 /* ensure_valgrind("__h_errno_location"); */
1118 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1119 VG_USERREQ__PTHREAD_GET_THREADID,
1120 0, 0, 0, 0);
1121 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001122 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001123 barf("__h_errno_location: invalid ThreadId");
1124 return & thread_specific_h_errno[tid];
1125}
1126
1127struct __res_state* __res_state ( void )
1128{
1129 int tid;
1130 /* ensure_valgrind("__res_state"); */
1131 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1132 VG_USERREQ__PTHREAD_GET_THREADID,
1133 0, 0, 0, 0);
1134 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001135 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001136 barf("__res_state: invalid ThreadId");
1137 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001138}
1139
1140
sewardj5716dbb2002-04-26 03:28:18 +00001141/* ---------------------------------------------------
1142 LIBC-PRIVATE SPECIFIC DATA
1143 ------------------------------------------------ */
1144
1145/* Relies on assumption that initial private data is NULL. This
1146 should be fixed somehow. */
1147
1148/* The allowable keys (indices) (all 2 of them).
1149 From sysdeps/pthread/bits/libc-tsd.h
1150*/
sewardj70adeb22002-04-27 01:35:38 +00001151#define N_LIBC_TSD_EXTRA_KEYS 1
1152
sewardj5716dbb2002-04-26 03:28:18 +00001153enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1154 _LIBC_TSD_KEY_DL_ERROR,
1155 _LIBC_TSD_KEY_N };
1156
1157/* Auto-initialising subsystem. libc_specifics_inited is set
1158 after initialisation. libc_specifics_inited_mx guards it. */
1159static int libc_specifics_inited = 0;
1160static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1161
1162/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001163static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1164 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001165
1166/* Initialise the keys, if they are not already initialise. */
1167static
1168void init_libc_tsd_keys ( void )
1169{
1170 int res, i;
1171 pthread_key_t k;
1172
1173 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1174 if (res != 0) barf("init_libc_tsd_keys: lock");
1175
1176 if (libc_specifics_inited == 0) {
1177 /* printf("INIT libc specifics\n"); */
1178 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001179 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001180 res = pthread_key_create(&k, NULL);
1181 if (res != 0) barf("init_libc_tsd_keys: create");
1182 libc_specifics_keys[i] = k;
1183 }
1184 }
1185
1186 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1187 if (res != 0) barf("init_libc_tsd_keys: unlock");
1188}
1189
1190
1191static int
1192libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1193 const void * pointer )
1194{
sewardj70adeb22002-04-27 01:35:38 +00001195 int res;
1196 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001197 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001198 if (key < _LIBC_TSD_KEY_MALLOC
1199 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001200 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001201 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1202 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001203 "valgrind's libpthread.so: libc_internal_tsd_set: "
1204 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001205 init_libc_tsd_keys();
1206 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1207 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1208 return 0;
1209}
1210
1211static void *
1212libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1213{
sewardj70adeb22002-04-27 01:35:38 +00001214 void* v;
1215 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001216 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001217 if (key < _LIBC_TSD_KEY_MALLOC
1218 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001219 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001220 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1221 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001222 "valgrind's libpthread.so: libc_internal_tsd_get: "
1223 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001224 init_libc_tsd_keys();
1225 v = pthread_getspecific(libc_specifics_keys[key]);
1226 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1227 return v;
1228}
1229
1230
1231
1232
sewardj70adeb22002-04-27 01:35:38 +00001233int (*__libc_internal_tsd_set)
1234 (enum __libc_tsd_key_t key, const void * pointer)
1235 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001236
sewardj70adeb22002-04-27 01:35:38 +00001237void* (*__libc_internal_tsd_get)
1238 (enum __libc_tsd_key_t key)
1239 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001240
1241
sewardje663cb92002-04-12 10:26:32 +00001242/* ---------------------------------------------------------------------
1243 These are here (I think) because they are deemed cancellation
1244 points by POSIX. For the moment we'll simply pass the call along
1245 to the corresponding thread-unaware (?) libc routine.
1246 ------------------------------------------------------------------ */
1247
sewardje663cb92002-04-12 10:26:32 +00001248#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001249#include <sys/types.h>
1250#include <sys/socket.h>
1251
sewardjd529a442002-05-04 19:49:21 +00001252#ifdef GLIBC_2_1
1253extern
1254int __sigaction
1255 (int signum,
1256 const struct sigaction *act,
1257 struct sigaction *oldact);
1258#else
sewardje663cb92002-04-12 10:26:32 +00001259extern
1260int __libc_sigaction
1261 (int signum,
1262 const struct sigaction *act,
1263 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001264#endif
sewardje663cb92002-04-12 10:26:32 +00001265int sigaction(int signum,
1266 const struct sigaction *act,
1267 struct sigaction *oldact)
1268{
sewardj2a1dcce2002-04-22 12:45:25 +00001269# ifdef GLIBC_2_1
1270 return __sigaction(signum, act, oldact);
1271# else
sewardj45b4b372002-04-16 22:50:32 +00001272 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001273# endif
sewardje663cb92002-04-12 10:26:32 +00001274}
1275
1276
1277extern
1278int __libc_connect(int sockfd,
1279 const struct sockaddr *serv_addr,
1280 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001281__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001282int connect(int sockfd,
1283 const struct sockaddr *serv_addr,
1284 socklen_t addrlen)
1285{
sewardj45b4b372002-04-16 22:50:32 +00001286 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001287}
1288
1289
1290extern
1291int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001292__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001293int fcntl(int fd, int cmd, long arg)
1294{
sewardj45b4b372002-04-16 22:50:32 +00001295 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001296}
1297
1298
1299extern
1300ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001301__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001302ssize_t write(int fd, const void *buf, size_t count)
1303{
sewardj45b4b372002-04-16 22:50:32 +00001304 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001305}
1306
1307
1308extern
1309ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001310__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001311ssize_t read(int fd, void *buf, size_t count)
1312{
sewardj45b4b372002-04-16 22:50:32 +00001313 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001314}
1315
sewardjbe32e452002-04-24 20:29:58 +00001316
1317extern
sewardj853f55d2002-04-26 00:27:53 +00001318int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001319__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001320int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001321{
sewardj853f55d2002-04-26 00:27:53 +00001322 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001323}
1324
sewardje663cb92002-04-12 10:26:32 +00001325
1326extern
sewardj853f55d2002-04-26 00:27:53 +00001327int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001328__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001329int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001330{
sewardj853f55d2002-04-26 00:27:53 +00001331 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001332}
1333
1334
1335extern
1336int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001337__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001338int close(int fd)
1339{
sewardj45b4b372002-04-16 22:50:32 +00001340 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001341}
1342
1343
1344extern
1345int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001346__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001347int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1348{
sewardj705d3cb2002-05-23 13:13:12 +00001349 wait_for_fd_to_be_readable_or_erring(s);
sewardj45b4b372002-04-16 22:50:32 +00001350 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001351}
1352
1353
1354extern
1355pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001356pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001357{
sewardj45b4b372002-04-16 22:50:32 +00001358 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001359}
1360
1361
1362extern
1363pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001364__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001365pid_t waitpid(pid_t pid, int *status, int options)
1366{
sewardj45b4b372002-04-16 22:50:32 +00001367 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001368}
1369
1370
1371extern
1372int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001373__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001374int nanosleep(const struct timespec *req, struct timespec *rem)
1375{
1376 return __libc_nanosleep(req, rem);
1377}
1378
sewardjbe32e452002-04-24 20:29:58 +00001379
sewardje663cb92002-04-12 10:26:32 +00001380extern
1381int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001382__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001383int fsync(int fd)
1384{
sewardj45b4b372002-04-16 22:50:32 +00001385 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001386}
1387
sewardjbe32e452002-04-24 20:29:58 +00001388
sewardj70c75362002-04-13 04:18:32 +00001389extern
1390off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001391__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001392off_t lseek(int fildes, off_t offset, int whence)
1393{
sewardj45b4b372002-04-16 22:50:32 +00001394 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001395}
1396
sewardjbe32e452002-04-24 20:29:58 +00001397
1398extern
1399__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001400__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001401__off64_t lseek64(int fildes, __off64_t offset, int whence)
1402{
1403 return __libc_lseek64(fildes, offset, whence);
1404}
1405
1406
sewardj726c4122002-05-16 23:39:10 +00001407extern
1408ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1409 __off64_t __offset);
1410ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1411 __off64_t __offset)
1412{
1413 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1414}
1415
1416
sewardja18e2102002-05-18 10:43:22 +00001417extern
1418ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1419 __off64_t __offset);
1420ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1421 __off64_t __offset)
1422{
1423 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1424}
1425
sewardj726c4122002-05-16 23:39:10 +00001426
sewardj39b93b12002-05-18 10:56:27 +00001427extern
1428ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1429__attribute__((weak))
1430ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1431{
1432 return __libc_pwrite(fd, buf, count, offset);
1433}
1434
1435
1436extern
1437ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1438__attribute__((weak))
1439ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1440{
1441 return __libc_pread(fd, buf, count, offset);
1442}
1443
1444
sewardj6af4b5d2002-04-16 04:40:49 +00001445extern
1446void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001447/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001448void longjmp(jmp_buf env, int val)
1449{
1450 __libc_longjmp(env, val);
1451}
1452
sewardjbe32e452002-04-24 20:29:58 +00001453
sewardj6af4b5d2002-04-16 04:40:49 +00001454extern
1455int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001456__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001457int send(int s, const void *msg, size_t len, int flags)
1458{
1459 return __libc_send(s, msg, len, flags);
1460}
1461
sewardjbe32e452002-04-24 20:29:58 +00001462
sewardj1e8cdc92002-04-18 11:37:52 +00001463extern
1464int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001465__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001466int recv(int s, void *buf, size_t len, int flags)
1467{
1468 return __libc_recv(s, buf, len, flags);
1469}
1470
sewardjbe32e452002-04-24 20:29:58 +00001471
sewardj3665ded2002-05-16 16:57:25 +00001472extern
1473int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1474__attribute__((weak))
1475int sendmsg(int s, const struct msghdr *msg, int flags)
1476{
1477 return __libc_sendmsg(s, msg, flags);
1478}
1479
1480
sewardj796d6a22002-04-24 02:28:34 +00001481extern
sewardj436e0582002-04-26 14:31:40 +00001482int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1483 struct sockaddr *from, socklen_t *fromlen);
1484__attribute__((weak))
1485int recvfrom(int s, void *buf, size_t len, int flags,
1486 struct sockaddr *from, socklen_t *fromlen)
1487{
1488 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1489}
1490
1491
1492extern
sewardj796d6a22002-04-24 02:28:34 +00001493int __libc_sendto(int s, const void *msg, size_t len, int flags,
1494 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001495__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001496int sendto(int s, const void *msg, size_t len, int flags,
1497 const struct sockaddr *to, socklen_t tolen)
1498{
1499 return __libc_sendto(s, msg, len, flags, to, tolen);
1500}
1501
sewardjbe32e452002-04-24 20:29:58 +00001502
sewardj369b1702002-04-24 13:28:15 +00001503extern
1504int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001505__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001506int system(const char* str)
1507{
1508 return __libc_system(str);
1509}
1510
sewardjbe32e452002-04-24 20:29:58 +00001511
sewardjab0b1c32002-04-24 19:26:47 +00001512extern
1513pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001514__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001515pid_t wait(int *status)
1516{
1517 return __libc_wait(status);
1518}
1519
sewardj45b4b372002-04-16 22:50:32 +00001520
sewardj67f1d582002-05-24 02:11:32 +00001521extern
1522int __libc_msync(const void *start, size_t length, int flags);
1523__attribute__((weak))
1524int msync(const void *start, size_t length, int flags)
1525{
1526 return __libc_msync(start, length, flags);
1527}
1528
sewardj5905fae2002-04-26 13:25:00 +00001529
sewardj3b13f0e2002-04-25 20:17:29 +00001530/* ---------------------------------------------------------------------
1531 Nonblocking implementations of select() and poll(). This stuff will
1532 surely rot your mind.
1533 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001534
sewardj08a4c3f2002-04-13 03:45:44 +00001535/*--------------------------------------------------*/
1536
1537#include "vg_kerneliface.h"
1538
1539static
1540__inline__
1541int is_kerror ( int res )
1542{
1543 if (res >= -4095 && res <= -1)
1544 return 1;
1545 else
1546 return 0;
1547}
1548
1549
1550static
1551int my_do_syscall1 ( int syscallno, int arg1 )
1552{
1553 int __res;
1554 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1555 : "=a" (__res)
1556 : "0" (syscallno),
1557 "d" (arg1) );
1558 return __res;
1559}
1560
1561static
1562int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001563 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001564{
1565 int __res;
1566 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1567 : "=a" (__res)
1568 : "0" (syscallno),
1569 "d" (arg1),
1570 "c" (arg2) );
1571 return __res;
1572}
1573
1574static
sewardjf854f472002-04-21 12:19:41 +00001575int my_do_syscall3 ( int syscallno,
1576 int arg1, int arg2, int arg3 )
1577{
1578 int __res;
1579 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1580 : "=a" (__res)
1581 : "0" (syscallno),
1582 "S" (arg1),
1583 "c" (arg2),
1584 "d" (arg3) );
1585 return __res;
1586}
1587
1588static
sewardj08a4c3f2002-04-13 03:45:44 +00001589int do_syscall_select( int n,
1590 vki_fd_set* readfds,
1591 vki_fd_set* writefds,
1592 vki_fd_set* exceptfds,
1593 struct vki_timeval * timeout )
1594{
1595 int res;
1596 int args[5];
1597 args[0] = n;
1598 args[1] = (int)readfds;
1599 args[2] = (int)writefds;
1600 args[3] = (int)exceptfds;
1601 args[4] = (int)timeout;
1602 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001603 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001604}
1605
1606
1607/* This is a wrapper round select(), which makes it thread-safe,
1608 meaning that only this thread will block, rather than the entire
1609 process. This wrapper in turn depends on nanosleep() not to block
1610 the entire process, but I think (hope? suspect?) that POSIX
1611 pthreads guarantees that to be the case.
1612
1613 Basic idea is: modify the timeout parameter to select so that it
1614 returns immediately. Poll like this until select returns non-zero,
1615 indicating something interesting happened, or until our time is up.
1616 Space out the polls with nanosleeps of say 20 milliseconds, which
1617 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001618
1619 Assumes:
1620 * (checked via assert) types fd_set and vki_fd_set are identical.
1621 * (checked via assert) types timeval and vki_timeval are identical.
1622 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1623 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001624*/
sewardj08a4c3f2002-04-13 03:45:44 +00001625
sewardj5905fae2002-04-26 13:25:00 +00001626/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001627int select ( int n,
1628 fd_set *rfds,
1629 fd_set *wfds,
1630 fd_set *xfds,
1631 struct timeval *timeout )
1632{
sewardj5f07b662002-04-23 16:52:51 +00001633 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001634 int res;
1635 fd_set rfds_copy;
1636 fd_set wfds_copy;
1637 fd_set xfds_copy;
1638 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001639 struct vki_timeval zero_timeout;
1640 struct vki_timespec nanosleep_interval;
1641
sewardj5f07b662002-04-23 16:52:51 +00001642 /* gcc's complains about ms_end being used uninitialised -- classic
1643 case it can't understand, where ms_end is both defined and used
1644 only if timeout != NULL. Hence ... */
1645 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001646
1647 /* We assume that the kernel and libc data layouts are identical
1648 for the following types. These asserts provide a crude
1649 check. */
1650 if (sizeof(fd_set) != sizeof(vki_fd_set)
1651 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1652 barf("valgrind's hacky non-blocking select(): data sizes error");
1653
sewardj5f07b662002-04-23 16:52:51 +00001654 /* Detect the current time and simultaneously find out if we are
1655 running on Valgrind. */
1656 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1657 VG_USERREQ__READ_MILLISECOND_TIMER,
1658 0, 0, 0, 0);
1659
1660 /* If a zero timeout specified, this call is harmless. Also go
1661 this route if we're not running on Valgrind, for whatever
1662 reason. */
1663 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1664 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001665 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001666 (vki_fd_set*)wfds,
1667 (vki_fd_set*)xfds,
1668 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001669 if (is_kerror(res)) {
1670 * (__errno_location()) = -res;
1671 return -1;
1672 } else {
1673 return res;
1674 }
1675 }
sewardj08a4c3f2002-04-13 03:45:44 +00001676
sewardj5f07b662002-04-23 16:52:51 +00001677 /* If a timeout was specified, set ms_end to be the end millisecond
1678 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001679 if (timeout) {
1680 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
1681 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001682 ms_end = ms_now;
1683 ms_end += (timeout->tv_usec / 1000);
1684 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001685 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +00001686 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001687 }
1688
1689 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1690
1691 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001692 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001693 while (1) {
1694 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +00001695 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1696 VG_USERREQ__READ_MILLISECOND_TIMER,
1697 0, 0, 0, 0);
1698 assert(ms_now != 0xFFFFFFFF);
1699 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +00001700 /* timeout; nothing interesting happened. */
1701 if (rfds) FD_ZERO(rfds);
1702 if (wfds) FD_ZERO(wfds);
1703 if (xfds) FD_ZERO(xfds);
1704 return 0;
1705 }
1706 }
1707
1708 /* These could be trashed each time round the loop, so restore
1709 them each time. */
1710 if (rfds) rfds_copy = *rfds;
1711 if (wfds) wfds_copy = *wfds;
1712 if (xfds) xfds_copy = *xfds;
1713
1714 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1715
1716 res = do_syscall_select( n,
1717 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1718 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1719 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1720 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001721 if (is_kerror(res)) {
1722 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001723 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001724 * (__errno_location()) = -res;
1725 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001726 }
1727 if (res > 0) {
1728 /* one or more fds is ready. Copy out resulting sets and
1729 return. */
1730 if (rfds) *rfds = rfds_copy;
1731 if (wfds) *wfds = wfds_copy;
1732 if (xfds) *xfds = xfds_copy;
1733 return res;
1734 }
1735 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1736 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001737 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001738 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001739 /* It's critical here that valgrind's nanosleep implementation
1740 is nonblocking. */
1741 (void)my_do_syscall2(__NR_nanosleep,
1742 (int)(&nanosleep_interval), (int)NULL);
1743 }
1744}
1745
1746
1747
1748
1749#include <sys/poll.h>
1750
sewardj72d58482002-04-24 02:20:20 +00001751#ifdef GLIBC_2_1
1752typedef unsigned long int nfds_t;
1753#endif
1754
sewardj705d3cb2002-05-23 13:13:12 +00001755
sewardj5905fae2002-04-26 13:25:00 +00001756/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00001757int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1758{
sewardj5f07b662002-04-23 16:52:51 +00001759 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001760 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001761 struct vki_timespec nanosleep_interval;
1762
1763 ensure_valgrind("poll");
1764
sewardj5f07b662002-04-23 16:52:51 +00001765 /* Detect the current time and simultaneously find out if we are
1766 running on Valgrind. */
1767 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1768 VG_USERREQ__READ_MILLISECOND_TIMER,
1769 0, 0, 0, 0);
1770
sewardjf854f472002-04-21 12:19:41 +00001771 if (/* CHECK SIZES FOR struct pollfd */
1772 sizeof(struct timeval) != sizeof(struct vki_timeval))
1773 barf("valgrind's hacky non-blocking poll(): data sizes error");
1774
sewardj5f07b662002-04-23 16:52:51 +00001775 /* dummy initialisation to keep gcc -Wall happy */
1776 ms_end = 0;
1777
1778 /* If a zero timeout specified, this call is harmless. Also do
1779 this if not running on Valgrind. */
1780 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001781 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1782 if (is_kerror(res)) {
1783 * (__errno_location()) = -res;
1784 return -1;
1785 } else {
1786 return res;
1787 }
1788 }
1789
sewardj5f07b662002-04-23 16:52:51 +00001790 /* If a timeout was specified, set ms_end to be the end wallclock
1791 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001792 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00001793 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001794 }
1795
1796 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1797
1798 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1799 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001800 assert(__timeout != 0);
1801
sewardjf854f472002-04-21 12:19:41 +00001802 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001803 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001804 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1805 VG_USERREQ__READ_MILLISECOND_TIMER,
1806 0, 0, 0, 0);
1807 assert(ms_now != 0xFFFFFFFF);
1808 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001809 /* timeout; nothing interesting happened. */
1810 for (i = 0; i < __nfds; i++)
1811 __fds[i].revents = 0;
1812 return 0;
1813 }
1814 }
1815
sewardj5f07b662002-04-23 16:52:51 +00001816 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001817 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1818 if (is_kerror(res)) {
1819 /* Some kind of error. Set errno and return. */
1820 * (__errno_location()) = -res;
1821 return -1;
1822 }
1823 if (res > 0) {
1824 /* One or more fds is ready. Return now. */
1825 return res;
1826 }
1827 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1828 /* nanosleep and go round again */
1829 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001830 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001831 /* It's critical here that valgrind's nanosleep implementation
1832 is nonblocking. */
1833 (void)my_do_syscall2(__NR_nanosleep,
1834 (int)(&nanosleep_interval), (int)NULL);
1835 }
1836}
sewardj3b13f0e2002-04-25 20:17:29 +00001837
1838
sewardj705d3cb2002-05-23 13:13:12 +00001839/* Helper function used to make accept() non-blocking. Idea is to use
1840 the above nonblocking poll() to make this thread ONLY wait for the
1841 specified fd to become ready, and then return. */
1842static void wait_for_fd_to_be_readable_or_erring ( int fd )
1843{
1844 struct pollfd pfd;
sewardj6e6cbaa2002-05-24 02:12:52 +00001845 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardj705d3cb2002-05-23 13:13:12 +00001846 pfd.fd = fd;
1847 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
1848 /* ... but not POLLOUT, you may notice. */
1849 pfd.revents = 0;
1850 (void)poll(&pfd, 1, -1 /* forever */);
1851}
1852
1853
sewardj3b13f0e2002-04-25 20:17:29 +00001854/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00001855 Hacky implementation of semaphores.
1856 ------------------------------------------------------------------ */
1857
1858#include <semaphore.h>
1859
1860/* This is a terrible way to do the remapping. Plan is to import an
1861 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00001862
1863typedef
1864 struct {
1865 pthread_mutex_t se_mx;
1866 pthread_cond_t se_cv;
1867 int count;
1868 }
1869 vg_sem_t;
1870
1871static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
1872
1873static int se_remap_used = 0;
1874static sem_t* se_remap_orig[VG_N_SEMAPHORES];
1875static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
1876
1877static vg_sem_t* se_remap ( sem_t* orig )
1878{
1879 int res, i;
1880 res = __pthread_mutex_lock(&se_remap_mx);
1881 assert(res == 0);
1882
1883 for (i = 0; i < se_remap_used; i++) {
1884 if (se_remap_orig[i] == orig)
1885 break;
1886 }
1887 if (i == se_remap_used) {
1888 if (se_remap_used == VG_N_SEMAPHORES) {
1889 res = pthread_mutex_unlock(&se_remap_mx);
1890 assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00001891 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00001892 }
1893 se_remap_used++;
1894 se_remap_orig[i] = orig;
1895 /* printf("allocated semaphore %d\n", i); */
1896 }
1897 res = __pthread_mutex_unlock(&se_remap_mx);
1898 assert(res == 0);
1899 return &se_remap_new[i];
1900}
1901
1902
1903int sem_init(sem_t *sem, int pshared, unsigned int value)
1904{
1905 int res;
1906 vg_sem_t* vg_sem;
1907 ensure_valgrind("sem_init");
1908 if (pshared != 0) {
1909 errno = ENOSYS;
1910 return -1;
1911 }
1912 vg_sem = se_remap(sem);
1913 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
1914 assert(res == 0);
1915 res = pthread_cond_init(&vg_sem->se_cv, NULL);
1916 assert(res == 0);
1917 vg_sem->count = value;
1918 return 0;
1919}
1920
1921
1922int sem_wait ( sem_t* sem )
1923{
1924 int res;
1925 vg_sem_t* vg_sem;
1926 ensure_valgrind("sem_wait");
1927 vg_sem = se_remap(sem);
1928 res = __pthread_mutex_lock(&vg_sem->se_mx);
1929 assert(res == 0);
1930 while (vg_sem->count == 0) {
1931 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
1932 assert(res == 0);
1933 }
1934 vg_sem->count--;
1935 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1936 assert(res == 0);
1937 return 0;
1938}
1939
1940int sem_post ( sem_t* sem )
1941{
1942 int res;
1943 vg_sem_t* vg_sem;
1944 ensure_valgrind("sem_post");
1945 vg_sem = se_remap(sem);
1946 res = __pthread_mutex_lock(&vg_sem->se_mx);
1947 assert(res == 0);
1948 if (vg_sem->count == 0) {
1949 vg_sem->count++;
1950 res = pthread_cond_broadcast(&vg_sem->se_cv);
1951 assert(res == 0);
1952 } else {
1953 vg_sem->count++;
1954 }
1955 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1956 assert(res == 0);
1957 return 0;
1958}
1959
1960
1961int sem_trywait ( sem_t* sem )
1962{
1963 int ret, res;
1964 vg_sem_t* vg_sem;
1965 ensure_valgrind("sem_trywait");
1966 vg_sem = se_remap(sem);
1967 res = __pthread_mutex_lock(&vg_sem->se_mx);
1968 assert(res == 0);
1969 if (vg_sem->count > 0) {
1970 vg_sem->count--;
1971 ret = 0;
1972 } else {
1973 ret = -1;
1974 errno = EAGAIN;
1975 }
1976 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1977 assert(res == 0);
1978 return ret;
1979}
1980
1981
1982int sem_getvalue(sem_t* sem, int * sval)
1983{
1984 vg_sem_t* vg_sem;
1985 ensure_valgrind("sem_trywait");
1986 vg_sem = se_remap(sem);
1987 *sval = vg_sem->count;
1988 return 0;
1989}
1990
1991
1992int sem_destroy(sem_t * sem)
1993{
1994 kludged("sem_destroy");
1995 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
1996 return 0;
1997}
1998
1999
2000/* ---------------------------------------------------------------------
sewardja1ac5cb2002-05-27 13:00:05 +00002001 Hacky implementation of reader-writer locks.
2002 ------------------------------------------------------------------ */
2003
2004/*
2005Errata from 7th printing:
2006
2007 Page 259, rwlock.c, line 27, the two "!=" should be ">", for
2008 consistency with other similar tests. (The values should never be
2009 negative; this isn't a fix, but an improvement to clarity and
2010 consistency.)
2011
2012 [27] if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2013
2014 Page 259, rwlock.c, lines 39 and 40, in both lines, "==" should
2015 become "!=":
2016
2017 [39] return (status != 0 ? status
2018 [40] : (status1 != 0 ? status1 : status2));
2019*/
2020
2021/*
2022 * rwlock.h
2023 *
2024 * This header file describes the "reader/writer lock" synchronization
2025 * construct. The type rwlock_t describes the full state of the lock
2026 * including the POSIX 1003.1c synchronization objects necessary.
2027 *
2028 * A reader/writer lock allows a thread to lock shared data either for shared
2029 * read access or exclusive write access.
2030 *
2031 * The rwl_init() and rwl_destroy() functions, respectively, allow you to
2032 * initialize/create and destroy/free the reader/writer lock.
2033 */
2034
sewardja1ac5cb2002-05-27 13:00:05 +00002035/*
2036 * Structure describing a read-write lock.
2037 */
2038typedef struct {
2039 pthread_mutex_t mutex;
2040 pthread_cond_t read; /* wait for read */
2041 pthread_cond_t write; /* wait for write */
2042 int valid; /* set when valid */
2043 int r_active; /* readers active */
2044 int w_active; /* writer active */
2045 int r_wait; /* readers waiting */
2046 int w_wait; /* writers waiting */
2047 int pref_writer; /* != 0 --> prefer writer */
2048} vg_rwlock_t;
2049
2050#define VG_RWLOCK_VALID 0xfacade
2051
2052
2053/*
2054 * Support static initialization of barriers
2055 */
2056#define VG_RWL_INITIALIZER \
2057 {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \
2058 PTHREAD_COND_INITIALIZER, VG_RWLOCK_VALID, 0, 0, 0, 0, 1}
2059
2060
2061static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2062
2063static int rw_remap_used = 0;
2064static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2065static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2066
2067/* Take the address of a LinuxThreads rwlock_t and return the shadow
2068 address of our version. Further, if the LinuxThreads version
2069 appears to have been statically initialised, do the same to the one
2070 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2071 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2072 uninitialised and non-zero meaning initialised.
2073*/
2074static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2075{
2076 int res, i;
2077 vg_rwlock_t* vg_rwl;
2078 res = __pthread_mutex_lock(&rw_remap_mx);
2079 assert(res == 0);
2080
2081 for (i = 0; i < rw_remap_used; i++) {
2082 if (rw_remap_orig[i] == orig)
2083 break;
2084 }
2085 if (i == rw_remap_used) {
2086 if (rw_remap_used == VG_N_RWLOCKS) {
2087 res = pthread_mutex_unlock(&rw_remap_mx);
2088 assert(res == 0);
2089 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2090 }
2091 rw_remap_used++;
2092 rw_remap_orig[i] = orig;
2093 if (0) printf("allocated rwlock %d\n", i);
2094 }
2095 res = __pthread_mutex_unlock(&rw_remap_mx);
2096 assert(res == 0);
2097 vg_rwl = &rw_remap_new[i];
2098
2099 /* Mimic static initialisation of the original. */
2100 if (orig->__rw_readers == 0) {
2101 const vg_rwlock_t default_rwl = VG_RWL_INITIALIZER;
2102 orig->__rw_readers = 1;
2103 *vg_rwl = default_rwl;
2104 vg_rwl->pref_writer = 1;
2105 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
2106 vg_rwl->pref_writer = 0;
2107 }
2108
2109 return vg_rwl;
2110}
2111
2112
2113/*
2114 * rwlock.c
2115 *
2116 * This file implements the "read-write lock" synchronization
2117 * construct.
2118 *
2119 * A read-write lock allows a thread to lock shared data either
2120 * for shared read access or exclusive write access.
2121 *
2122 * The rwl_init() and rwl_destroy() functions, respectively,
2123 * allow you to initialize/create and destroy/free the
2124 * read-write lock.
2125 *
2126 * The rwl_readlock() function locks a read-write lock for
2127 * shared read access, and rwl_readunlock() releases the
2128 * lock. rwl_readtrylock() attempts to lock a read-write lock
2129 * for read access, and returns EBUSY instead of blocking.
2130 *
2131 * The rwl_writelock() function locks a read-write lock for
2132 * exclusive write access, and rwl_writeunlock() releases the
2133 * lock. rwl_writetrylock() attempts to lock a read-write lock
2134 * for write access, and returns EBUSY instead of blocking.
2135 */
2136
2137
2138/*
2139 * Initialize a read-write lock
2140 */
2141static int rwl_init ( vg_rwlock_t *rwl )
2142{
2143 int status;
2144
2145 rwl->r_active = 0;
2146 rwl->r_wait = rwl->w_wait = 0;
2147 rwl->w_active = 0;
2148 status = pthread_mutex_init (&rwl->mutex, NULL);
2149 if (status != 0)
2150 return status;
2151 status = pthread_cond_init (&rwl->read, NULL);
2152 if (status != 0) {
2153 /* if unable to create read CV, destroy mutex */
2154 pthread_mutex_destroy (&rwl->mutex);
2155 return status;
2156 }
2157 status = pthread_cond_init (&rwl->write, NULL);
2158 if (status != 0) {
2159 /* if unable to create write CV, destroy read CV and mutex */
2160 pthread_cond_destroy (&rwl->read);
2161 pthread_mutex_destroy (&rwl->mutex);
2162 return status;
2163 }
2164 rwl->valid = VG_RWLOCK_VALID;
2165 return 0;
2166}
2167
2168/*
2169 * Destroy a read-write lock
2170 */
2171static int rwl_destroy (vg_rwlock_t *rwl)
2172{
2173 int status, status1, status2;
2174
2175 if (rwl->valid != VG_RWLOCK_VALID)
2176 return EINVAL;
2177 status = pthread_mutex_lock (&rwl->mutex);
2178 if (status != 0)
2179 return status;
2180
2181 /*
2182 * Check whether any threads own the lock; report "BUSY" if
2183 * so.
2184 */
2185 if (rwl->r_active > 0 || rwl->w_active) {
2186 pthread_mutex_unlock (&rwl->mutex);
2187 return EBUSY;
2188 }
2189
2190 /*
2191 * Check whether any threads are known to be waiting; report
2192 * EBUSY if so.
2193 */
2194 if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2195 pthread_mutex_unlock (&rwl->mutex);
2196 return EBUSY;
2197 }
2198
2199 rwl->valid = 0;
2200 status = pthread_mutex_unlock (&rwl->mutex);
2201 if (status != 0)
2202 return status;
2203 status = pthread_mutex_destroy (&rwl->mutex);
2204 status1 = pthread_cond_destroy (&rwl->read);
2205 status2 = pthread_cond_destroy (&rwl->write);
2206 return (status != 0 ? status : (status1 != 0 ? status1 : status2));
2207}
2208
2209/*
2210 * Handle cleanup when the read lock condition variable
2211 * wait is cancelled.
2212 *
2213 * Simply record that the thread is no longer waiting,
2214 * and unlock the mutex.
2215 */
2216static void rwl_readcleanup (void *arg)
2217{
2218 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2219
2220 rwl->r_wait--;
2221 pthread_mutex_unlock (&rwl->mutex);
2222}
2223
2224/*
2225 * Lock a read-write lock for read access.
2226 */
2227static int rwl_readlock (vg_rwlock_t *rwl)
2228{
2229 int status;
2230
2231 if (rwl->valid != VG_RWLOCK_VALID)
2232 return EINVAL;
2233 status = pthread_mutex_lock (&rwl->mutex);
2234 if (status != 0)
2235 return status;
2236 if (rwl->w_active) {
2237 rwl->r_wait++;
2238 pthread_cleanup_push (rwl_readcleanup, (void*)rwl);
2239 while (rwl->w_active) {
2240 status = pthread_cond_wait (&rwl->read, &rwl->mutex);
2241 if (status != 0)
2242 break;
2243 }
2244 pthread_cleanup_pop (0);
2245 rwl->r_wait--;
2246 }
2247 if (status == 0)
2248 rwl->r_active++;
2249 pthread_mutex_unlock (&rwl->mutex);
2250 return status;
2251}
2252
2253/*
2254 * Attempt to lock a read-write lock for read access (don't
2255 * block if unavailable).
2256 */
2257static int rwl_readtrylock (vg_rwlock_t *rwl)
2258{
2259 int status, status2;
2260
2261 if (rwl->valid != VG_RWLOCK_VALID)
2262 return EINVAL;
2263 status = pthread_mutex_lock (&rwl->mutex);
2264 if (status != 0)
2265 return status;
2266 if (rwl->w_active)
2267 status = EBUSY;
2268 else
2269 rwl->r_active++;
2270 status2 = pthread_mutex_unlock (&rwl->mutex);
2271 return (status2 != 0 ? status2 : status);
2272}
2273
2274/*
2275 * Handle cleanup when the write lock condition variable
2276 * wait is cancelled.
2277 *
2278 * Simply record that the thread is no longer waiting,
2279 * and unlock the mutex.
2280 */
2281static void rwl_writecleanup (void *arg)
2282{
2283 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2284
2285 rwl->w_wait--;
2286 pthread_mutex_unlock (&rwl->mutex);
2287}
2288
2289/*
2290 * Lock a read-write lock for write access.
2291 */
2292static int rwl_writelock (vg_rwlock_t *rwl)
2293{
2294 int status;
2295
2296 if (rwl->valid != VG_RWLOCK_VALID)
2297 return EINVAL;
2298 status = pthread_mutex_lock (&rwl->mutex);
2299 if (status != 0)
2300 return status;
2301 if (rwl->w_active || rwl->r_active > 0) {
2302 rwl->w_wait++;
2303 pthread_cleanup_push (rwl_writecleanup, (void*)rwl);
2304 while (rwl->w_active || rwl->r_active > 0) {
2305 status = pthread_cond_wait (&rwl->write, &rwl->mutex);
2306 if (status != 0)
2307 break;
2308 }
2309 pthread_cleanup_pop (0);
2310 rwl->w_wait--;
2311 }
2312 if (status == 0)
2313 rwl->w_active = 1;
2314 pthread_mutex_unlock (&rwl->mutex);
2315 return status;
2316}
2317
2318/*
2319 * Attempt to lock a read-write lock for write access. Don't
2320 * block if unavailable.
2321 */
2322static int rwl_writetrylock (vg_rwlock_t *rwl)
2323{
2324 int status, status2;
2325
2326 if (rwl->valid != VG_RWLOCK_VALID)
2327 return EINVAL;
2328 status = pthread_mutex_lock (&rwl->mutex);
2329 if (status != 0)
2330 return status;
2331 if (rwl->w_active || rwl->r_active > 0)
2332 status = EBUSY;
2333 else
2334 rwl->w_active = 1;
2335 status2 = pthread_mutex_unlock (&rwl->mutex);
2336 return (status != 0 ? status : status2);
2337}
2338
2339/*
2340 * Unlock a read-write lock, using the r_active and w_active fields to
2341 * decide whether we're in a read or write lock.
2342 */
2343static int rwl_unlock (vg_rwlock_t *rwl)
2344{
2345 int status, status2;
2346
2347 if (rwl->valid != VG_RWLOCK_VALID)
2348 return EINVAL;
2349 status = pthread_mutex_lock (&rwl->mutex);
2350 if (status != 0)
2351 return status;
2352
2353 if (rwl->r_active > 0) {
2354
2355 /* READ case */
2356 assert(!rwl->w_active);
2357 rwl->r_active--;
2358 if (rwl->r_active == 0 && rwl->w_wait > 0)
2359 status = pthread_cond_signal (&rwl->write);
2360 /* END READ case */
2361
2362 } else {
2363
2364 /* WRITE case */
2365 assert(rwl->w_active);
2366 assert(rwl->r_active == 0);
2367 rwl->w_active = 0;
2368
2369 if (rwl->pref_writer) {
2370 /* Do writer-preference wakeups. */
2371 if (rwl->w_wait > 0) {
2372 status = pthread_cond_signal (&rwl->write);
2373 if (status != 0) {
2374 pthread_mutex_unlock (&rwl->mutex);
2375 return status;
2376 }
2377 } else if (rwl->r_wait > 0) {
2378 status = pthread_cond_broadcast (&rwl->read);
2379 if (status != 0) {
2380 pthread_mutex_unlock (&rwl->mutex);
2381 return status;
2382 }
2383 }
2384 } else {
2385 /* Do reader-preference wakeups. */
2386 if (rwl->r_wait > 0) {
2387 status = pthread_cond_broadcast (&rwl->read);
2388 if (status != 0) {
2389 pthread_mutex_unlock (&rwl->mutex);
2390 return status;
2391 }
2392 } else if (rwl->w_wait > 0) {
2393 status = pthread_cond_signal (&rwl->write);
2394 if (status != 0) {
2395 pthread_mutex_unlock (&rwl->mutex);
2396 return status;
2397 }
2398 }
2399 }
2400 /* END WRITE case */
2401
2402 }
2403
2404 status2 = pthread_mutex_unlock (&rwl->mutex);
2405 return (status2 == 0 ? status : status2);
2406}
2407
2408/* -------------------------------- */
2409
2410int pthread_rwlock_init ( pthread_rwlock_t* orig,
2411 const pthread_rwlockattr_t* attr )
2412{
2413 int res;
2414 vg_rwlock_t* rwl;
2415 if (0) printf ("pthread_rwlock_init\n");
2416 /* Force the remapper to initialise the shadow. */
2417 orig->__rw_readers = 0;
2418 /* Install the lock preference; the remapper needs to know it. */
2419 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2420 if (attr)
2421 orig->__rw_kind = attr->__lockkind;
2422 rwl = rw_remap ( orig );
2423 res = rwl_init ( rwl );
2424 return res;
2425}
2426
2427int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2428{
2429 int res;
2430 vg_rwlock_t* rwl;
2431 if (0) printf ("pthread_rwlock_destroy\n");
2432 rwl = rw_remap ( orig );
2433 res = rwl_destroy ( rwl );
2434 return res;
2435}
2436
2437int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2438{
2439 int res;
2440 vg_rwlock_t* rwl;
2441 if (0) printf ("pthread_rwlock_rdlock\n");
2442 rwl = rw_remap ( orig );
2443 res = rwl_readlock ( rwl );
2444 return res;
2445}
2446
2447int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2448{
2449 int res;
2450 vg_rwlock_t* rwl;
2451 if (0) printf ("pthread_rwlock_tryrdlock\n");
2452 rwl = rw_remap ( orig );
2453 res = rwl_readtrylock ( rwl );
2454 return res;
2455}
2456
2457int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2458{
2459 int res;
2460 vg_rwlock_t* rwl;
2461 if (0) printf ("pthread_rwlock_wrlock\n");
2462 rwl = rw_remap ( orig );
2463 res = rwl_writelock ( rwl );
2464 return res;
2465}
2466
2467int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2468{
2469 int res;
2470 vg_rwlock_t* rwl;
2471 if (0) printf ("pthread_rwlock_trywrlock\n");
2472 rwl = rw_remap ( orig );
2473 res = rwl_writetrylock ( rwl );
2474 return res;
2475}
2476
2477int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2478{
2479 int res;
2480 vg_rwlock_t* rwl;
2481 if (0) printf ("pthread_rwlock_unlock\n");
2482 rwl = rw_remap ( orig );
2483 res = rwl_unlock ( rwl );
2484 return res;
2485}
2486
2487
2488/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002489 B'stard.
2490 ------------------------------------------------------------------ */
2491
2492# define strong_alias(name, aliasname) \
2493 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2494
sewardj5905fae2002-04-26 13:25:00 +00002495# define weak_alias(name, aliasname) \
2496 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002497
sewardj5905fae2002-04-26 13:25:00 +00002498strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2499strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2500strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2501strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2502 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2503strong_alias(__pthread_mutex_init, pthread_mutex_init)
2504strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2505strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2506strong_alias(__pthread_once, pthread_once)
2507strong_alias(__pthread_atfork, pthread_atfork)
2508strong_alias(__pthread_key_create, pthread_key_create)
2509strong_alias(__pthread_getspecific, pthread_getspecific)
2510strong_alias(__pthread_setspecific, pthread_setspecific)
2511
sewardjd529a442002-05-04 19:49:21 +00002512#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002513strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002514#endif
2515
sewardj5905fae2002-04-26 13:25:00 +00002516strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002517strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002518strong_alias(lseek, __lseek)
2519strong_alias(open, __open)
2520strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002521strong_alias(read, __read)
2522strong_alias(wait, __wait)
2523strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002524strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002525strong_alias(send, __send)
2526
sewardj726c4122002-05-16 23:39:10 +00002527weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002528weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002529weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002530
sewardj5905fae2002-04-26 13:25:00 +00002531
sewardj3b13f0e2002-04-25 20:17:29 +00002532
2533/*--------------------------------------------------*/
2534
sewardj5905fae2002-04-26 13:25:00 +00002535weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002536weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002537weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002538
sewardja1ac5cb2002-05-27 13:00:05 +00002539weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2540weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2541weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2542weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2543
sewardj060b04f2002-04-26 21:01:13 +00002544
sewardj3b13f0e2002-04-25 20:17:29 +00002545/* I've no idea what these are, but they get called quite a lot.
2546 Anybody know? */
2547
2548#undef _IO_flockfile
2549void _IO_flockfile ( _IO_FILE * file )
2550{
sewardj853f55d2002-04-26 00:27:53 +00002551 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002552}
sewardj5905fae2002-04-26 13:25:00 +00002553weak_alias(_IO_flockfile, flockfile);
2554
sewardj3b13f0e2002-04-25 20:17:29 +00002555
2556#undef _IO_funlockfile
2557void _IO_funlockfile ( _IO_FILE * file )
2558{
sewardj853f55d2002-04-26 00:27:53 +00002559 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002560}
sewardj5905fae2002-04-26 13:25:00 +00002561weak_alias(_IO_funlockfile, funlockfile);
2562
sewardj3b13f0e2002-04-25 20:17:29 +00002563
sewardjd4f2c712002-04-30 10:20:10 +00002564/* This doesn't seem to be needed to simulate libpthread.so's external
2565 interface, but many people complain about its absence. */
2566
2567strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2568weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002569
2570
2571/*--------------------------------------------------------------------*/
2572/*--- end vg_libpthread.c ---*/
2573/*--------------------------------------------------------------------*/