blob: 7fba3b0f80efa256279d0e6b3a83722c525d929b [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{
sewardj8ad94e12002-05-29 00:10:20 +0000282 int detached, res;
283 CleanupEntry cu;
sewardj20917d82002-05-28 01:36:45 +0000284 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000285 while (1) {
286 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
287 VG_USERREQ__CLEANUP_POP,
288 &cu, 0, 0, 0);
289 if (res == -1) break; /* stack empty */
290 assert(res == 0);
291 if (0) printf("running exit cleanup handler");
292 cu.fn ( cu.arg );
293 }
294
sewardj20917d82002-05-28 01:36:45 +0000295 /* Run this thread's key finalizers. */
296
297 /* Decide on my final disposition. */
298 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
299 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000300 2 /* get */, pthread_self(), 0, 0);
sewardj20917d82002-05-28 01:36:45 +0000301 assert(detached == 0 || detached == 1);
302
303 if (detached) {
304 /* Detached; I just quit right now. */
305 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
306 VG_USERREQ__QUIT, 0, 0, 0, 0);
307 } else {
308 /* Not detached; so I wait for a joiner. */
309 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
310 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
311 }
312 /* NOTREACHED */
313 barf("thread_exit_wrapper: still alive?!");
314}
315
316
317/* This function is a wrapper function for running a thread. It runs
318 the root function specified in pthread_create, and then, should the
319 root function return a value, it arranges to run the thread's
320 cleanup handlers and exit correctly. */
321
322/* Struct used to convey info from pthread_create to
323 thread_wrapper. */
324typedef
325 struct {
326 pthread_attr_t* attr;
327 void* (*root_fn) ( void* );
328 void* arg;
329 }
330 NewThreadInfo;
331
332
333/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
334 not return. Note that this runs in the new thread, not the
335 parent. */
336static
337__attribute__((noreturn))
338void thread_wrapper ( NewThreadInfo* info )
339{
340 int res;
341 pthread_attr_t* attr;
342 void* (*root_fn) ( void* );
343 void* arg;
344 void* ret_val;
345
346 attr = info->attr;
347 root_fn = info->root_fn;
348 arg = info->arg;
349
sewardj20917d82002-05-28 01:36:45 +0000350 /* Free up the arg block that pthread_create malloced. */
351 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
352 VG_USERREQ__FREE, info, 0, 0, 0);
353 assert(res == 0);
354
sewardj7989d0c2002-05-28 11:00:01 +0000355 /* Minimally observe the attributes supplied. */
356 if (attr) {
357 assert(attr->__detachstate == PTHREAD_CREATE_DETACHED
358 || attr->__detachstate == PTHREAD_CREATE_JOINABLE);
359 if (attr->__detachstate == PTHREAD_CREATE_DETACHED)
360 pthread_detach(pthread_self());
361 }
362
sewardj20917d82002-05-28 01:36:45 +0000363 /* The root function might not return. But if it does we simply
364 move along to thread_exit_wrapper. All other ways out for the
365 thread (cancellation, or calling pthread_exit) lead there
366 too. */
367 ret_val = root_fn(arg);
368 thread_exit_wrapper(ret_val);
369 /* NOTREACHED */
370}
371
372
sewardjf8f819e2002-04-17 23:21:37 +0000373/* ---------------------------------------------------
374 THREADs
375 ------------------------------------------------ */
376
sewardjff42d1d2002-05-22 13:17:31 +0000377__attribute__((weak))
378int pthread_yield ( void )
379{
380 int res;
381 ensure_valgrind("pthread_yield");
382 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
383 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
384 return 0;
385}
386
387
sewardj6072c362002-04-19 14:40:57 +0000388int pthread_equal(pthread_t thread1, pthread_t thread2)
389{
390 return thread1 == thread2 ? 1 : 0;
391}
392
393
sewardj20917d82002-05-28 01:36:45 +0000394/* Bundle up the args into a malloc'd block and create a new thread
395 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000396int
397pthread_create (pthread_t *__restrict __thread,
398 __const pthread_attr_t *__restrict __attr,
399 void *(*__start_routine) (void *),
400 void *__restrict __arg)
401{
sewardj20917d82002-05-28 01:36:45 +0000402 int tid_child;
403 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000404
sewardj20917d82002-05-28 01:36:45 +0000405 ensure_valgrind("pthread_create");
406
407 /* Allocate space for the arg block. thread_wrapper will free
408 it. */
409 VALGRIND_MAGIC_SEQUENCE(info, NULL /* default */,
410 VG_USERREQ__MALLOC,
411 sizeof(NewThreadInfo), 0, 0, 0);
412 assert(info != NULL);
413
414 info->attr = (pthread_attr_t*)__attr;
415 info->root_fn = __start_routine;
416 info->arg = __arg;
417 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
418 VG_USERREQ__APPLY_IN_NEW_THREAD,
419 &thread_wrapper, info, 0, 0);
420 assert(tid_child != VG_INVALID_THREADID);
421
422 if (__thread)
423 *__thread = tid_child;
424 return 0; /* success */
425}
sewardje663cb92002-04-12 10:26:32 +0000426
427
428int
429pthread_join (pthread_t __th, void **__thread_return)
430{
431 int res;
432 ensure_valgrind("pthread_join");
433 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
434 VG_USERREQ__PTHREAD_JOIN,
435 __th, __thread_return, 0, 0);
436 return res;
437}
438
439
sewardj3b5d8862002-04-20 13:53:23 +0000440void pthread_exit(void *retval)
441{
sewardj3b5d8862002-04-20 13:53:23 +0000442 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000443 /* Simple! */
444 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000445}
446
sewardje663cb92002-04-12 10:26:32 +0000447
sewardj3b13f0e2002-04-25 20:17:29 +0000448pthread_t pthread_self(void)
sewardje663cb92002-04-12 10:26:32 +0000449{
450 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000451 ensure_valgrind("pthread_self");
sewardj439d45e2002-05-03 20:43:10 +0000452 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardje663cb92002-04-12 10:26:32 +0000453 VG_USERREQ__PTHREAD_GET_THREADID,
454 0, 0, 0, 0);
sewardj439d45e2002-05-03 20:43:10 +0000455 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000456 barf("pthread_self: invalid ThreadId");
457 return tid;
sewardje663cb92002-04-12 10:26:32 +0000458}
459
460
sewardj853f55d2002-04-26 00:27:53 +0000461int pthread_detach(pthread_t th)
462{
sewardj20917d82002-05-28 01:36:45 +0000463 int res;
464 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000465 /* First we enquire as to the current detach state. */
466 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000467 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000468 2 /* get */, th, 0, 0);
469 if (res == -1) /* not found */
470 return ESRCH;
471 if (res == 1) /* already detached */
472 return EINVAL;
473 if (res == 0) {
474 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
475 VG_USERREQ__SET_OR_GET_DETACH,
476 1 /* set */, th, 0, 0);
477 assert(res == 0);
478 return 0;
479 }
480 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000481}
482
483
sewardjf8f819e2002-04-17 23:21:37 +0000484/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000485 CLEANUP STACKS
486 ------------------------------------------------ */
487
488void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
489 void (*__routine) (void *),
490 void *__arg)
491{
492 int res;
493 CleanupEntry cu;
494 ensure_valgrind("_pthread_cleanup_push");
495 cu.fn = __routine;
496 cu.arg = __arg;
497 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
498 VG_USERREQ__CLEANUP_PUSH,
499 &cu, 0, 0, 0);
500 assert(res == 0);
501}
502
503
504void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
505 void (*__routine) (void *),
506 void *__arg)
507{
508 /* As _pthread_cleanup_push, but first save the thread's original
509 cancellation type in __buffer and set it to Deferred. */
510 int orig_ctype;
511 ensure_valgrind("_pthread_cleanup_push_defer");
512 /* Set to Deferred, and put the old cancellation type in res. */
513 assert(-1 != PTHREAD_CANCEL_DEFERRED);
514 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
515 assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
516 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
517 VG_USERREQ__SET_CANCELTYPE,
518 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
519 assert(orig_ctype != -1);
520 *((int*)(__buffer)) = orig_ctype;
521 /* Now push the cleanup. */
522 _pthread_cleanup_push(NULL, __routine, __arg);
523}
524
525
526void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
527 int __execute)
528{
529 int res;
530 CleanupEntry cu;
531 ensure_valgrind("_pthread_cleanup_push");
532 cu.fn = cu.arg = NULL; /* paranoia */
533 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
534 VG_USERREQ__CLEANUP_POP,
535 &cu, 0, 0, 0);
536 if (res == 0) {
537 /* pop succeeded */
538 if (__execute) {
539 cu.fn ( cu.arg );
540 }
541 return;
542 }
543 if (res == -1) {
544 /* stack underflow */
545 return;
546 }
547 barf("_pthread_cleanup_pop");
548}
549
550
551void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
552 int __execute)
553{
554 int orig_ctype, fake_ctype;
555 /* As _pthread_cleanup_pop, but after popping/running the handler,
556 restore the thread's original cancellation type from the first
557 word of __buffer. */
558 _pthread_cleanup_pop(NULL, __execute);
559 orig_ctype = *((int*)(__buffer));
560 assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
561 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
562 assert(-1 != PTHREAD_CANCEL_DEFERRED);
563 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
564 assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
565 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
566 VG_USERREQ__SET_CANCELTYPE,
567 orig_ctype, 0, 0, 0);
568 assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
569}
570
571
572/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000573 MUTEX ATTRIBUTES
574 ------------------------------------------------ */
575
sewardj5905fae2002-04-26 13:25:00 +0000576int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000577{
sewardjf8f819e2002-04-17 23:21:37 +0000578 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000579 return 0;
sewardje663cb92002-04-12 10:26:32 +0000580}
581
sewardj5905fae2002-04-26 13:25:00 +0000582int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000583{
584 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000585# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000586 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000587 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000588# endif
sewardja1679dd2002-05-10 22:31:40 +0000589# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000590 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000591# endif
sewardjf8f819e2002-04-17 23:21:37 +0000592 case PTHREAD_MUTEX_RECURSIVE_NP:
593 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000594 attr->__mutexkind = type;
595 return 0;
596 default:
597 return EINVAL;
598 }
599}
600
sewardj5905fae2002-04-26 13:25:00 +0000601int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000602{
603 return 0;
604}
605
606
607/* ---------------------------------------------------
608 MUTEXes
609 ------------------------------------------------ */
610
sewardj5905fae2002-04-26 13:25:00 +0000611int __pthread_mutex_init(pthread_mutex_t *mutex,
612 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000613{
sewardj604ec3c2002-04-18 22:38:41 +0000614 mutex->__m_count = 0;
615 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
616 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
617 if (mutexattr)
618 mutex->__m_kind = mutexattr->__mutexkind;
619 return 0;
sewardje663cb92002-04-12 10:26:32 +0000620}
621
sewardj439d45e2002-05-03 20:43:10 +0000622
sewardj5905fae2002-04-26 13:25:00 +0000623int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000624{
625 int res;
sewardj436e0582002-04-26 14:31:40 +0000626 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000627 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000628 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
629 VG_USERREQ__PTHREAD_MUTEX_LOCK,
630 mutex, 0, 0, 0);
631 return res;
sewardj439d45e2002-05-03 20:43:10 +0000632 } else {
633 if (moans-- > 0)
634 not_inside("pthread_mutex_lock");
635 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000636 }
637}
638
sewardj439d45e2002-05-03 20:43:10 +0000639
sewardj5905fae2002-04-26 13:25:00 +0000640int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000641{
642 int res;
sewardj436e0582002-04-26 14:31:40 +0000643 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000644 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000645 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
646 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
647 mutex, 0, 0, 0);
648 return res;
sewardj439d45e2002-05-03 20:43:10 +0000649 } else {
650 if (moans-- > 0)
651 not_inside("pthread_mutex_trylock");
652 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000653 }
654}
655
sewardj439d45e2002-05-03 20:43:10 +0000656
sewardj5905fae2002-04-26 13:25:00 +0000657int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000658{
659 int res;
sewardj436e0582002-04-26 14:31:40 +0000660 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000661 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000662 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
663 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
664 mutex, 0, 0, 0);
665 return res;
sewardj439d45e2002-05-03 20:43:10 +0000666 } else {
667 if (moans-- > 0)
668 not_inside("pthread_mutex_unlock");
669 return 0;
sewardje663cb92002-04-12 10:26:32 +0000670 }
671}
672
sewardj439d45e2002-05-03 20:43:10 +0000673
sewardj5905fae2002-04-26 13:25:00 +0000674int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000675{
sewardj604ec3c2002-04-18 22:38:41 +0000676 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
677 need to involve it. */
678 if (mutex->__m_count > 0)
679 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000680 mutex->__m_count = 0;
681 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
682 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000683 return 0;
sewardje663cb92002-04-12 10:26:32 +0000684}
685
686
sewardjf8f819e2002-04-17 23:21:37 +0000687/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000688 CONDITION VARIABLES
689 ------------------------------------------------ */
690
691/* LinuxThreads supports no attributes for conditions. Hence ... */
692
693int pthread_condattr_init(pthread_condattr_t *attr)
694{
695 return 0;
696}
697
sewardj0738a592002-04-20 13:59:33 +0000698int pthread_condattr_destroy(pthread_condattr_t *attr)
699{
700 return 0;
701}
sewardj6072c362002-04-19 14:40:57 +0000702
703int pthread_cond_init( pthread_cond_t *cond,
704 const pthread_condattr_t *cond_attr)
705{
706 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
707 return 0;
708}
709
sewardjf854f472002-04-21 12:19:41 +0000710int pthread_cond_destroy(pthread_cond_t *cond)
711{
712 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000713 static int moans = N_MOANS;
714 if (moans-- > 0)
715 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000716 return 0;
717}
sewardj6072c362002-04-19 14:40:57 +0000718
719/* ---------------------------------------------------
720 SCHEDULING
721 ------------------------------------------------ */
722
723/* This is completely bogus. */
724int pthread_getschedparam(pthread_t target_thread,
725 int *policy,
726 struct sched_param *param)
727{
sewardj436e0582002-04-26 14:31:40 +0000728 static int moans = N_MOANS;
729 if (moans-- > 0)
730 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000731 if (policy) *policy = SCHED_OTHER;
sewardj2a1dcce2002-04-22 12:45:25 +0000732# ifdef GLIBC_2_1
733 if (param) param->sched_priority = 0; /* who knows */
734# else
sewardj6072c362002-04-19 14:40:57 +0000735 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000736# endif
sewardj6072c362002-04-19 14:40:57 +0000737 return 0;
738}
739
740int pthread_setschedparam(pthread_t target_thread,
741 int policy,
742 const struct sched_param *param)
743{
sewardj436e0582002-04-26 14:31:40 +0000744 static int moans = N_MOANS;
745 if (moans-- > 0)
746 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000747 return 0;
748}
749
sewardj3b5d8862002-04-20 13:53:23 +0000750int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
751{
752 int res;
753 ensure_valgrind("pthread_cond_wait");
754 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
755 VG_USERREQ__PTHREAD_COND_WAIT,
756 cond, mutex, 0, 0);
757 return res;
758}
759
sewardj5f07b662002-04-23 16:52:51 +0000760int pthread_cond_timedwait ( pthread_cond_t *cond,
761 pthread_mutex_t *mutex,
762 const struct timespec *abstime )
763{
764 int res;
765 unsigned int ms_now, ms_end;
766 struct timeval timeval_now;
767 unsigned long long int ull_ms_now_after_1970;
768 unsigned long long int ull_ms_end_after_1970;
769
770 ensure_valgrind("pthread_cond_timedwait");
771 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
772 VG_USERREQ__READ_MILLISECOND_TIMER,
773 0, 0, 0, 0);
774 assert(ms_now != 0xFFFFFFFF);
775 res = gettimeofday(&timeval_now, NULL);
776 assert(res == 0);
777
778 ull_ms_now_after_1970
779 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
780 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
781 ull_ms_end_after_1970
782 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
783 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
784 assert(ull_ms_end_after_1970 >= ull_ms_now_after_1970);
785 ms_end
786 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
787 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
788 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
789 cond, mutex, ms_end, 0);
790 return res;
791}
792
793
sewardj3b5d8862002-04-20 13:53:23 +0000794int pthread_cond_signal(pthread_cond_t *cond)
795{
796 int res;
797 ensure_valgrind("pthread_cond_signal");
798 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
799 VG_USERREQ__PTHREAD_COND_SIGNAL,
800 cond, 0, 0, 0);
801 return res;
802}
803
804int pthread_cond_broadcast(pthread_cond_t *cond)
805{
806 int res;
807 ensure_valgrind("pthread_cond_broadcast");
808 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
809 VG_USERREQ__PTHREAD_COND_BROADCAST,
810 cond, 0, 0, 0);
811 return res;
812}
813
sewardj6072c362002-04-19 14:40:57 +0000814
815/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000816 CANCELLATION
817 ------------------------------------------------ */
818
sewardj853f55d2002-04-26 00:27:53 +0000819int pthread_setcancelstate(int state, int *oldstate)
820{
sewardj20917d82002-05-28 01:36:45 +0000821 int res;
822 ensure_valgrind("pthread_setcancelstate");
823 if (state != PTHREAD_CANCEL_ENABLE
824 && state != PTHREAD_CANCEL_DISABLE)
825 return EINVAL;
826 assert(-1 != PTHREAD_CANCEL_ENABLE);
827 assert(-1 != PTHREAD_CANCEL_DISABLE);
828 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
829 VG_USERREQ__SET_CANCELSTATE,
830 state, 0, 0, 0);
831 assert(res != -1);
832 if (oldstate)
833 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +0000834 return 0;
835}
836
sewardje663cb92002-04-12 10:26:32 +0000837int pthread_setcanceltype(int type, int *oldtype)
838{
sewardj20917d82002-05-28 01:36:45 +0000839 int res;
840 ensure_valgrind("pthread_setcanceltype");
841 if (type != PTHREAD_CANCEL_DEFERRED
842 && type != PTHREAD_CANCEL_ASYNCHRONOUS)
843 return EINVAL;
844 assert(-1 != PTHREAD_CANCEL_DEFERRED);
845 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
846 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
847 VG_USERREQ__SET_CANCELTYPE,
848 type, 0, 0, 0);
849 assert(res != -1);
850 if (oldtype)
851 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +0000852 return 0;
853}
854
sewardje663cb92002-04-12 10:26:32 +0000855int pthread_cancel(pthread_t thread)
856{
857 int res;
858 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +0000859 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
860 VG_USERREQ__SET_CANCELPEND,
861 thread, &thread_exit_wrapper, 0, 0);
862 assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +0000863 return res;
864}
865
sewardj20917d82002-05-28 01:36:45 +0000866__inline__
sewardj853f55d2002-04-26 00:27:53 +0000867void pthread_testcancel(void)
868{
sewardj20917d82002-05-28 01:36:45 +0000869 int res;
870 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
871 VG_USERREQ__TESTCANCEL,
872 0, 0, 0, 0);
873 assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +0000874}
875
sewardj20917d82002-05-28 01:36:45 +0000876
sewardj853f55d2002-04-26 00:27:53 +0000877/*-------------------*/
878static pthread_mutex_t massacre_mx = PTHREAD_MUTEX_INITIALIZER;
879
880void __pthread_kill_other_threads_np ( void )
881{
882 int i, res, me;
sewardj68b2dd92002-05-10 21:03:56 +0000883 __pthread_mutex_lock(&massacre_mx);
sewardj853f55d2002-04-26 00:27:53 +0000884 me = pthread_self();
885 for (i = 1; i < VG_N_THREADS; i++) {
886 if (i == me) continue;
887 res = pthread_cancel(i);
sewardj436e0582002-04-26 14:31:40 +0000888 if (0 && res == 0)
sewardj853f55d2002-04-26 00:27:53 +0000889 printf("----------- NUKED %d\n", i);
890 }
sewardj68b2dd92002-05-10 21:03:56 +0000891 __pthread_mutex_unlock(&massacre_mx);
sewardj853f55d2002-04-26 00:27:53 +0000892}
893
sewardje663cb92002-04-12 10:26:32 +0000894
sewardjf8f819e2002-04-17 23:21:37 +0000895/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +0000896 SIGNALS
897 ------------------------------------------------ */
898
899#include <signal.h>
900
901int pthread_sigmask(int how, const sigset_t *newmask,
902 sigset_t *oldmask)
903{
904 int res;
905
906 /* A bit subtle, because the scheduler expects newmask and oldmask
907 to be vki_sigset_t* rather than sigset_t*, and the two are
908 different. Fortunately the first 64 bits of a sigset_t are
909 exactly a vki_sigset_t, so we just pass the pointers through
910 unmodified. Haaaack!
911
912 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +0000913 constants to VKI_ constants, so that the former do not have to
914 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +0000915
916 ensure_valgrind("pthread_sigmask");
917
918 switch (how) {
sewardj018f7622002-05-15 21:13:39 +0000919 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
920 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
921 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardjb48e5002002-05-13 00:16:03 +0000922 default: return EINVAL;
923 }
924
925 /* Crude check */
926 if (newmask == NULL)
927 return EFAULT;
928
929 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
930 VG_USERREQ__PTHREAD_SIGMASK,
931 how, newmask, oldmask, 0);
932
933 /* The scheduler tells us of any memory violations. */
934 return res == 0 ? 0 : EFAULT;
935}
936
937
938int sigwait ( const sigset_t* set, int* sig )
939{
940 int res;
941 ensure_valgrind("sigwait");
942 /* As with pthread_sigmask we deliberately confuse sigset_t with
943 vki_ksigset_t. */
944 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
945 VG_USERREQ__SIGWAIT,
946 set, sig, 0, 0);
947 return res;
948}
949
950
sewardj018f7622002-05-15 21:13:39 +0000951int pthread_kill(pthread_t thread, int signo)
952{
953 int res;
954 ensure_valgrind("pthread_kill");
955 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
956 VG_USERREQ__PTHREAD_KILL,
957 thread, signo, 0, 0);
958 return res;
959}
960
961
sewardj3665ded2002-05-16 16:57:25 +0000962/* Copied verbatim from Linuxthreads */
963/* Redefine raise() to send signal to calling thread only,
964 as per POSIX 1003.1c */
965int raise (int sig)
966{
967 int retcode = pthread_kill(pthread_self(), sig);
968 if (retcode == 0)
969 return 0;
970 else {
971 errno = retcode;
972 return -1;
973 }
974}
975
976
sewardjb48e5002002-05-13 00:16:03 +0000977/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000978 THREAD-SPECIFICs
979 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000980
sewardj5905fae2002-04-26 13:25:00 +0000981int __pthread_key_create(pthread_key_t *key,
982 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +0000983{
sewardj5f07b662002-04-23 16:52:51 +0000984 int res;
985 ensure_valgrind("pthread_key_create");
986 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
987 VG_USERREQ__PTHREAD_KEY_CREATE,
988 key, destr_function, 0, 0);
989 return res;
sewardj5e5fa512002-04-14 13:13:05 +0000990}
991
992int pthread_key_delete(pthread_key_t key)
993{
sewardj436e0582002-04-26 14:31:40 +0000994 static int moans = N_MOANS;
995 if (moans-- > 0)
996 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000997 return 0;
998}
999
sewardj5905fae2002-04-26 13:25:00 +00001000int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001001{
sewardj5f07b662002-04-23 16:52:51 +00001002 int res;
1003 ensure_valgrind("pthread_setspecific");
1004 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1005 VG_USERREQ__PTHREAD_SETSPECIFIC,
1006 key, pointer, 0, 0);
1007 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001008}
1009
sewardj5905fae2002-04-26 13:25:00 +00001010void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001011{
sewardj5f07b662002-04-23 16:52:51 +00001012 int res;
1013 ensure_valgrind("pthread_getspecific");
1014 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1015 VG_USERREQ__PTHREAD_GETSPECIFIC,
1016 key, 0 , 0, 0);
1017 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001018}
1019
sewardjf8f819e2002-04-17 23:21:37 +00001020
1021/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001022 ONCEry
1023 ------------------------------------------------ */
1024
1025static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1026
1027
sewardj5905fae2002-04-26 13:25:00 +00001028int __pthread_once ( pthread_once_t *once_control,
1029 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001030{
1031 int res;
1032 ensure_valgrind("pthread_once");
1033
sewardj68b2dd92002-05-10 21:03:56 +00001034 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001035
sewardj68b2dd92002-05-10 21:03:56 +00001036 if (res != 0) {
1037 printf("res = %d\n",res);
sewardj89d3d852002-04-24 19:21:39 +00001038 barf("pthread_once: Looks like your program's "
1039 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001040 }
sewardj89d3d852002-04-24 19:21:39 +00001041
1042 if (*once_control == 0) {
1043 *once_control = 1;
1044 init_routine();
1045 }
1046
sewardj68b2dd92002-05-10 21:03:56 +00001047 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001048
1049 return 0;
1050}
1051
1052
1053/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001054 MISC
1055 ------------------------------------------------ */
1056
sewardj5905fae2002-04-26 13:25:00 +00001057int __pthread_atfork ( void (*prepare)(void),
1058 void (*parent)(void),
1059 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001060{
sewardj436e0582002-04-26 14:31:40 +00001061 static int moans = N_MOANS;
1062 if (moans-- > 0)
1063 ignored("pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +00001064 return 0;
1065}
1066
1067
sewardjbb990782002-05-08 02:01:14 +00001068__attribute__((weak))
1069void __pthread_initialize ( void )
1070{
sewardjbea1caa2002-05-10 23:20:58 +00001071 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001072}
1073
1074
sewardj853f55d2002-04-26 00:27:53 +00001075/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001076 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001077 ------------------------------------------------ */
1078
sewardj3b13f0e2002-04-25 20:17:29 +00001079#include <resolv.h>
1080static int thread_specific_errno[VG_N_THREADS];
1081static int thread_specific_h_errno[VG_N_THREADS];
1082static struct __res_state
1083 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001084
sewardj3b13f0e2002-04-25 20:17:29 +00001085int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001086{
1087 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001088 /* ensure_valgrind("__errno_location"); */
1089 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001090 VG_USERREQ__PTHREAD_GET_THREADID,
1091 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001092 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001093 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001094 barf("__errno_location: invalid ThreadId");
1095 return & thread_specific_errno[tid];
1096}
1097
1098int* __h_errno_location ( void )
1099{
1100 int tid;
1101 /* ensure_valgrind("__h_errno_location"); */
1102 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1103 VG_USERREQ__PTHREAD_GET_THREADID,
1104 0, 0, 0, 0);
1105 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001106 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001107 barf("__h_errno_location: invalid ThreadId");
1108 return & thread_specific_h_errno[tid];
1109}
1110
1111struct __res_state* __res_state ( void )
1112{
1113 int tid;
1114 /* ensure_valgrind("__res_state"); */
1115 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1116 VG_USERREQ__PTHREAD_GET_THREADID,
1117 0, 0, 0, 0);
1118 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001119 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001120 barf("__res_state: invalid ThreadId");
1121 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001122}
1123
1124
sewardj5716dbb2002-04-26 03:28:18 +00001125/* ---------------------------------------------------
1126 LIBC-PRIVATE SPECIFIC DATA
1127 ------------------------------------------------ */
1128
1129/* Relies on assumption that initial private data is NULL. This
1130 should be fixed somehow. */
1131
1132/* The allowable keys (indices) (all 2 of them).
1133 From sysdeps/pthread/bits/libc-tsd.h
1134*/
sewardj70adeb22002-04-27 01:35:38 +00001135#define N_LIBC_TSD_EXTRA_KEYS 1
1136
sewardj5716dbb2002-04-26 03:28:18 +00001137enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1138 _LIBC_TSD_KEY_DL_ERROR,
1139 _LIBC_TSD_KEY_N };
1140
1141/* Auto-initialising subsystem. libc_specifics_inited is set
1142 after initialisation. libc_specifics_inited_mx guards it. */
1143static int libc_specifics_inited = 0;
1144static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1145
1146/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001147static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1148 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001149
1150/* Initialise the keys, if they are not already initialise. */
1151static
1152void init_libc_tsd_keys ( void )
1153{
1154 int res, i;
1155 pthread_key_t k;
1156
1157 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1158 if (res != 0) barf("init_libc_tsd_keys: lock");
1159
1160 if (libc_specifics_inited == 0) {
1161 /* printf("INIT libc specifics\n"); */
1162 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001163 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001164 res = pthread_key_create(&k, NULL);
1165 if (res != 0) barf("init_libc_tsd_keys: create");
1166 libc_specifics_keys[i] = k;
1167 }
1168 }
1169
1170 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1171 if (res != 0) barf("init_libc_tsd_keys: unlock");
1172}
1173
1174
1175static int
1176libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1177 const void * pointer )
1178{
sewardj70adeb22002-04-27 01:35:38 +00001179 int res;
1180 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001181 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001182 if (key < _LIBC_TSD_KEY_MALLOC
1183 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001184 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001185 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1186 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001187 "valgrind's libpthread.so: libc_internal_tsd_set: "
1188 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001189 init_libc_tsd_keys();
1190 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1191 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1192 return 0;
1193}
1194
1195static void *
1196libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1197{
sewardj70adeb22002-04-27 01:35:38 +00001198 void* v;
1199 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001200 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001201 if (key < _LIBC_TSD_KEY_MALLOC
1202 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001203 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001204 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1205 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001206 "valgrind's libpthread.so: libc_internal_tsd_get: "
1207 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001208 init_libc_tsd_keys();
1209 v = pthread_getspecific(libc_specifics_keys[key]);
1210 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1211 return v;
1212}
1213
1214
1215
1216
sewardj70adeb22002-04-27 01:35:38 +00001217int (*__libc_internal_tsd_set)
1218 (enum __libc_tsd_key_t key, const void * pointer)
1219 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001220
sewardj70adeb22002-04-27 01:35:38 +00001221void* (*__libc_internal_tsd_get)
1222 (enum __libc_tsd_key_t key)
1223 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001224
1225
sewardje663cb92002-04-12 10:26:32 +00001226/* ---------------------------------------------------------------------
1227 These are here (I think) because they are deemed cancellation
1228 points by POSIX. For the moment we'll simply pass the call along
1229 to the corresponding thread-unaware (?) libc routine.
1230 ------------------------------------------------------------------ */
1231
sewardje663cb92002-04-12 10:26:32 +00001232#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001233#include <sys/types.h>
1234#include <sys/socket.h>
1235
sewardjd529a442002-05-04 19:49:21 +00001236#ifdef GLIBC_2_1
1237extern
1238int __sigaction
1239 (int signum,
1240 const struct sigaction *act,
1241 struct sigaction *oldact);
1242#else
sewardje663cb92002-04-12 10:26:32 +00001243extern
1244int __libc_sigaction
1245 (int signum,
1246 const struct sigaction *act,
1247 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001248#endif
sewardje663cb92002-04-12 10:26:32 +00001249int sigaction(int signum,
1250 const struct sigaction *act,
1251 struct sigaction *oldact)
1252{
sewardj2a1dcce2002-04-22 12:45:25 +00001253# ifdef GLIBC_2_1
1254 return __sigaction(signum, act, oldact);
1255# else
sewardj45b4b372002-04-16 22:50:32 +00001256 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001257# endif
sewardje663cb92002-04-12 10:26:32 +00001258}
1259
1260
1261extern
1262int __libc_connect(int sockfd,
1263 const struct sockaddr *serv_addr,
1264 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001265__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001266int connect(int sockfd,
1267 const struct sockaddr *serv_addr,
1268 socklen_t addrlen)
1269{
sewardj45b4b372002-04-16 22:50:32 +00001270 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001271}
1272
1273
1274extern
1275int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001276__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001277int fcntl(int fd, int cmd, long arg)
1278{
sewardj45b4b372002-04-16 22:50:32 +00001279 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001280}
1281
1282
1283extern
1284ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001285__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001286ssize_t write(int fd, const void *buf, size_t count)
1287{
sewardj45b4b372002-04-16 22:50:32 +00001288 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001289}
1290
1291
1292extern
1293ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001294__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001295ssize_t read(int fd, void *buf, size_t count)
1296{
sewardj45b4b372002-04-16 22:50:32 +00001297 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001298}
1299
sewardjbe32e452002-04-24 20:29:58 +00001300
1301extern
sewardj853f55d2002-04-26 00:27:53 +00001302int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001303__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001304int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001305{
sewardj853f55d2002-04-26 00:27:53 +00001306 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001307}
1308
sewardje663cb92002-04-12 10:26:32 +00001309
1310extern
sewardj853f55d2002-04-26 00:27:53 +00001311int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001312__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001313int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001314{
sewardj853f55d2002-04-26 00:27:53 +00001315 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001316}
1317
1318
1319extern
1320int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001321__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001322int close(int fd)
1323{
sewardj45b4b372002-04-16 22:50:32 +00001324 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001325}
1326
1327
1328extern
1329int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001330__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001331int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1332{
sewardj705d3cb2002-05-23 13:13:12 +00001333 wait_for_fd_to_be_readable_or_erring(s);
sewardj45b4b372002-04-16 22:50:32 +00001334 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001335}
1336
1337
1338extern
1339pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001340pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001341{
sewardj45b4b372002-04-16 22:50:32 +00001342 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001343}
1344
1345
1346extern
1347pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001348__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001349pid_t waitpid(pid_t pid, int *status, int options)
1350{
sewardj45b4b372002-04-16 22:50:32 +00001351 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001352}
1353
1354
1355extern
1356int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001357__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001358int nanosleep(const struct timespec *req, struct timespec *rem)
1359{
1360 return __libc_nanosleep(req, rem);
1361}
1362
sewardjbe32e452002-04-24 20:29:58 +00001363
sewardje663cb92002-04-12 10:26:32 +00001364extern
1365int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001366__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001367int fsync(int fd)
1368{
sewardj45b4b372002-04-16 22:50:32 +00001369 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001370}
1371
sewardjbe32e452002-04-24 20:29:58 +00001372
sewardj70c75362002-04-13 04:18:32 +00001373extern
1374off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001375__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001376off_t lseek(int fildes, off_t offset, int whence)
1377{
sewardj45b4b372002-04-16 22:50:32 +00001378 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001379}
1380
sewardjbe32e452002-04-24 20:29:58 +00001381
1382extern
1383__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001384__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001385__off64_t lseek64(int fildes, __off64_t offset, int whence)
1386{
1387 return __libc_lseek64(fildes, offset, whence);
1388}
1389
1390
sewardj726c4122002-05-16 23:39:10 +00001391extern
1392ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1393 __off64_t __offset);
1394ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1395 __off64_t __offset)
1396{
1397 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1398}
1399
1400
sewardja18e2102002-05-18 10:43:22 +00001401extern
1402ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1403 __off64_t __offset);
1404ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1405 __off64_t __offset)
1406{
1407 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1408}
1409
sewardj726c4122002-05-16 23:39:10 +00001410
sewardj39b93b12002-05-18 10:56:27 +00001411extern
1412ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1413__attribute__((weak))
1414ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1415{
1416 return __libc_pwrite(fd, buf, count, offset);
1417}
1418
1419
1420extern
1421ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1422__attribute__((weak))
1423ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1424{
1425 return __libc_pread(fd, buf, count, offset);
1426}
1427
1428
sewardj6af4b5d2002-04-16 04:40:49 +00001429extern
1430void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001431/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001432void longjmp(jmp_buf env, int val)
1433{
1434 __libc_longjmp(env, val);
1435}
1436
sewardjbe32e452002-04-24 20:29:58 +00001437
sewardj6af4b5d2002-04-16 04:40:49 +00001438extern
1439int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001440__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001441int send(int s, const void *msg, size_t len, int flags)
1442{
1443 return __libc_send(s, msg, len, flags);
1444}
1445
sewardjbe32e452002-04-24 20:29:58 +00001446
sewardj1e8cdc92002-04-18 11:37:52 +00001447extern
1448int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001449__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001450int recv(int s, void *buf, size_t len, int flags)
1451{
1452 return __libc_recv(s, buf, len, flags);
1453}
1454
sewardjbe32e452002-04-24 20:29:58 +00001455
sewardj3665ded2002-05-16 16:57:25 +00001456extern
1457int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1458__attribute__((weak))
1459int sendmsg(int s, const struct msghdr *msg, int flags)
1460{
1461 return __libc_sendmsg(s, msg, flags);
1462}
1463
1464
sewardj796d6a22002-04-24 02:28:34 +00001465extern
sewardj436e0582002-04-26 14:31:40 +00001466int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1467 struct sockaddr *from, socklen_t *fromlen);
1468__attribute__((weak))
1469int recvfrom(int s, void *buf, size_t len, int flags,
1470 struct sockaddr *from, socklen_t *fromlen)
1471{
1472 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1473}
1474
1475
1476extern
sewardj796d6a22002-04-24 02:28:34 +00001477int __libc_sendto(int s, const void *msg, size_t len, int flags,
1478 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001479__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001480int sendto(int s, const void *msg, size_t len, int flags,
1481 const struct sockaddr *to, socklen_t tolen)
1482{
1483 return __libc_sendto(s, msg, len, flags, to, tolen);
1484}
1485
sewardjbe32e452002-04-24 20:29:58 +00001486
sewardj369b1702002-04-24 13:28:15 +00001487extern
1488int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001489__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001490int system(const char* str)
1491{
1492 return __libc_system(str);
1493}
1494
sewardjbe32e452002-04-24 20:29:58 +00001495
sewardjab0b1c32002-04-24 19:26:47 +00001496extern
1497pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001498__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001499pid_t wait(int *status)
1500{
1501 return __libc_wait(status);
1502}
1503
sewardj45b4b372002-04-16 22:50:32 +00001504
sewardj67f1d582002-05-24 02:11:32 +00001505extern
1506int __libc_msync(const void *start, size_t length, int flags);
1507__attribute__((weak))
1508int msync(const void *start, size_t length, int flags)
1509{
1510 return __libc_msync(start, length, flags);
1511}
1512
sewardj5905fae2002-04-26 13:25:00 +00001513
sewardj3b13f0e2002-04-25 20:17:29 +00001514/* ---------------------------------------------------------------------
1515 Nonblocking implementations of select() and poll(). This stuff will
1516 surely rot your mind.
1517 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001518
sewardj08a4c3f2002-04-13 03:45:44 +00001519/*--------------------------------------------------*/
1520
1521#include "vg_kerneliface.h"
1522
1523static
1524__inline__
1525int is_kerror ( int res )
1526{
1527 if (res >= -4095 && res <= -1)
1528 return 1;
1529 else
1530 return 0;
1531}
1532
1533
1534static
1535int my_do_syscall1 ( int syscallno, int arg1 )
1536{
1537 int __res;
1538 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1539 : "=a" (__res)
1540 : "0" (syscallno),
1541 "d" (arg1) );
1542 return __res;
1543}
1544
1545static
1546int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001547 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001548{
1549 int __res;
1550 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1551 : "=a" (__res)
1552 : "0" (syscallno),
1553 "d" (arg1),
1554 "c" (arg2) );
1555 return __res;
1556}
1557
1558static
sewardjf854f472002-04-21 12:19:41 +00001559int my_do_syscall3 ( int syscallno,
1560 int arg1, int arg2, int arg3 )
1561{
1562 int __res;
1563 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1564 : "=a" (__res)
1565 : "0" (syscallno),
1566 "S" (arg1),
1567 "c" (arg2),
1568 "d" (arg3) );
1569 return __res;
1570}
1571
1572static
sewardj08a4c3f2002-04-13 03:45:44 +00001573int do_syscall_select( int n,
1574 vki_fd_set* readfds,
1575 vki_fd_set* writefds,
1576 vki_fd_set* exceptfds,
1577 struct vki_timeval * timeout )
1578{
1579 int res;
1580 int args[5];
1581 args[0] = n;
1582 args[1] = (int)readfds;
1583 args[2] = (int)writefds;
1584 args[3] = (int)exceptfds;
1585 args[4] = (int)timeout;
1586 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001587 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001588}
1589
1590
1591/* This is a wrapper round select(), which makes it thread-safe,
1592 meaning that only this thread will block, rather than the entire
1593 process. This wrapper in turn depends on nanosleep() not to block
1594 the entire process, but I think (hope? suspect?) that POSIX
1595 pthreads guarantees that to be the case.
1596
1597 Basic idea is: modify the timeout parameter to select so that it
1598 returns immediately. Poll like this until select returns non-zero,
1599 indicating something interesting happened, or until our time is up.
1600 Space out the polls with nanosleeps of say 20 milliseconds, which
1601 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001602
1603 Assumes:
1604 * (checked via assert) types fd_set and vki_fd_set are identical.
1605 * (checked via assert) types timeval and vki_timeval are identical.
1606 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1607 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001608*/
sewardj08a4c3f2002-04-13 03:45:44 +00001609
sewardj5905fae2002-04-26 13:25:00 +00001610/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001611int select ( int n,
1612 fd_set *rfds,
1613 fd_set *wfds,
1614 fd_set *xfds,
1615 struct timeval *timeout )
1616{
sewardj5f07b662002-04-23 16:52:51 +00001617 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001618 int res;
1619 fd_set rfds_copy;
1620 fd_set wfds_copy;
1621 fd_set xfds_copy;
1622 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001623 struct vki_timeval zero_timeout;
1624 struct vki_timespec nanosleep_interval;
1625
sewardj5f07b662002-04-23 16:52:51 +00001626 /* gcc's complains about ms_end being used uninitialised -- classic
1627 case it can't understand, where ms_end is both defined and used
1628 only if timeout != NULL. Hence ... */
1629 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001630
1631 /* We assume that the kernel and libc data layouts are identical
1632 for the following types. These asserts provide a crude
1633 check. */
1634 if (sizeof(fd_set) != sizeof(vki_fd_set)
1635 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1636 barf("valgrind's hacky non-blocking select(): data sizes error");
1637
sewardj5f07b662002-04-23 16:52:51 +00001638 /* Detect the current time and simultaneously find out if we are
1639 running on Valgrind. */
1640 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1641 VG_USERREQ__READ_MILLISECOND_TIMER,
1642 0, 0, 0, 0);
1643
1644 /* If a zero timeout specified, this call is harmless. Also go
1645 this route if we're not running on Valgrind, for whatever
1646 reason. */
1647 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1648 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001649 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001650 (vki_fd_set*)wfds,
1651 (vki_fd_set*)xfds,
1652 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001653 if (is_kerror(res)) {
1654 * (__errno_location()) = -res;
1655 return -1;
1656 } else {
1657 return res;
1658 }
1659 }
sewardj08a4c3f2002-04-13 03:45:44 +00001660
sewardj5f07b662002-04-23 16:52:51 +00001661 /* If a timeout was specified, set ms_end to be the end millisecond
1662 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001663 if (timeout) {
1664 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
1665 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001666 ms_end = ms_now;
1667 ms_end += (timeout->tv_usec / 1000);
1668 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001669 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +00001670 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001671 }
1672
1673 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1674
1675 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001676 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001677 while (1) {
1678 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +00001679 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1680 VG_USERREQ__READ_MILLISECOND_TIMER,
1681 0, 0, 0, 0);
1682 assert(ms_now != 0xFFFFFFFF);
1683 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +00001684 /* timeout; nothing interesting happened. */
1685 if (rfds) FD_ZERO(rfds);
1686 if (wfds) FD_ZERO(wfds);
1687 if (xfds) FD_ZERO(xfds);
1688 return 0;
1689 }
1690 }
1691
1692 /* These could be trashed each time round the loop, so restore
1693 them each time. */
1694 if (rfds) rfds_copy = *rfds;
1695 if (wfds) wfds_copy = *wfds;
1696 if (xfds) xfds_copy = *xfds;
1697
1698 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1699
1700 res = do_syscall_select( n,
1701 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1702 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1703 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1704 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001705 if (is_kerror(res)) {
1706 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001707 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001708 * (__errno_location()) = -res;
1709 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001710 }
1711 if (res > 0) {
1712 /* one or more fds is ready. Copy out resulting sets and
1713 return. */
1714 if (rfds) *rfds = rfds_copy;
1715 if (wfds) *wfds = wfds_copy;
1716 if (xfds) *xfds = xfds_copy;
1717 return res;
1718 }
1719 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1720 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001721 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001722 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001723 /* It's critical here that valgrind's nanosleep implementation
1724 is nonblocking. */
1725 (void)my_do_syscall2(__NR_nanosleep,
1726 (int)(&nanosleep_interval), (int)NULL);
1727 }
1728}
1729
1730
1731
1732
1733#include <sys/poll.h>
1734
sewardj72d58482002-04-24 02:20:20 +00001735#ifdef GLIBC_2_1
1736typedef unsigned long int nfds_t;
1737#endif
1738
sewardj705d3cb2002-05-23 13:13:12 +00001739
sewardj5905fae2002-04-26 13:25:00 +00001740/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00001741int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1742{
sewardj5f07b662002-04-23 16:52:51 +00001743 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001744 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001745 struct vki_timespec nanosleep_interval;
1746
1747 ensure_valgrind("poll");
1748
sewardj5f07b662002-04-23 16:52:51 +00001749 /* Detect the current time and simultaneously find out if we are
1750 running on Valgrind. */
1751 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1752 VG_USERREQ__READ_MILLISECOND_TIMER,
1753 0, 0, 0, 0);
1754
sewardjf854f472002-04-21 12:19:41 +00001755 if (/* CHECK SIZES FOR struct pollfd */
1756 sizeof(struct timeval) != sizeof(struct vki_timeval))
1757 barf("valgrind's hacky non-blocking poll(): data sizes error");
1758
sewardj5f07b662002-04-23 16:52:51 +00001759 /* dummy initialisation to keep gcc -Wall happy */
1760 ms_end = 0;
1761
1762 /* If a zero timeout specified, this call is harmless. Also do
1763 this if not running on Valgrind. */
1764 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001765 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1766 if (is_kerror(res)) {
1767 * (__errno_location()) = -res;
1768 return -1;
1769 } else {
1770 return res;
1771 }
1772 }
1773
sewardj5f07b662002-04-23 16:52:51 +00001774 /* If a timeout was specified, set ms_end to be the end wallclock
1775 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001776 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00001777 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001778 }
1779
1780 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1781
1782 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1783 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001784 assert(__timeout != 0);
1785
sewardjf854f472002-04-21 12:19:41 +00001786 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001787 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001788 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1789 VG_USERREQ__READ_MILLISECOND_TIMER,
1790 0, 0, 0, 0);
1791 assert(ms_now != 0xFFFFFFFF);
1792 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001793 /* timeout; nothing interesting happened. */
1794 for (i = 0; i < __nfds; i++)
1795 __fds[i].revents = 0;
1796 return 0;
1797 }
1798 }
1799
sewardj5f07b662002-04-23 16:52:51 +00001800 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001801 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1802 if (is_kerror(res)) {
1803 /* Some kind of error. Set errno and return. */
1804 * (__errno_location()) = -res;
1805 return -1;
1806 }
1807 if (res > 0) {
1808 /* One or more fds is ready. Return now. */
1809 return res;
1810 }
1811 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1812 /* nanosleep and go round again */
1813 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001814 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001815 /* It's critical here that valgrind's nanosleep implementation
1816 is nonblocking. */
1817 (void)my_do_syscall2(__NR_nanosleep,
1818 (int)(&nanosleep_interval), (int)NULL);
1819 }
1820}
sewardj3b13f0e2002-04-25 20:17:29 +00001821
1822
sewardj705d3cb2002-05-23 13:13:12 +00001823/* Helper function used to make accept() non-blocking. Idea is to use
1824 the above nonblocking poll() to make this thread ONLY wait for the
1825 specified fd to become ready, and then return. */
1826static void wait_for_fd_to_be_readable_or_erring ( int fd )
1827{
1828 struct pollfd pfd;
sewardj6e6cbaa2002-05-24 02:12:52 +00001829 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardj705d3cb2002-05-23 13:13:12 +00001830 pfd.fd = fd;
1831 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
1832 /* ... but not POLLOUT, you may notice. */
1833 pfd.revents = 0;
1834 (void)poll(&pfd, 1, -1 /* forever */);
1835}
1836
1837
sewardj3b13f0e2002-04-25 20:17:29 +00001838/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00001839 Hacky implementation of semaphores.
1840 ------------------------------------------------------------------ */
1841
1842#include <semaphore.h>
1843
1844/* This is a terrible way to do the remapping. Plan is to import an
1845 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00001846
1847typedef
1848 struct {
1849 pthread_mutex_t se_mx;
1850 pthread_cond_t se_cv;
1851 int count;
1852 }
1853 vg_sem_t;
1854
1855static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
1856
1857static int se_remap_used = 0;
1858static sem_t* se_remap_orig[VG_N_SEMAPHORES];
1859static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
1860
1861static vg_sem_t* se_remap ( sem_t* orig )
1862{
1863 int res, i;
1864 res = __pthread_mutex_lock(&se_remap_mx);
1865 assert(res == 0);
1866
1867 for (i = 0; i < se_remap_used; i++) {
1868 if (se_remap_orig[i] == orig)
1869 break;
1870 }
1871 if (i == se_remap_used) {
1872 if (se_remap_used == VG_N_SEMAPHORES) {
1873 res = pthread_mutex_unlock(&se_remap_mx);
1874 assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00001875 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00001876 }
1877 se_remap_used++;
1878 se_remap_orig[i] = orig;
1879 /* printf("allocated semaphore %d\n", i); */
1880 }
1881 res = __pthread_mutex_unlock(&se_remap_mx);
1882 assert(res == 0);
1883 return &se_remap_new[i];
1884}
1885
1886
1887int sem_init(sem_t *sem, int pshared, unsigned int value)
1888{
1889 int res;
1890 vg_sem_t* vg_sem;
1891 ensure_valgrind("sem_init");
1892 if (pshared != 0) {
1893 errno = ENOSYS;
1894 return -1;
1895 }
1896 vg_sem = se_remap(sem);
1897 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
1898 assert(res == 0);
1899 res = pthread_cond_init(&vg_sem->se_cv, NULL);
1900 assert(res == 0);
1901 vg_sem->count = value;
1902 return 0;
1903}
1904
1905
1906int sem_wait ( sem_t* sem )
1907{
1908 int res;
1909 vg_sem_t* vg_sem;
1910 ensure_valgrind("sem_wait");
1911 vg_sem = se_remap(sem);
1912 res = __pthread_mutex_lock(&vg_sem->se_mx);
1913 assert(res == 0);
1914 while (vg_sem->count == 0) {
1915 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
1916 assert(res == 0);
1917 }
1918 vg_sem->count--;
1919 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1920 assert(res == 0);
1921 return 0;
1922}
1923
1924int sem_post ( sem_t* sem )
1925{
1926 int res;
1927 vg_sem_t* vg_sem;
1928 ensure_valgrind("sem_post");
1929 vg_sem = se_remap(sem);
1930 res = __pthread_mutex_lock(&vg_sem->se_mx);
1931 assert(res == 0);
1932 if (vg_sem->count == 0) {
1933 vg_sem->count++;
1934 res = pthread_cond_broadcast(&vg_sem->se_cv);
1935 assert(res == 0);
1936 } else {
1937 vg_sem->count++;
1938 }
1939 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1940 assert(res == 0);
1941 return 0;
1942}
1943
1944
1945int sem_trywait ( sem_t* sem )
1946{
1947 int ret, res;
1948 vg_sem_t* vg_sem;
1949 ensure_valgrind("sem_trywait");
1950 vg_sem = se_remap(sem);
1951 res = __pthread_mutex_lock(&vg_sem->se_mx);
1952 assert(res == 0);
1953 if (vg_sem->count > 0) {
1954 vg_sem->count--;
1955 ret = 0;
1956 } else {
1957 ret = -1;
1958 errno = EAGAIN;
1959 }
1960 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1961 assert(res == 0);
1962 return ret;
1963}
1964
1965
1966int sem_getvalue(sem_t* sem, int * sval)
1967{
1968 vg_sem_t* vg_sem;
1969 ensure_valgrind("sem_trywait");
1970 vg_sem = se_remap(sem);
1971 *sval = vg_sem->count;
1972 return 0;
1973}
1974
1975
1976int sem_destroy(sem_t * sem)
1977{
1978 kludged("sem_destroy");
1979 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
1980 return 0;
1981}
1982
1983
1984/* ---------------------------------------------------------------------
sewardja1ac5cb2002-05-27 13:00:05 +00001985 Hacky implementation of reader-writer locks.
1986 ------------------------------------------------------------------ */
1987
1988/*
1989Errata from 7th printing:
1990
1991 Page 259, rwlock.c, line 27, the two "!=" should be ">", for
1992 consistency with other similar tests. (The values should never be
1993 negative; this isn't a fix, but an improvement to clarity and
1994 consistency.)
1995
1996 [27] if (rwl->r_wait > 0 || rwl->w_wait > 0) {
1997
1998 Page 259, rwlock.c, lines 39 and 40, in both lines, "==" should
1999 become "!=":
2000
2001 [39] return (status != 0 ? status
2002 [40] : (status1 != 0 ? status1 : status2));
2003*/
2004
2005/*
2006 * rwlock.h
2007 *
2008 * This header file describes the "reader/writer lock" synchronization
2009 * construct. The type rwlock_t describes the full state of the lock
2010 * including the POSIX 1003.1c synchronization objects necessary.
2011 *
2012 * A reader/writer lock allows a thread to lock shared data either for shared
2013 * read access or exclusive write access.
2014 *
2015 * The rwl_init() and rwl_destroy() functions, respectively, allow you to
2016 * initialize/create and destroy/free the reader/writer lock.
2017 */
2018
sewardja1ac5cb2002-05-27 13:00:05 +00002019/*
2020 * Structure describing a read-write lock.
2021 */
2022typedef struct {
2023 pthread_mutex_t mutex;
2024 pthread_cond_t read; /* wait for read */
2025 pthread_cond_t write; /* wait for write */
2026 int valid; /* set when valid */
2027 int r_active; /* readers active */
2028 int w_active; /* writer active */
2029 int r_wait; /* readers waiting */
2030 int w_wait; /* writers waiting */
2031 int pref_writer; /* != 0 --> prefer writer */
2032} vg_rwlock_t;
2033
2034#define VG_RWLOCK_VALID 0xfacade
2035
2036
2037/*
2038 * Support static initialization of barriers
2039 */
2040#define VG_RWL_INITIALIZER \
2041 {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \
2042 PTHREAD_COND_INITIALIZER, VG_RWLOCK_VALID, 0, 0, 0, 0, 1}
2043
2044
2045static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2046
2047static int rw_remap_used = 0;
2048static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2049static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2050
2051/* Take the address of a LinuxThreads rwlock_t and return the shadow
2052 address of our version. Further, if the LinuxThreads version
2053 appears to have been statically initialised, do the same to the one
2054 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2055 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2056 uninitialised and non-zero meaning initialised.
2057*/
2058static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2059{
2060 int res, i;
2061 vg_rwlock_t* vg_rwl;
2062 res = __pthread_mutex_lock(&rw_remap_mx);
2063 assert(res == 0);
2064
2065 for (i = 0; i < rw_remap_used; i++) {
2066 if (rw_remap_orig[i] == orig)
2067 break;
2068 }
2069 if (i == rw_remap_used) {
2070 if (rw_remap_used == VG_N_RWLOCKS) {
2071 res = pthread_mutex_unlock(&rw_remap_mx);
2072 assert(res == 0);
2073 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2074 }
2075 rw_remap_used++;
2076 rw_remap_orig[i] = orig;
2077 if (0) printf("allocated rwlock %d\n", i);
2078 }
2079 res = __pthread_mutex_unlock(&rw_remap_mx);
2080 assert(res == 0);
2081 vg_rwl = &rw_remap_new[i];
2082
2083 /* Mimic static initialisation of the original. */
2084 if (orig->__rw_readers == 0) {
2085 const vg_rwlock_t default_rwl = VG_RWL_INITIALIZER;
2086 orig->__rw_readers = 1;
2087 *vg_rwl = default_rwl;
2088 vg_rwl->pref_writer = 1;
2089 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
2090 vg_rwl->pref_writer = 0;
2091 }
2092
2093 return vg_rwl;
2094}
2095
2096
2097/*
2098 * rwlock.c
2099 *
2100 * This file implements the "read-write lock" synchronization
2101 * construct.
2102 *
2103 * A read-write lock allows a thread to lock shared data either
2104 * for shared read access or exclusive write access.
2105 *
2106 * The rwl_init() and rwl_destroy() functions, respectively,
2107 * allow you to initialize/create and destroy/free the
2108 * read-write lock.
2109 *
2110 * The rwl_readlock() function locks a read-write lock for
2111 * shared read access, and rwl_readunlock() releases the
2112 * lock. rwl_readtrylock() attempts to lock a read-write lock
2113 * for read access, and returns EBUSY instead of blocking.
2114 *
2115 * The rwl_writelock() function locks a read-write lock for
2116 * exclusive write access, and rwl_writeunlock() releases the
2117 * lock. rwl_writetrylock() attempts to lock a read-write lock
2118 * for write access, and returns EBUSY instead of blocking.
2119 */
2120
2121
2122/*
2123 * Initialize a read-write lock
2124 */
2125static int rwl_init ( vg_rwlock_t *rwl )
2126{
2127 int status;
2128
2129 rwl->r_active = 0;
2130 rwl->r_wait = rwl->w_wait = 0;
2131 rwl->w_active = 0;
2132 status = pthread_mutex_init (&rwl->mutex, NULL);
2133 if (status != 0)
2134 return status;
2135 status = pthread_cond_init (&rwl->read, NULL);
2136 if (status != 0) {
2137 /* if unable to create read CV, destroy mutex */
2138 pthread_mutex_destroy (&rwl->mutex);
2139 return status;
2140 }
2141 status = pthread_cond_init (&rwl->write, NULL);
2142 if (status != 0) {
2143 /* if unable to create write CV, destroy read CV and mutex */
2144 pthread_cond_destroy (&rwl->read);
2145 pthread_mutex_destroy (&rwl->mutex);
2146 return status;
2147 }
2148 rwl->valid = VG_RWLOCK_VALID;
2149 return 0;
2150}
2151
2152/*
2153 * Destroy a read-write lock
2154 */
2155static int rwl_destroy (vg_rwlock_t *rwl)
2156{
2157 int status, status1, status2;
2158
2159 if (rwl->valid != VG_RWLOCK_VALID)
2160 return EINVAL;
2161 status = pthread_mutex_lock (&rwl->mutex);
2162 if (status != 0)
2163 return status;
2164
2165 /*
2166 * Check whether any threads own the lock; report "BUSY" if
2167 * so.
2168 */
2169 if (rwl->r_active > 0 || rwl->w_active) {
2170 pthread_mutex_unlock (&rwl->mutex);
2171 return EBUSY;
2172 }
2173
2174 /*
2175 * Check whether any threads are known to be waiting; report
2176 * EBUSY if so.
2177 */
2178 if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2179 pthread_mutex_unlock (&rwl->mutex);
2180 return EBUSY;
2181 }
2182
2183 rwl->valid = 0;
2184 status = pthread_mutex_unlock (&rwl->mutex);
2185 if (status != 0)
2186 return status;
2187 status = pthread_mutex_destroy (&rwl->mutex);
2188 status1 = pthread_cond_destroy (&rwl->read);
2189 status2 = pthread_cond_destroy (&rwl->write);
2190 return (status != 0 ? status : (status1 != 0 ? status1 : status2));
2191}
2192
2193/*
2194 * Handle cleanup when the read lock condition variable
2195 * wait is cancelled.
2196 *
2197 * Simply record that the thread is no longer waiting,
2198 * and unlock the mutex.
2199 */
2200static void rwl_readcleanup (void *arg)
2201{
2202 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2203
2204 rwl->r_wait--;
2205 pthread_mutex_unlock (&rwl->mutex);
2206}
2207
2208/*
2209 * Lock a read-write lock for read access.
2210 */
2211static int rwl_readlock (vg_rwlock_t *rwl)
2212{
2213 int status;
2214
2215 if (rwl->valid != VG_RWLOCK_VALID)
2216 return EINVAL;
2217 status = pthread_mutex_lock (&rwl->mutex);
2218 if (status != 0)
2219 return status;
2220 if (rwl->w_active) {
2221 rwl->r_wait++;
2222 pthread_cleanup_push (rwl_readcleanup, (void*)rwl);
2223 while (rwl->w_active) {
2224 status = pthread_cond_wait (&rwl->read, &rwl->mutex);
2225 if (status != 0)
2226 break;
2227 }
2228 pthread_cleanup_pop (0);
2229 rwl->r_wait--;
2230 }
2231 if (status == 0)
2232 rwl->r_active++;
2233 pthread_mutex_unlock (&rwl->mutex);
2234 return status;
2235}
2236
2237/*
2238 * Attempt to lock a read-write lock for read access (don't
2239 * block if unavailable).
2240 */
2241static int rwl_readtrylock (vg_rwlock_t *rwl)
2242{
2243 int status, status2;
2244
2245 if (rwl->valid != VG_RWLOCK_VALID)
2246 return EINVAL;
2247 status = pthread_mutex_lock (&rwl->mutex);
2248 if (status != 0)
2249 return status;
2250 if (rwl->w_active)
2251 status = EBUSY;
2252 else
2253 rwl->r_active++;
2254 status2 = pthread_mutex_unlock (&rwl->mutex);
2255 return (status2 != 0 ? status2 : status);
2256}
2257
2258/*
2259 * Handle cleanup when the write lock condition variable
2260 * wait is cancelled.
2261 *
2262 * Simply record that the thread is no longer waiting,
2263 * and unlock the mutex.
2264 */
2265static void rwl_writecleanup (void *arg)
2266{
2267 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2268
2269 rwl->w_wait--;
2270 pthread_mutex_unlock (&rwl->mutex);
2271}
2272
2273/*
2274 * Lock a read-write lock for write access.
2275 */
2276static int rwl_writelock (vg_rwlock_t *rwl)
2277{
2278 int status;
2279
2280 if (rwl->valid != VG_RWLOCK_VALID)
2281 return EINVAL;
2282 status = pthread_mutex_lock (&rwl->mutex);
2283 if (status != 0)
2284 return status;
2285 if (rwl->w_active || rwl->r_active > 0) {
2286 rwl->w_wait++;
2287 pthread_cleanup_push (rwl_writecleanup, (void*)rwl);
2288 while (rwl->w_active || rwl->r_active > 0) {
2289 status = pthread_cond_wait (&rwl->write, &rwl->mutex);
2290 if (status != 0)
2291 break;
2292 }
2293 pthread_cleanup_pop (0);
2294 rwl->w_wait--;
2295 }
2296 if (status == 0)
2297 rwl->w_active = 1;
2298 pthread_mutex_unlock (&rwl->mutex);
2299 return status;
2300}
2301
2302/*
2303 * Attempt to lock a read-write lock for write access. Don't
2304 * block if unavailable.
2305 */
2306static int rwl_writetrylock (vg_rwlock_t *rwl)
2307{
2308 int status, status2;
2309
2310 if (rwl->valid != VG_RWLOCK_VALID)
2311 return EINVAL;
2312 status = pthread_mutex_lock (&rwl->mutex);
2313 if (status != 0)
2314 return status;
2315 if (rwl->w_active || rwl->r_active > 0)
2316 status = EBUSY;
2317 else
2318 rwl->w_active = 1;
2319 status2 = pthread_mutex_unlock (&rwl->mutex);
2320 return (status != 0 ? status : status2);
2321}
2322
2323/*
2324 * Unlock a read-write lock, using the r_active and w_active fields to
2325 * decide whether we're in a read or write lock.
2326 */
2327static int rwl_unlock (vg_rwlock_t *rwl)
2328{
2329 int status, status2;
2330
2331 if (rwl->valid != VG_RWLOCK_VALID)
2332 return EINVAL;
2333 status = pthread_mutex_lock (&rwl->mutex);
2334 if (status != 0)
2335 return status;
2336
2337 if (rwl->r_active > 0) {
2338
2339 /* READ case */
2340 assert(!rwl->w_active);
2341 rwl->r_active--;
2342 if (rwl->r_active == 0 && rwl->w_wait > 0)
2343 status = pthread_cond_signal (&rwl->write);
2344 /* END READ case */
2345
2346 } else {
2347
2348 /* WRITE case */
2349 assert(rwl->w_active);
2350 assert(rwl->r_active == 0);
2351 rwl->w_active = 0;
2352
2353 if (rwl->pref_writer) {
2354 /* Do writer-preference wakeups. */
2355 if (rwl->w_wait > 0) {
2356 status = pthread_cond_signal (&rwl->write);
2357 if (status != 0) {
2358 pthread_mutex_unlock (&rwl->mutex);
2359 return status;
2360 }
2361 } else if (rwl->r_wait > 0) {
2362 status = pthread_cond_broadcast (&rwl->read);
2363 if (status != 0) {
2364 pthread_mutex_unlock (&rwl->mutex);
2365 return status;
2366 }
2367 }
2368 } else {
2369 /* Do reader-preference wakeups. */
2370 if (rwl->r_wait > 0) {
2371 status = pthread_cond_broadcast (&rwl->read);
2372 if (status != 0) {
2373 pthread_mutex_unlock (&rwl->mutex);
2374 return status;
2375 }
2376 } else if (rwl->w_wait > 0) {
2377 status = pthread_cond_signal (&rwl->write);
2378 if (status != 0) {
2379 pthread_mutex_unlock (&rwl->mutex);
2380 return status;
2381 }
2382 }
2383 }
2384 /* END WRITE case */
2385
2386 }
2387
2388 status2 = pthread_mutex_unlock (&rwl->mutex);
2389 return (status2 == 0 ? status : status2);
2390}
2391
2392/* -------------------------------- */
2393
2394int pthread_rwlock_init ( pthread_rwlock_t* orig,
2395 const pthread_rwlockattr_t* attr )
2396{
2397 int res;
2398 vg_rwlock_t* rwl;
2399 if (0) printf ("pthread_rwlock_init\n");
2400 /* Force the remapper to initialise the shadow. */
2401 orig->__rw_readers = 0;
2402 /* Install the lock preference; the remapper needs to know it. */
2403 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2404 if (attr)
2405 orig->__rw_kind = attr->__lockkind;
2406 rwl = rw_remap ( orig );
2407 res = rwl_init ( rwl );
2408 return res;
2409}
2410
2411int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2412{
2413 int res;
2414 vg_rwlock_t* rwl;
2415 if (0) printf ("pthread_rwlock_destroy\n");
2416 rwl = rw_remap ( orig );
2417 res = rwl_destroy ( rwl );
2418 return res;
2419}
2420
2421int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2422{
2423 int res;
2424 vg_rwlock_t* rwl;
2425 if (0) printf ("pthread_rwlock_rdlock\n");
2426 rwl = rw_remap ( orig );
2427 res = rwl_readlock ( rwl );
2428 return res;
2429}
2430
2431int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2432{
2433 int res;
2434 vg_rwlock_t* rwl;
2435 if (0) printf ("pthread_rwlock_tryrdlock\n");
2436 rwl = rw_remap ( orig );
2437 res = rwl_readtrylock ( rwl );
2438 return res;
2439}
2440
2441int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2442{
2443 int res;
2444 vg_rwlock_t* rwl;
2445 if (0) printf ("pthread_rwlock_wrlock\n");
2446 rwl = rw_remap ( orig );
2447 res = rwl_writelock ( rwl );
2448 return res;
2449}
2450
2451int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2452{
2453 int res;
2454 vg_rwlock_t* rwl;
2455 if (0) printf ("pthread_rwlock_trywrlock\n");
2456 rwl = rw_remap ( orig );
2457 res = rwl_writetrylock ( rwl );
2458 return res;
2459}
2460
2461int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2462{
2463 int res;
2464 vg_rwlock_t* rwl;
2465 if (0) printf ("pthread_rwlock_unlock\n");
2466 rwl = rw_remap ( orig );
2467 res = rwl_unlock ( rwl );
2468 return res;
2469}
2470
2471
2472/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002473 B'stard.
2474 ------------------------------------------------------------------ */
2475
2476# define strong_alias(name, aliasname) \
2477 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2478
sewardj5905fae2002-04-26 13:25:00 +00002479# define weak_alias(name, aliasname) \
2480 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002481
sewardj5905fae2002-04-26 13:25:00 +00002482strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2483strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2484strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2485strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2486 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2487strong_alias(__pthread_mutex_init, pthread_mutex_init)
2488strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2489strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2490strong_alias(__pthread_once, pthread_once)
2491strong_alias(__pthread_atfork, pthread_atfork)
2492strong_alias(__pthread_key_create, pthread_key_create)
2493strong_alias(__pthread_getspecific, pthread_getspecific)
2494strong_alias(__pthread_setspecific, pthread_setspecific)
2495
sewardjd529a442002-05-04 19:49:21 +00002496#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002497strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002498#endif
2499
sewardj5905fae2002-04-26 13:25:00 +00002500strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002501strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002502strong_alias(lseek, __lseek)
2503strong_alias(open, __open)
2504strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002505strong_alias(read, __read)
2506strong_alias(wait, __wait)
2507strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002508strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002509strong_alias(send, __send)
2510
sewardj726c4122002-05-16 23:39:10 +00002511weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002512weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002513weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002514
sewardj5905fae2002-04-26 13:25:00 +00002515
sewardj3b13f0e2002-04-25 20:17:29 +00002516
2517/*--------------------------------------------------*/
2518
sewardj5905fae2002-04-26 13:25:00 +00002519weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002520weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002521weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002522
sewardja1ac5cb2002-05-27 13:00:05 +00002523weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2524weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2525weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2526weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2527
sewardj060b04f2002-04-26 21:01:13 +00002528
sewardj3b13f0e2002-04-25 20:17:29 +00002529/* I've no idea what these are, but they get called quite a lot.
2530 Anybody know? */
2531
2532#undef _IO_flockfile
2533void _IO_flockfile ( _IO_FILE * file )
2534{
sewardj853f55d2002-04-26 00:27:53 +00002535 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002536}
sewardj5905fae2002-04-26 13:25:00 +00002537weak_alias(_IO_flockfile, flockfile);
2538
sewardj3b13f0e2002-04-25 20:17:29 +00002539
2540#undef _IO_funlockfile
2541void _IO_funlockfile ( _IO_FILE * file )
2542{
sewardj853f55d2002-04-26 00:27:53 +00002543 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002544}
sewardj5905fae2002-04-26 13:25:00 +00002545weak_alias(_IO_funlockfile, funlockfile);
2546
sewardj3b13f0e2002-04-25 20:17:29 +00002547
sewardjd4f2c712002-04-30 10:20:10 +00002548/* This doesn't seem to be needed to simulate libpthread.so's external
2549 interface, but many people complain about its absence. */
2550
2551strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2552weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002553
2554
2555/*--------------------------------------------------------------------*/
2556/*--- end vg_libpthread.c ---*/
2557/*--------------------------------------------------------------------*/