blob: 2cdc5ce98c3bccd0635abc0443bebcb9d9c58394 [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
sewardjccef2e62002-05-29 19:26:32 +0000174__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000175void vgPlain_unimp ( char* what )
176{
sewardj439d45e2002-05-03 20:43:10 +0000177 char* ig = "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ";
sewardj3b13f0e2002-04-25 20:17:29 +0000178 write(2, ig, strlen(ig));
179 write(2, what, strlen(what));
180 ig = "\n";
181 write(2, ig, strlen(ig));
182 barf("Please report this bug to me at: jseward@acm.org");
183}
184
sewardje663cb92002-04-12 10:26:32 +0000185
186/* ---------------------------------------------------------------------
187 Pass pthread_ calls to Valgrind's request mechanism.
188 ------------------------------------------------------------------ */
189
sewardjf8f819e2002-04-17 23:21:37 +0000190#include <stdio.h>
191#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000192#include <assert.h>
193#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000194
sewardja1ac5cb2002-05-27 13:00:05 +0000195
sewardjf8f819e2002-04-17 23:21:37 +0000196/* ---------------------------------------------------
197 THREAD ATTRIBUTES
198 ------------------------------------------------ */
199
sewardj6af4b5d2002-04-16 04:40:49 +0000200int pthread_attr_init(pthread_attr_t *attr)
201{
sewardj7989d0c2002-05-28 11:00:01 +0000202 /* Just initialise the fields which we might look at. */
203 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj6af4b5d2002-04-16 04:40:49 +0000204 return 0;
205}
206
207int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
208{
sewardj7989d0c2002-05-28 11:00:01 +0000209 if (detachstate != PTHREAD_CREATE_JOINABLE
210 && detachstate != PTHREAD_CREATE_DETACHED)
211 return EINVAL;
212 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000213 return 0;
214}
215
sewardj30671ff2002-04-21 00:13:57 +0000216int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
217{
sewardj436e0582002-04-26 14:31:40 +0000218 static int moans = N_MOANS;
219 if (moans-- > 0)
220 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000221 return 0;
222}
sewardj6af4b5d2002-04-16 04:40:49 +0000223
sewardj0286dd52002-05-16 20:51:15 +0000224__attribute__((weak))
225int pthread_attr_setstacksize (pthread_attr_t *__attr,
226 size_t __stacksize)
227{
sewardja18e2102002-05-18 10:43:22 +0000228 size_t limit;
sewardj0286dd52002-05-16 20:51:15 +0000229 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000230 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
231 - 1000; /* paranoia */
232 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000233 return 0;
234 barf("pthread_attr_setstacksize: "
235 "requested size >= VG_PTHREAD_STACK_SIZE\n "
236 "edit vg_include.h and rebuild.");
237}
238
239
sewardj30671ff2002-04-21 00:13:57 +0000240/* This is completely bogus. */
241int pthread_attr_getschedparam(const pthread_attr_t *attr,
242 struct sched_param *param)
243{
sewardj436e0582002-04-26 14:31:40 +0000244 static int moans = N_MOANS;
245 if (moans-- > 0)
246 kludged("pthread_attr_getschedparam");
sewardj72d58482002-04-24 02:20:20 +0000247# ifdef GLIBC_2_1
248 if (param) param->sched_priority = 0; /* who knows */
249# else
sewardj30671ff2002-04-21 00:13:57 +0000250 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000251# endif
sewardj30671ff2002-04-21 00:13:57 +0000252 return 0;
253}
254
255int pthread_attr_setschedparam(pthread_attr_t *attr,
256 const struct sched_param *param)
257{
sewardj436e0582002-04-26 14:31:40 +0000258 static int moans = N_MOANS;
259 if (moans-- > 0)
260 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000261 return 0;
262}
263
264int pthread_attr_destroy(pthread_attr_t *attr)
265{
sewardj436e0582002-04-26 14:31:40 +0000266 static int moans = N_MOANS;
267 if (moans-- > 0)
268 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000269 return 0;
270}
sewardjf8f819e2002-04-17 23:21:37 +0000271
sewardj20917d82002-05-28 01:36:45 +0000272/* ---------------------------------------------------
273 Helper functions for running a thread
274 and for clearing up afterwards.
275 ------------------------------------------------ */
276
277/* All exiting threads eventually pass through here, bearing the
278 return value, or PTHREAD_CANCELED, in ret_val. */
279static
280__attribute__((noreturn))
281void thread_exit_wrapper ( void* ret_val )
282{
sewardj870497a2002-05-29 01:06:47 +0000283 int detached, res;
284 CleanupEntry cu;
285 pthread_key_t key;
286
sewardj20917d82002-05-28 01:36:45 +0000287 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000288 while (1) {
289 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
290 VG_USERREQ__CLEANUP_POP,
291 &cu, 0, 0, 0);
292 if (res == -1) break; /* stack empty */
293 assert(res == 0);
294 if (0) printf("running exit cleanup handler");
295 cu.fn ( cu.arg );
296 }
297
sewardj870497a2002-05-29 01:06:47 +0000298 /* Run this thread's key finalizers. Really this should be run
299 PTHREAD_DESTRUCTOR_ITERATIONS times. */
300 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
301 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
302 VG_USERREQ__GET_KEY_D_AND_S,
303 key, &cu, 0, 0 );
304 if (res == 0) {
305 /* valid key */
306 if (cu.fn && cu.arg)
307 cu.fn /* destructor for key */
308 ( cu.arg /* specific for key for this thread */ );
309 continue;
310 }
311 assert(res == -1);
312 }
sewardj20917d82002-05-28 01:36:45 +0000313
314 /* Decide on my final disposition. */
315 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
316 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000317 2 /* get */, pthread_self(), 0, 0);
sewardj20917d82002-05-28 01:36:45 +0000318 assert(detached == 0 || detached == 1);
319
320 if (detached) {
321 /* Detached; I just quit right now. */
322 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
323 VG_USERREQ__QUIT, 0, 0, 0, 0);
324 } else {
325 /* Not detached; so I wait for a joiner. */
326 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
327 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
328 }
329 /* NOTREACHED */
330 barf("thread_exit_wrapper: still alive?!");
331}
332
333
334/* This function is a wrapper function for running a thread. It runs
335 the root function specified in pthread_create, and then, should the
336 root function return a value, it arranges to run the thread's
337 cleanup handlers and exit correctly. */
338
339/* Struct used to convey info from pthread_create to
340 thread_wrapper. */
341typedef
342 struct {
343 pthread_attr_t* attr;
344 void* (*root_fn) ( void* );
345 void* arg;
346 }
347 NewThreadInfo;
348
349
350/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
351 not return. Note that this runs in the new thread, not the
352 parent. */
353static
354__attribute__((noreturn))
355void thread_wrapper ( NewThreadInfo* info )
356{
357 int res;
358 pthread_attr_t* attr;
359 void* (*root_fn) ( void* );
360 void* arg;
361 void* ret_val;
362
363 attr = info->attr;
364 root_fn = info->root_fn;
365 arg = info->arg;
366
sewardj20917d82002-05-28 01:36:45 +0000367 /* Free up the arg block that pthread_create malloced. */
368 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
369 VG_USERREQ__FREE, info, 0, 0, 0);
370 assert(res == 0);
371
sewardj7989d0c2002-05-28 11:00:01 +0000372 /* Minimally observe the attributes supplied. */
373 if (attr) {
374 assert(attr->__detachstate == PTHREAD_CREATE_DETACHED
375 || attr->__detachstate == PTHREAD_CREATE_JOINABLE);
376 if (attr->__detachstate == PTHREAD_CREATE_DETACHED)
377 pthread_detach(pthread_self());
378 }
379
sewardj20917d82002-05-28 01:36:45 +0000380 /* The root function might not return. But if it does we simply
381 move along to thread_exit_wrapper. All other ways out for the
382 thread (cancellation, or calling pthread_exit) lead there
383 too. */
384 ret_val = root_fn(arg);
385 thread_exit_wrapper(ret_val);
386 /* NOTREACHED */
387}
388
389
sewardjf8f819e2002-04-17 23:21:37 +0000390/* ---------------------------------------------------
391 THREADs
392 ------------------------------------------------ */
393
sewardjff42d1d2002-05-22 13:17:31 +0000394__attribute__((weak))
395int pthread_yield ( void )
396{
397 int res;
398 ensure_valgrind("pthread_yield");
399 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
400 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
401 return 0;
402}
403
404
sewardj6072c362002-04-19 14:40:57 +0000405int pthread_equal(pthread_t thread1, pthread_t thread2)
406{
407 return thread1 == thread2 ? 1 : 0;
408}
409
410
sewardj20917d82002-05-28 01:36:45 +0000411/* Bundle up the args into a malloc'd block and create a new thread
412 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000413int
414pthread_create (pthread_t *__restrict __thread,
415 __const pthread_attr_t *__restrict __attr,
416 void *(*__start_routine) (void *),
417 void *__restrict __arg)
418{
sewardj20917d82002-05-28 01:36:45 +0000419 int tid_child;
420 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000421
sewardj20917d82002-05-28 01:36:45 +0000422 ensure_valgrind("pthread_create");
423
424 /* Allocate space for the arg block. thread_wrapper will free
425 it. */
426 VALGRIND_MAGIC_SEQUENCE(info, NULL /* default */,
427 VG_USERREQ__MALLOC,
428 sizeof(NewThreadInfo), 0, 0, 0);
429 assert(info != NULL);
430
431 info->attr = (pthread_attr_t*)__attr;
432 info->root_fn = __start_routine;
433 info->arg = __arg;
434 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
435 VG_USERREQ__APPLY_IN_NEW_THREAD,
436 &thread_wrapper, info, 0, 0);
437 assert(tid_child != VG_INVALID_THREADID);
438
439 if (__thread)
440 *__thread = tid_child;
441 return 0; /* success */
442}
sewardje663cb92002-04-12 10:26:32 +0000443
444
445int
446pthread_join (pthread_t __th, void **__thread_return)
447{
448 int res;
449 ensure_valgrind("pthread_join");
450 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
451 VG_USERREQ__PTHREAD_JOIN,
452 __th, __thread_return, 0, 0);
453 return res;
454}
455
456
sewardj3b5d8862002-04-20 13:53:23 +0000457void pthread_exit(void *retval)
458{
sewardj3b5d8862002-04-20 13:53:23 +0000459 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000460 /* Simple! */
461 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000462}
463
sewardje663cb92002-04-12 10:26:32 +0000464
sewardj3b13f0e2002-04-25 20:17:29 +0000465pthread_t pthread_self(void)
sewardje663cb92002-04-12 10:26:32 +0000466{
467 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000468 ensure_valgrind("pthread_self");
sewardj439d45e2002-05-03 20:43:10 +0000469 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardje663cb92002-04-12 10:26:32 +0000470 VG_USERREQ__PTHREAD_GET_THREADID,
471 0, 0, 0, 0);
sewardj439d45e2002-05-03 20:43:10 +0000472 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000473 barf("pthread_self: invalid ThreadId");
474 return tid;
sewardje663cb92002-04-12 10:26:32 +0000475}
476
477
sewardj853f55d2002-04-26 00:27:53 +0000478int pthread_detach(pthread_t th)
479{
sewardj20917d82002-05-28 01:36:45 +0000480 int res;
481 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000482 /* First we enquire as to the current detach state. */
483 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000484 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000485 2 /* get */, th, 0, 0);
486 if (res == -1) /* not found */
487 return ESRCH;
488 if (res == 1) /* already detached */
489 return EINVAL;
490 if (res == 0) {
491 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
492 VG_USERREQ__SET_OR_GET_DETACH,
493 1 /* set */, th, 0, 0);
494 assert(res == 0);
495 return 0;
496 }
497 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000498}
499
500
sewardjf8f819e2002-04-17 23:21:37 +0000501/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000502 CLEANUP STACKS
503 ------------------------------------------------ */
504
505void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
506 void (*__routine) (void *),
507 void *__arg)
508{
509 int res;
510 CleanupEntry cu;
511 ensure_valgrind("_pthread_cleanup_push");
512 cu.fn = __routine;
513 cu.arg = __arg;
514 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
515 VG_USERREQ__CLEANUP_PUSH,
516 &cu, 0, 0, 0);
517 assert(res == 0);
518}
519
520
521void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
522 void (*__routine) (void *),
523 void *__arg)
524{
525 /* As _pthread_cleanup_push, but first save the thread's original
526 cancellation type in __buffer and set it to Deferred. */
527 int orig_ctype;
528 ensure_valgrind("_pthread_cleanup_push_defer");
529 /* Set to Deferred, and put the old cancellation type in res. */
530 assert(-1 != PTHREAD_CANCEL_DEFERRED);
531 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
532 assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
533 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
534 VG_USERREQ__SET_CANCELTYPE,
535 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
536 assert(orig_ctype != -1);
537 *((int*)(__buffer)) = orig_ctype;
538 /* Now push the cleanup. */
539 _pthread_cleanup_push(NULL, __routine, __arg);
540}
541
542
543void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
544 int __execute)
545{
546 int res;
547 CleanupEntry cu;
548 ensure_valgrind("_pthread_cleanup_push");
549 cu.fn = cu.arg = NULL; /* paranoia */
550 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
551 VG_USERREQ__CLEANUP_POP,
552 &cu, 0, 0, 0);
553 if (res == 0) {
554 /* pop succeeded */
555 if (__execute) {
556 cu.fn ( cu.arg );
557 }
558 return;
559 }
560 if (res == -1) {
561 /* stack underflow */
562 return;
563 }
564 barf("_pthread_cleanup_pop");
565}
566
567
568void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
569 int __execute)
570{
571 int orig_ctype, fake_ctype;
572 /* As _pthread_cleanup_pop, but after popping/running the handler,
573 restore the thread's original cancellation type from the first
574 word of __buffer. */
575 _pthread_cleanup_pop(NULL, __execute);
576 orig_ctype = *((int*)(__buffer));
577 assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
578 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
579 assert(-1 != PTHREAD_CANCEL_DEFERRED);
580 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
581 assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
582 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
583 VG_USERREQ__SET_CANCELTYPE,
584 orig_ctype, 0, 0, 0);
585 assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
586}
587
588
589/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000590 MUTEX ATTRIBUTES
591 ------------------------------------------------ */
592
sewardj5905fae2002-04-26 13:25:00 +0000593int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000594{
sewardjf8f819e2002-04-17 23:21:37 +0000595 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000596 return 0;
sewardje663cb92002-04-12 10:26:32 +0000597}
598
sewardj5905fae2002-04-26 13:25:00 +0000599int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000600{
601 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000602# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000603 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000604 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000605# endif
sewardja1679dd2002-05-10 22:31:40 +0000606# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000607 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000608# endif
sewardjf8f819e2002-04-17 23:21:37 +0000609 case PTHREAD_MUTEX_RECURSIVE_NP:
610 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000611 attr->__mutexkind = type;
612 return 0;
613 default:
614 return EINVAL;
615 }
616}
617
sewardj5905fae2002-04-26 13:25:00 +0000618int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000619{
620 return 0;
621}
622
623
624/* ---------------------------------------------------
625 MUTEXes
626 ------------------------------------------------ */
627
sewardj5905fae2002-04-26 13:25:00 +0000628int __pthread_mutex_init(pthread_mutex_t *mutex,
629 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000630{
sewardj604ec3c2002-04-18 22:38:41 +0000631 mutex->__m_count = 0;
632 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
633 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
634 if (mutexattr)
635 mutex->__m_kind = mutexattr->__mutexkind;
636 return 0;
sewardje663cb92002-04-12 10:26:32 +0000637}
638
sewardj439d45e2002-05-03 20:43:10 +0000639
sewardj5905fae2002-04-26 13:25:00 +0000640int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +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) {
sewardje663cb92002-04-12 10:26:32 +0000645 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
646 VG_USERREQ__PTHREAD_MUTEX_LOCK,
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_lock");
652 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000653 }
654}
655
sewardj439d45e2002-05-03 20:43:10 +0000656
sewardj5905fae2002-04-26 13:25:00 +0000657int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +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) {
sewardj30671ff2002-04-21 00:13:57 +0000662 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
663 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
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_trylock");
669 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000670 }
671}
672
sewardj439d45e2002-05-03 20:43:10 +0000673
sewardj5905fae2002-04-26 13:25:00 +0000674int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000675{
676 int res;
sewardj436e0582002-04-26 14:31:40 +0000677 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000678 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000679 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
680 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
681 mutex, 0, 0, 0);
682 return res;
sewardj439d45e2002-05-03 20:43:10 +0000683 } else {
684 if (moans-- > 0)
685 not_inside("pthread_mutex_unlock");
686 return 0;
sewardje663cb92002-04-12 10:26:32 +0000687 }
688}
689
sewardj439d45e2002-05-03 20:43:10 +0000690
sewardj5905fae2002-04-26 13:25:00 +0000691int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000692{
sewardj604ec3c2002-04-18 22:38:41 +0000693 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
694 need to involve it. */
695 if (mutex->__m_count > 0)
696 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000697 mutex->__m_count = 0;
698 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
699 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000700 return 0;
sewardje663cb92002-04-12 10:26:32 +0000701}
702
703
sewardjf8f819e2002-04-17 23:21:37 +0000704/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000705 CONDITION VARIABLES
706 ------------------------------------------------ */
707
708/* LinuxThreads supports no attributes for conditions. Hence ... */
709
710int pthread_condattr_init(pthread_condattr_t *attr)
711{
712 return 0;
713}
714
sewardj0738a592002-04-20 13:59:33 +0000715int pthread_condattr_destroy(pthread_condattr_t *attr)
716{
717 return 0;
718}
sewardj6072c362002-04-19 14:40:57 +0000719
720int pthread_cond_init( pthread_cond_t *cond,
721 const pthread_condattr_t *cond_attr)
722{
723 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
724 return 0;
725}
726
sewardjf854f472002-04-21 12:19:41 +0000727int pthread_cond_destroy(pthread_cond_t *cond)
728{
729 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000730 static int moans = N_MOANS;
731 if (moans-- > 0)
732 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000733 return 0;
734}
sewardj6072c362002-04-19 14:40:57 +0000735
736/* ---------------------------------------------------
737 SCHEDULING
738 ------------------------------------------------ */
739
740/* This is completely bogus. */
741int pthread_getschedparam(pthread_t target_thread,
742 int *policy,
743 struct sched_param *param)
744{
sewardj436e0582002-04-26 14:31:40 +0000745 static int moans = N_MOANS;
746 if (moans-- > 0)
747 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000748 if (policy) *policy = SCHED_OTHER;
sewardj2a1dcce2002-04-22 12:45:25 +0000749# ifdef GLIBC_2_1
750 if (param) param->sched_priority = 0; /* who knows */
751# else
sewardj6072c362002-04-19 14:40:57 +0000752 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000753# endif
sewardj6072c362002-04-19 14:40:57 +0000754 return 0;
755}
756
757int pthread_setschedparam(pthread_t target_thread,
758 int policy,
759 const struct sched_param *param)
760{
sewardj436e0582002-04-26 14:31:40 +0000761 static int moans = N_MOANS;
762 if (moans-- > 0)
763 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000764 return 0;
765}
766
sewardj3b5d8862002-04-20 13:53:23 +0000767int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
768{
769 int res;
770 ensure_valgrind("pthread_cond_wait");
771 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
772 VG_USERREQ__PTHREAD_COND_WAIT,
773 cond, mutex, 0, 0);
774 return res;
775}
776
sewardj5f07b662002-04-23 16:52:51 +0000777int pthread_cond_timedwait ( pthread_cond_t *cond,
778 pthread_mutex_t *mutex,
779 const struct timespec *abstime )
780{
781 int res;
782 unsigned int ms_now, ms_end;
783 struct timeval timeval_now;
784 unsigned long long int ull_ms_now_after_1970;
785 unsigned long long int ull_ms_end_after_1970;
786
787 ensure_valgrind("pthread_cond_timedwait");
788 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
789 VG_USERREQ__READ_MILLISECOND_TIMER,
790 0, 0, 0, 0);
791 assert(ms_now != 0xFFFFFFFF);
792 res = gettimeofday(&timeval_now, NULL);
793 assert(res == 0);
794
795 ull_ms_now_after_1970
796 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
797 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
798 ull_ms_end_after_1970
799 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
800 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +0000801 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
802 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +0000803 ms_end
804 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
805 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
806 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
807 cond, mutex, ms_end, 0);
808 return res;
809}
810
811
sewardj3b5d8862002-04-20 13:53:23 +0000812int pthread_cond_signal(pthread_cond_t *cond)
813{
814 int res;
815 ensure_valgrind("pthread_cond_signal");
816 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
817 VG_USERREQ__PTHREAD_COND_SIGNAL,
818 cond, 0, 0, 0);
819 return res;
820}
821
822int pthread_cond_broadcast(pthread_cond_t *cond)
823{
824 int res;
825 ensure_valgrind("pthread_cond_broadcast");
826 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
827 VG_USERREQ__PTHREAD_COND_BROADCAST,
828 cond, 0, 0, 0);
829 return res;
830}
831
sewardj6072c362002-04-19 14:40:57 +0000832
833/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000834 CANCELLATION
835 ------------------------------------------------ */
836
sewardj853f55d2002-04-26 00:27:53 +0000837int pthread_setcancelstate(int state, int *oldstate)
838{
sewardj20917d82002-05-28 01:36:45 +0000839 int res;
840 ensure_valgrind("pthread_setcancelstate");
841 if (state != PTHREAD_CANCEL_ENABLE
842 && state != PTHREAD_CANCEL_DISABLE)
843 return EINVAL;
844 assert(-1 != PTHREAD_CANCEL_ENABLE);
845 assert(-1 != PTHREAD_CANCEL_DISABLE);
846 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
847 VG_USERREQ__SET_CANCELSTATE,
848 state, 0, 0, 0);
849 assert(res != -1);
850 if (oldstate)
851 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +0000852 return 0;
853}
854
sewardje663cb92002-04-12 10:26:32 +0000855int pthread_setcanceltype(int type, int *oldtype)
856{
sewardj20917d82002-05-28 01:36:45 +0000857 int res;
858 ensure_valgrind("pthread_setcanceltype");
859 if (type != PTHREAD_CANCEL_DEFERRED
860 && type != PTHREAD_CANCEL_ASYNCHRONOUS)
861 return EINVAL;
862 assert(-1 != PTHREAD_CANCEL_DEFERRED);
863 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
864 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
865 VG_USERREQ__SET_CANCELTYPE,
866 type, 0, 0, 0);
867 assert(res != -1);
868 if (oldtype)
869 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +0000870 return 0;
871}
872
sewardje663cb92002-04-12 10:26:32 +0000873int pthread_cancel(pthread_t thread)
874{
875 int res;
876 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +0000877 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
878 VG_USERREQ__SET_CANCELPEND,
879 thread, &thread_exit_wrapper, 0, 0);
880 assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +0000881 return res;
882}
883
sewardjd140e442002-05-29 01:21:19 +0000884static __inline__
885void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +0000886{
sewardj20917d82002-05-28 01:36:45 +0000887 int res;
888 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
889 VG_USERREQ__TESTCANCEL,
890 0, 0, 0, 0);
891 assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +0000892}
893
sewardjd140e442002-05-29 01:21:19 +0000894void pthread_testcancel ( void )
895{
896 __my_pthread_testcancel();
897}
898
sewardj20917d82002-05-28 01:36:45 +0000899
sewardj853f55d2002-04-26 00:27:53 +0000900/*-------------------*/
sewardjccef2e62002-05-29 19:26:32 +0000901/* If this is indeed used by LinuxThreads to implement thread nuking
902 post fork and pre exec, we should really nuke em, not do
903 pthread_cancel. */
sewardj853f55d2002-04-26 00:27:53 +0000904static pthread_mutex_t massacre_mx = PTHREAD_MUTEX_INITIALIZER;
905
906void __pthread_kill_other_threads_np ( void )
907{
908 int i, res, me;
sewardj68b2dd92002-05-10 21:03:56 +0000909 __pthread_mutex_lock(&massacre_mx);
sewardj853f55d2002-04-26 00:27:53 +0000910 me = pthread_self();
911 for (i = 1; i < VG_N_THREADS; i++) {
912 if (i == me) continue;
913 res = pthread_cancel(i);
sewardj436e0582002-04-26 14:31:40 +0000914 if (0 && res == 0)
sewardj853f55d2002-04-26 00:27:53 +0000915 printf("----------- NUKED %d\n", i);
916 }
sewardj68b2dd92002-05-10 21:03:56 +0000917 __pthread_mutex_unlock(&massacre_mx);
sewardj853f55d2002-04-26 00:27:53 +0000918}
919
sewardje663cb92002-04-12 10:26:32 +0000920
sewardjf8f819e2002-04-17 23:21:37 +0000921/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +0000922 SIGNALS
923 ------------------------------------------------ */
924
925#include <signal.h>
926
927int pthread_sigmask(int how, const sigset_t *newmask,
928 sigset_t *oldmask)
929{
930 int res;
931
932 /* A bit subtle, because the scheduler expects newmask and oldmask
933 to be vki_sigset_t* rather than sigset_t*, and the two are
934 different. Fortunately the first 64 bits of a sigset_t are
935 exactly a vki_sigset_t, so we just pass the pointers through
936 unmodified. Haaaack!
937
938 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +0000939 constants to VKI_ constants, so that the former do not have to
940 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +0000941
942 ensure_valgrind("pthread_sigmask");
943
944 switch (how) {
sewardj018f7622002-05-15 21:13:39 +0000945 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
946 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
947 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardjb48e5002002-05-13 00:16:03 +0000948 default: return EINVAL;
949 }
950
951 /* Crude check */
952 if (newmask == NULL)
953 return EFAULT;
954
955 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
956 VG_USERREQ__PTHREAD_SIGMASK,
957 how, newmask, oldmask, 0);
958
959 /* The scheduler tells us of any memory violations. */
960 return res == 0 ? 0 : EFAULT;
961}
962
963
964int sigwait ( const sigset_t* set, int* sig )
965{
966 int res;
967 ensure_valgrind("sigwait");
968 /* As with pthread_sigmask we deliberately confuse sigset_t with
969 vki_ksigset_t. */
970 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
971 VG_USERREQ__SIGWAIT,
972 set, sig, 0, 0);
973 return res;
974}
975
976
sewardj018f7622002-05-15 21:13:39 +0000977int pthread_kill(pthread_t thread, int signo)
978{
979 int res;
980 ensure_valgrind("pthread_kill");
981 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
982 VG_USERREQ__PTHREAD_KILL,
983 thread, signo, 0, 0);
984 return res;
985}
986
987
sewardj3665ded2002-05-16 16:57:25 +0000988/* Copied verbatim from Linuxthreads */
989/* Redefine raise() to send signal to calling thread only,
990 as per POSIX 1003.1c */
991int raise (int sig)
992{
993 int retcode = pthread_kill(pthread_self(), sig);
994 if (retcode == 0)
995 return 0;
996 else {
997 errno = retcode;
998 return -1;
999 }
1000}
1001
1002
sewardjb48e5002002-05-13 00:16:03 +00001003/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001004 THREAD-SPECIFICs
1005 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001006
sewardj5905fae2002-04-26 13:25:00 +00001007int __pthread_key_create(pthread_key_t *key,
1008 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001009{
sewardj5f07b662002-04-23 16:52:51 +00001010 int res;
1011 ensure_valgrind("pthread_key_create");
1012 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1013 VG_USERREQ__PTHREAD_KEY_CREATE,
1014 key, destr_function, 0, 0);
1015 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001016}
1017
1018int pthread_key_delete(pthread_key_t key)
1019{
sewardj436e0582002-04-26 14:31:40 +00001020 static int moans = N_MOANS;
1021 if (moans-- > 0)
1022 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +00001023 return 0;
1024}
1025
sewardj5905fae2002-04-26 13:25:00 +00001026int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001027{
sewardj5f07b662002-04-23 16:52:51 +00001028 int res;
1029 ensure_valgrind("pthread_setspecific");
1030 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1031 VG_USERREQ__PTHREAD_SETSPECIFIC,
1032 key, pointer, 0, 0);
1033 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001034}
1035
sewardj5905fae2002-04-26 13:25:00 +00001036void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001037{
sewardj5f07b662002-04-23 16:52:51 +00001038 int res;
1039 ensure_valgrind("pthread_getspecific");
1040 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1041 VG_USERREQ__PTHREAD_GETSPECIFIC,
1042 key, 0 , 0, 0);
1043 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001044}
1045
sewardjf8f819e2002-04-17 23:21:37 +00001046
1047/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001048 ONCEry
1049 ------------------------------------------------ */
1050
1051static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1052
1053
sewardj5905fae2002-04-26 13:25:00 +00001054int __pthread_once ( pthread_once_t *once_control,
1055 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001056{
1057 int res;
1058 ensure_valgrind("pthread_once");
1059
sewardj68b2dd92002-05-10 21:03:56 +00001060 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001061
sewardj68b2dd92002-05-10 21:03:56 +00001062 if (res != 0) {
1063 printf("res = %d\n",res);
sewardj89d3d852002-04-24 19:21:39 +00001064 barf("pthread_once: Looks like your program's "
1065 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001066 }
sewardj89d3d852002-04-24 19:21:39 +00001067
1068 if (*once_control == 0) {
1069 *once_control = 1;
1070 init_routine();
1071 }
1072
sewardj68b2dd92002-05-10 21:03:56 +00001073 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001074
1075 return 0;
1076}
1077
1078
1079/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001080 MISC
1081 ------------------------------------------------ */
1082
sewardj5905fae2002-04-26 13:25:00 +00001083int __pthread_atfork ( void (*prepare)(void),
1084 void (*parent)(void),
1085 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001086{
sewardjccef2e62002-05-29 19:26:32 +00001087 /* We have to do this properly or not at all; faking it isn't an
1088 option. */
1089 vgPlain_unimp("__pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +00001090}
1091
1092
sewardjbb990782002-05-08 02:01:14 +00001093__attribute__((weak))
1094void __pthread_initialize ( void )
1095{
sewardjbea1caa2002-05-10 23:20:58 +00001096 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001097}
1098
1099
sewardj853f55d2002-04-26 00:27:53 +00001100/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001101 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001102 ------------------------------------------------ */
1103
sewardj3b13f0e2002-04-25 20:17:29 +00001104#include <resolv.h>
1105static int thread_specific_errno[VG_N_THREADS];
1106static int thread_specific_h_errno[VG_N_THREADS];
1107static struct __res_state
1108 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001109
sewardj3b13f0e2002-04-25 20:17:29 +00001110int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001111{
1112 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001113 /* ensure_valgrind("__errno_location"); */
1114 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001115 VG_USERREQ__PTHREAD_GET_THREADID,
1116 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001117 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001118 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001119 barf("__errno_location: invalid ThreadId");
1120 return & thread_specific_errno[tid];
1121}
1122
1123int* __h_errno_location ( void )
1124{
1125 int tid;
1126 /* ensure_valgrind("__h_errno_location"); */
1127 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1128 VG_USERREQ__PTHREAD_GET_THREADID,
1129 0, 0, 0, 0);
1130 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001131 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001132 barf("__h_errno_location: invalid ThreadId");
1133 return & thread_specific_h_errno[tid];
1134}
1135
1136struct __res_state* __res_state ( void )
1137{
1138 int tid;
1139 /* ensure_valgrind("__res_state"); */
1140 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1141 VG_USERREQ__PTHREAD_GET_THREADID,
1142 0, 0, 0, 0);
1143 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001144 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001145 barf("__res_state: invalid ThreadId");
1146 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001147}
1148
1149
sewardj5716dbb2002-04-26 03:28:18 +00001150/* ---------------------------------------------------
1151 LIBC-PRIVATE SPECIFIC DATA
1152 ------------------------------------------------ */
1153
1154/* Relies on assumption that initial private data is NULL. This
1155 should be fixed somehow. */
1156
1157/* The allowable keys (indices) (all 2 of them).
1158 From sysdeps/pthread/bits/libc-tsd.h
1159*/
sewardj70adeb22002-04-27 01:35:38 +00001160#define N_LIBC_TSD_EXTRA_KEYS 1
1161
sewardj5716dbb2002-04-26 03:28:18 +00001162enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1163 _LIBC_TSD_KEY_DL_ERROR,
1164 _LIBC_TSD_KEY_N };
1165
1166/* Auto-initialising subsystem. libc_specifics_inited is set
1167 after initialisation. libc_specifics_inited_mx guards it. */
1168static int libc_specifics_inited = 0;
1169static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1170
1171/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001172static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1173 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001174
1175/* Initialise the keys, if they are not already initialise. */
1176static
1177void init_libc_tsd_keys ( void )
1178{
1179 int res, i;
1180 pthread_key_t k;
1181
1182 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1183 if (res != 0) barf("init_libc_tsd_keys: lock");
1184
1185 if (libc_specifics_inited == 0) {
1186 /* printf("INIT libc specifics\n"); */
1187 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001188 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001189 res = pthread_key_create(&k, NULL);
1190 if (res != 0) barf("init_libc_tsd_keys: create");
1191 libc_specifics_keys[i] = k;
1192 }
1193 }
1194
1195 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1196 if (res != 0) barf("init_libc_tsd_keys: unlock");
1197}
1198
1199
1200static int
1201libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1202 const void * pointer )
1203{
sewardj70adeb22002-04-27 01:35:38 +00001204 int res;
1205 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001206 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001207 if (key < _LIBC_TSD_KEY_MALLOC
1208 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001209 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001210 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1211 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001212 "valgrind's libpthread.so: libc_internal_tsd_set: "
1213 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001214 init_libc_tsd_keys();
1215 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1216 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1217 return 0;
1218}
1219
1220static void *
1221libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1222{
sewardj70adeb22002-04-27 01:35:38 +00001223 void* v;
1224 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001225 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001226 if (key < _LIBC_TSD_KEY_MALLOC
1227 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001228 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001229 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1230 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001231 "valgrind's libpthread.so: libc_internal_tsd_get: "
1232 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001233 init_libc_tsd_keys();
1234 v = pthread_getspecific(libc_specifics_keys[key]);
1235 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1236 return v;
1237}
1238
1239
1240
1241
sewardj70adeb22002-04-27 01:35:38 +00001242int (*__libc_internal_tsd_set)
1243 (enum __libc_tsd_key_t key, const void * pointer)
1244 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001245
sewardj70adeb22002-04-27 01:35:38 +00001246void* (*__libc_internal_tsd_get)
1247 (enum __libc_tsd_key_t key)
1248 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001249
1250
sewardje663cb92002-04-12 10:26:32 +00001251/* ---------------------------------------------------------------------
1252 These are here (I think) because they are deemed cancellation
1253 points by POSIX. For the moment we'll simply pass the call along
1254 to the corresponding thread-unaware (?) libc routine.
1255 ------------------------------------------------------------------ */
1256
sewardje663cb92002-04-12 10:26:32 +00001257#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001258#include <sys/types.h>
1259#include <sys/socket.h>
1260
sewardjd529a442002-05-04 19:49:21 +00001261#ifdef GLIBC_2_1
1262extern
1263int __sigaction
1264 (int signum,
1265 const struct sigaction *act,
1266 struct sigaction *oldact);
1267#else
sewardje663cb92002-04-12 10:26:32 +00001268extern
1269int __libc_sigaction
1270 (int signum,
1271 const struct sigaction *act,
1272 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001273#endif
sewardje663cb92002-04-12 10:26:32 +00001274int sigaction(int signum,
1275 const struct sigaction *act,
1276 struct sigaction *oldact)
1277{
sewardjd140e442002-05-29 01:21:19 +00001278 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001279# ifdef GLIBC_2_1
1280 return __sigaction(signum, act, oldact);
1281# else
sewardj45b4b372002-04-16 22:50:32 +00001282 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001283# endif
sewardje663cb92002-04-12 10:26:32 +00001284}
1285
1286
1287extern
1288int __libc_connect(int sockfd,
1289 const struct sockaddr *serv_addr,
1290 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001291__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001292int connect(int sockfd,
1293 const struct sockaddr *serv_addr,
1294 socklen_t addrlen)
1295{
sewardjd140e442002-05-29 01:21:19 +00001296 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001297 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001298}
1299
1300
1301extern
1302int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001303__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001304int fcntl(int fd, int cmd, long arg)
1305{
sewardjd140e442002-05-29 01:21:19 +00001306 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001307 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001308}
1309
1310
1311extern
1312ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001313__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001314ssize_t write(int fd, const void *buf, size_t count)
1315{
sewardjd140e442002-05-29 01:21:19 +00001316 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001317 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001318}
1319
1320
1321extern
1322ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001323__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001324ssize_t read(int fd, void *buf, size_t count)
1325{
sewardjd140e442002-05-29 01:21:19 +00001326 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001327 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001328}
1329
sewardjbe32e452002-04-24 20:29:58 +00001330
1331extern
sewardj853f55d2002-04-26 00:27:53 +00001332int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001333__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001334int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001335{
sewardjd140e442002-05-29 01:21:19 +00001336 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001337 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001338}
1339
sewardje663cb92002-04-12 10:26:32 +00001340
1341extern
sewardj853f55d2002-04-26 00:27:53 +00001342int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001343__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001344int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001345{
sewardjd140e442002-05-29 01:21:19 +00001346 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001347 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001348}
1349
1350
1351extern
1352int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001353__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001354int close(int fd)
1355{
sewardjd140e442002-05-29 01:21:19 +00001356 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001357 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001358}
1359
1360
1361extern
1362int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001363__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001364int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1365{
sewardjd140e442002-05-29 01:21:19 +00001366 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001367 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001368 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001369 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001370}
1371
1372
1373extern
1374pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001375pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001376{
sewardjd140e442002-05-29 01:21:19 +00001377 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001378 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001379}
1380
1381
1382extern
1383pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001384__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001385pid_t waitpid(pid_t pid, int *status, int options)
1386{
sewardjd140e442002-05-29 01:21:19 +00001387 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001388 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001389}
1390
1391
1392extern
1393int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001394__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001395int nanosleep(const struct timespec *req, struct timespec *rem)
1396{
sewardjd140e442002-05-29 01:21:19 +00001397 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001398 return __libc_nanosleep(req, rem);
1399}
1400
sewardjbe32e452002-04-24 20:29:58 +00001401
sewardje663cb92002-04-12 10:26:32 +00001402extern
1403int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001404__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001405int fsync(int fd)
1406{
sewardjd140e442002-05-29 01:21:19 +00001407 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001408 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001409}
1410
sewardjbe32e452002-04-24 20:29:58 +00001411
sewardj70c75362002-04-13 04:18:32 +00001412extern
1413off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001414__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001415off_t lseek(int fildes, off_t offset, int whence)
1416{
sewardjd140e442002-05-29 01:21:19 +00001417 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001418 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001419}
1420
sewardjbe32e452002-04-24 20:29:58 +00001421
1422extern
1423__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001424__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001425__off64_t lseek64(int fildes, __off64_t offset, int whence)
1426{
sewardjd140e442002-05-29 01:21:19 +00001427 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001428 return __libc_lseek64(fildes, offset, whence);
1429}
1430
1431
sewardj726c4122002-05-16 23:39:10 +00001432extern
1433ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1434 __off64_t __offset);
1435ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1436 __off64_t __offset)
1437{
sewardjd140e442002-05-29 01:21:19 +00001438 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001439 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1440}
1441
1442
sewardja18e2102002-05-18 10:43:22 +00001443extern
1444ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1445 __off64_t __offset);
1446ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1447 __off64_t __offset)
1448{
sewardjd140e442002-05-29 01:21:19 +00001449 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001450 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1451}
1452
sewardj726c4122002-05-16 23:39:10 +00001453
sewardj39b93b12002-05-18 10:56:27 +00001454extern
1455ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1456__attribute__((weak))
1457ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1458{
sewardjd140e442002-05-29 01:21:19 +00001459 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001460 return __libc_pwrite(fd, buf, count, offset);
1461}
1462
1463
1464extern
1465ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1466__attribute__((weak))
1467ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1468{
sewardjd140e442002-05-29 01:21:19 +00001469 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001470 return __libc_pread(fd, buf, count, offset);
1471}
1472
1473
sewardj6af4b5d2002-04-16 04:40:49 +00001474extern
1475void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001476/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001477void longjmp(jmp_buf env, int val)
1478{
sewardjd140e442002-05-29 01:21:19 +00001479 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001480 __libc_longjmp(env, val);
1481}
1482
sewardjbe32e452002-04-24 20:29:58 +00001483
sewardj6af4b5d2002-04-16 04:40:49 +00001484extern
1485int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001486__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001487int send(int s, const void *msg, size_t len, int flags)
1488{
sewardjd140e442002-05-29 01:21:19 +00001489 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001490 return __libc_send(s, msg, len, flags);
1491}
1492
sewardjbe32e452002-04-24 20:29:58 +00001493
sewardj1e8cdc92002-04-18 11:37:52 +00001494extern
1495int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001496__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001497int recv(int s, void *buf, size_t len, int flags)
1498{
sewardjd140e442002-05-29 01:21:19 +00001499 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001500 return __libc_recv(s, buf, len, flags);
1501}
1502
sewardjbe32e452002-04-24 20:29:58 +00001503
sewardj3665ded2002-05-16 16:57:25 +00001504extern
1505int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1506__attribute__((weak))
1507int sendmsg(int s, const struct msghdr *msg, int flags)
1508{
sewardjd140e442002-05-29 01:21:19 +00001509 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001510 return __libc_sendmsg(s, msg, flags);
1511}
1512
1513
sewardj796d6a22002-04-24 02:28:34 +00001514extern
sewardj436e0582002-04-26 14:31:40 +00001515int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1516 struct sockaddr *from, socklen_t *fromlen);
1517__attribute__((weak))
1518int recvfrom(int s, void *buf, size_t len, int flags,
1519 struct sockaddr *from, socklen_t *fromlen)
1520{
sewardjd140e442002-05-29 01:21:19 +00001521 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001522 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1523}
1524
1525
1526extern
sewardj796d6a22002-04-24 02:28:34 +00001527int __libc_sendto(int s, const void *msg, size_t len, int flags,
1528 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001529__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001530int sendto(int s, const void *msg, size_t len, int flags,
1531 const struct sockaddr *to, socklen_t tolen)
1532{
sewardjd140e442002-05-29 01:21:19 +00001533 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001534 return __libc_sendto(s, msg, len, flags, to, tolen);
1535}
1536
sewardjbe32e452002-04-24 20:29:58 +00001537
sewardj369b1702002-04-24 13:28:15 +00001538extern
1539int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001540__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001541int system(const char* str)
1542{
sewardjd140e442002-05-29 01:21:19 +00001543 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001544 return __libc_system(str);
1545}
1546
sewardjbe32e452002-04-24 20:29:58 +00001547
sewardjab0b1c32002-04-24 19:26:47 +00001548extern
1549pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001550__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001551pid_t wait(int *status)
1552{
sewardjd140e442002-05-29 01:21:19 +00001553 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00001554 return __libc_wait(status);
1555}
1556
sewardj45b4b372002-04-16 22:50:32 +00001557
sewardj67f1d582002-05-24 02:11:32 +00001558extern
1559int __libc_msync(const void *start, size_t length, int flags);
1560__attribute__((weak))
1561int msync(const void *start, size_t length, int flags)
1562{
sewardjd140e442002-05-29 01:21:19 +00001563 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00001564 return __libc_msync(start, length, flags);
1565}
1566
sewardj5905fae2002-04-26 13:25:00 +00001567
sewardj3b13f0e2002-04-25 20:17:29 +00001568/* ---------------------------------------------------------------------
1569 Nonblocking implementations of select() and poll(). This stuff will
1570 surely rot your mind.
1571 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001572
sewardj08a4c3f2002-04-13 03:45:44 +00001573/*--------------------------------------------------*/
1574
1575#include "vg_kerneliface.h"
1576
1577static
1578__inline__
1579int is_kerror ( int res )
1580{
1581 if (res >= -4095 && res <= -1)
1582 return 1;
1583 else
1584 return 0;
1585}
1586
1587
1588static
1589int my_do_syscall1 ( int syscallno, int arg1 )
1590{
1591 int __res;
1592 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1593 : "=a" (__res)
1594 : "0" (syscallno),
1595 "d" (arg1) );
1596 return __res;
1597}
1598
1599static
1600int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001601 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001602{
1603 int __res;
1604 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1605 : "=a" (__res)
1606 : "0" (syscallno),
1607 "d" (arg1),
1608 "c" (arg2) );
1609 return __res;
1610}
1611
1612static
sewardjf854f472002-04-21 12:19:41 +00001613int my_do_syscall3 ( int syscallno,
1614 int arg1, int arg2, int arg3 )
1615{
1616 int __res;
1617 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1618 : "=a" (__res)
1619 : "0" (syscallno),
1620 "S" (arg1),
1621 "c" (arg2),
1622 "d" (arg3) );
1623 return __res;
1624}
1625
1626static
sewardj08a4c3f2002-04-13 03:45:44 +00001627int do_syscall_select( int n,
1628 vki_fd_set* readfds,
1629 vki_fd_set* writefds,
1630 vki_fd_set* exceptfds,
1631 struct vki_timeval * timeout )
1632{
1633 int res;
1634 int args[5];
1635 args[0] = n;
1636 args[1] = (int)readfds;
1637 args[2] = (int)writefds;
1638 args[3] = (int)exceptfds;
1639 args[4] = (int)timeout;
1640 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001641 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001642}
1643
1644
1645/* This is a wrapper round select(), which makes it thread-safe,
1646 meaning that only this thread will block, rather than the entire
1647 process. This wrapper in turn depends on nanosleep() not to block
1648 the entire process, but I think (hope? suspect?) that POSIX
1649 pthreads guarantees that to be the case.
1650
1651 Basic idea is: modify the timeout parameter to select so that it
1652 returns immediately. Poll like this until select returns non-zero,
1653 indicating something interesting happened, or until our time is up.
1654 Space out the polls with nanosleeps of say 20 milliseconds, which
1655 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001656
1657 Assumes:
1658 * (checked via assert) types fd_set and vki_fd_set are identical.
1659 * (checked via assert) types timeval and vki_timeval are identical.
1660 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1661 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001662*/
sewardj08a4c3f2002-04-13 03:45:44 +00001663
sewardj5905fae2002-04-26 13:25:00 +00001664/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001665int select ( int n,
1666 fd_set *rfds,
1667 fd_set *wfds,
1668 fd_set *xfds,
1669 struct timeval *timeout )
1670{
sewardj5f07b662002-04-23 16:52:51 +00001671 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001672 int res;
1673 fd_set rfds_copy;
1674 fd_set wfds_copy;
1675 fd_set xfds_copy;
1676 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001677 struct vki_timeval zero_timeout;
1678 struct vki_timespec nanosleep_interval;
1679
sewardjd140e442002-05-29 01:21:19 +00001680 __my_pthread_testcancel();
1681
sewardj5f07b662002-04-23 16:52:51 +00001682 /* gcc's complains about ms_end being used uninitialised -- classic
1683 case it can't understand, where ms_end is both defined and used
1684 only if timeout != NULL. Hence ... */
1685 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001686
1687 /* We assume that the kernel and libc data layouts are identical
1688 for the following types. These asserts provide a crude
1689 check. */
1690 if (sizeof(fd_set) != sizeof(vki_fd_set)
1691 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1692 barf("valgrind's hacky non-blocking select(): data sizes error");
1693
sewardj5f07b662002-04-23 16:52:51 +00001694 /* Detect the current time and simultaneously find out if we are
1695 running on Valgrind. */
1696 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1697 VG_USERREQ__READ_MILLISECOND_TIMER,
1698 0, 0, 0, 0);
1699
1700 /* If a zero timeout specified, this call is harmless. Also go
1701 this route if we're not running on Valgrind, for whatever
1702 reason. */
1703 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1704 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001705 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001706 (vki_fd_set*)wfds,
1707 (vki_fd_set*)xfds,
1708 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001709 if (is_kerror(res)) {
1710 * (__errno_location()) = -res;
1711 return -1;
1712 } else {
1713 return res;
1714 }
1715 }
sewardj08a4c3f2002-04-13 03:45:44 +00001716
sewardj5f07b662002-04-23 16:52:51 +00001717 /* If a timeout was specified, set ms_end to be the end millisecond
1718 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001719 if (timeout) {
1720 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
1721 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001722 ms_end = ms_now;
1723 ms_end += (timeout->tv_usec / 1000);
1724 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001725 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +00001726 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001727 }
1728
1729 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1730
1731 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001732 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001733 while (1) {
1734 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +00001735 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1736 VG_USERREQ__READ_MILLISECOND_TIMER,
1737 0, 0, 0, 0);
1738 assert(ms_now != 0xFFFFFFFF);
1739 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +00001740 /* timeout; nothing interesting happened. */
1741 if (rfds) FD_ZERO(rfds);
1742 if (wfds) FD_ZERO(wfds);
1743 if (xfds) FD_ZERO(xfds);
1744 return 0;
1745 }
1746 }
1747
1748 /* These could be trashed each time round the loop, so restore
1749 them each time. */
1750 if (rfds) rfds_copy = *rfds;
1751 if (wfds) wfds_copy = *wfds;
1752 if (xfds) xfds_copy = *xfds;
1753
1754 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1755
1756 res = do_syscall_select( n,
1757 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1758 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1759 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1760 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001761 if (is_kerror(res)) {
1762 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001763 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001764 * (__errno_location()) = -res;
1765 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001766 }
1767 if (res > 0) {
1768 /* one or more fds is ready. Copy out resulting sets and
1769 return. */
1770 if (rfds) *rfds = rfds_copy;
1771 if (wfds) *wfds = wfds_copy;
1772 if (xfds) *xfds = xfds_copy;
1773 return res;
1774 }
1775 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1776 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001777 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001778 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001779 /* It's critical here that valgrind's nanosleep implementation
1780 is nonblocking. */
1781 (void)my_do_syscall2(__NR_nanosleep,
1782 (int)(&nanosleep_interval), (int)NULL);
1783 }
1784}
1785
1786
1787
1788
1789#include <sys/poll.h>
1790
sewardj72d58482002-04-24 02:20:20 +00001791#ifdef GLIBC_2_1
1792typedef unsigned long int nfds_t;
1793#endif
1794
sewardj705d3cb2002-05-23 13:13:12 +00001795
sewardj5905fae2002-04-26 13:25:00 +00001796/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00001797int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1798{
sewardj5f07b662002-04-23 16:52:51 +00001799 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001800 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001801 struct vki_timespec nanosleep_interval;
1802
sewardjd140e442002-05-29 01:21:19 +00001803 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00001804 ensure_valgrind("poll");
1805
sewardj5f07b662002-04-23 16:52:51 +00001806 /* Detect the current time and simultaneously find out if we are
1807 running on Valgrind. */
1808 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1809 VG_USERREQ__READ_MILLISECOND_TIMER,
1810 0, 0, 0, 0);
1811
sewardjf854f472002-04-21 12:19:41 +00001812 if (/* CHECK SIZES FOR struct pollfd */
1813 sizeof(struct timeval) != sizeof(struct vki_timeval))
1814 barf("valgrind's hacky non-blocking poll(): data sizes error");
1815
sewardj5f07b662002-04-23 16:52:51 +00001816 /* dummy initialisation to keep gcc -Wall happy */
1817 ms_end = 0;
1818
1819 /* If a zero timeout specified, this call is harmless. Also do
1820 this if not running on Valgrind. */
1821 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001822 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1823 if (is_kerror(res)) {
1824 * (__errno_location()) = -res;
1825 return -1;
1826 } else {
1827 return res;
1828 }
1829 }
1830
sewardj5f07b662002-04-23 16:52:51 +00001831 /* If a timeout was specified, set ms_end to be the end wallclock
1832 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001833 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00001834 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001835 }
1836
1837 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1838
1839 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1840 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001841 assert(__timeout != 0);
1842
sewardjf854f472002-04-21 12:19:41 +00001843 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001844 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001845 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1846 VG_USERREQ__READ_MILLISECOND_TIMER,
1847 0, 0, 0, 0);
1848 assert(ms_now != 0xFFFFFFFF);
1849 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001850 /* timeout; nothing interesting happened. */
1851 for (i = 0; i < __nfds; i++)
1852 __fds[i].revents = 0;
1853 return 0;
1854 }
1855 }
1856
sewardj5f07b662002-04-23 16:52:51 +00001857 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001858 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1859 if (is_kerror(res)) {
1860 /* Some kind of error. Set errno and return. */
1861 * (__errno_location()) = -res;
1862 return -1;
1863 }
1864 if (res > 0) {
1865 /* One or more fds is ready. Return now. */
1866 return res;
1867 }
1868 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1869 /* nanosleep and go round again */
1870 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001871 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001872 /* It's critical here that valgrind's nanosleep implementation
1873 is nonblocking. */
1874 (void)my_do_syscall2(__NR_nanosleep,
1875 (int)(&nanosleep_interval), (int)NULL);
1876 }
1877}
sewardj3b13f0e2002-04-25 20:17:29 +00001878
1879
sewardj705d3cb2002-05-23 13:13:12 +00001880/* Helper function used to make accept() non-blocking. Idea is to use
1881 the above nonblocking poll() to make this thread ONLY wait for the
1882 specified fd to become ready, and then return. */
1883static void wait_for_fd_to_be_readable_or_erring ( int fd )
1884{
1885 struct pollfd pfd;
sewardj6e6cbaa2002-05-24 02:12:52 +00001886 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardj705d3cb2002-05-23 13:13:12 +00001887 pfd.fd = fd;
1888 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
1889 /* ... but not POLLOUT, you may notice. */
1890 pfd.revents = 0;
1891 (void)poll(&pfd, 1, -1 /* forever */);
1892}
1893
1894
sewardj3b13f0e2002-04-25 20:17:29 +00001895/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00001896 Hacky implementation of semaphores.
1897 ------------------------------------------------------------------ */
1898
1899#include <semaphore.h>
1900
1901/* This is a terrible way to do the remapping. Plan is to import an
1902 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00001903
1904typedef
1905 struct {
1906 pthread_mutex_t se_mx;
1907 pthread_cond_t se_cv;
1908 int count;
1909 }
1910 vg_sem_t;
1911
1912static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
1913
1914static int se_remap_used = 0;
1915static sem_t* se_remap_orig[VG_N_SEMAPHORES];
1916static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
1917
1918static vg_sem_t* se_remap ( sem_t* orig )
1919{
1920 int res, i;
1921 res = __pthread_mutex_lock(&se_remap_mx);
1922 assert(res == 0);
1923
1924 for (i = 0; i < se_remap_used; i++) {
1925 if (se_remap_orig[i] == orig)
1926 break;
1927 }
1928 if (i == se_remap_used) {
1929 if (se_remap_used == VG_N_SEMAPHORES) {
1930 res = pthread_mutex_unlock(&se_remap_mx);
1931 assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00001932 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00001933 }
1934 se_remap_used++;
1935 se_remap_orig[i] = orig;
1936 /* printf("allocated semaphore %d\n", i); */
1937 }
1938 res = __pthread_mutex_unlock(&se_remap_mx);
1939 assert(res == 0);
1940 return &se_remap_new[i];
1941}
1942
1943
1944int sem_init(sem_t *sem, int pshared, unsigned int value)
1945{
1946 int res;
1947 vg_sem_t* vg_sem;
1948 ensure_valgrind("sem_init");
1949 if (pshared != 0) {
1950 errno = ENOSYS;
1951 return -1;
1952 }
1953 vg_sem = se_remap(sem);
1954 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
1955 assert(res == 0);
1956 res = pthread_cond_init(&vg_sem->se_cv, NULL);
1957 assert(res == 0);
1958 vg_sem->count = value;
1959 return 0;
1960}
1961
1962
1963int sem_wait ( sem_t* sem )
1964{
1965 int res;
1966 vg_sem_t* vg_sem;
1967 ensure_valgrind("sem_wait");
1968 vg_sem = se_remap(sem);
1969 res = __pthread_mutex_lock(&vg_sem->se_mx);
1970 assert(res == 0);
1971 while (vg_sem->count == 0) {
1972 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
1973 assert(res == 0);
1974 }
1975 vg_sem->count--;
1976 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1977 assert(res == 0);
1978 return 0;
1979}
1980
1981int sem_post ( sem_t* sem )
1982{
1983 int res;
1984 vg_sem_t* vg_sem;
1985 ensure_valgrind("sem_post");
1986 vg_sem = se_remap(sem);
1987 res = __pthread_mutex_lock(&vg_sem->se_mx);
1988 assert(res == 0);
1989 if (vg_sem->count == 0) {
1990 vg_sem->count++;
1991 res = pthread_cond_broadcast(&vg_sem->se_cv);
1992 assert(res == 0);
1993 } else {
1994 vg_sem->count++;
1995 }
1996 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1997 assert(res == 0);
1998 return 0;
1999}
2000
2001
2002int sem_trywait ( sem_t* sem )
2003{
2004 int ret, res;
2005 vg_sem_t* vg_sem;
2006 ensure_valgrind("sem_trywait");
2007 vg_sem = se_remap(sem);
2008 res = __pthread_mutex_lock(&vg_sem->se_mx);
2009 assert(res == 0);
2010 if (vg_sem->count > 0) {
2011 vg_sem->count--;
2012 ret = 0;
2013 } else {
2014 ret = -1;
2015 errno = EAGAIN;
2016 }
2017 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2018 assert(res == 0);
2019 return ret;
2020}
2021
2022
2023int sem_getvalue(sem_t* sem, int * sval)
2024{
2025 vg_sem_t* vg_sem;
2026 ensure_valgrind("sem_trywait");
2027 vg_sem = se_remap(sem);
2028 *sval = vg_sem->count;
2029 return 0;
2030}
2031
2032
2033int sem_destroy(sem_t * sem)
2034{
2035 kludged("sem_destroy");
2036 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2037 return 0;
2038}
2039
2040
2041/* ---------------------------------------------------------------------
sewardja1ac5cb2002-05-27 13:00:05 +00002042 Hacky implementation of reader-writer locks.
2043 ------------------------------------------------------------------ */
2044
2045/*
2046Errata from 7th printing:
2047
2048 Page 259, rwlock.c, line 27, the two "!=" should be ">", for
2049 consistency with other similar tests. (The values should never be
2050 negative; this isn't a fix, but an improvement to clarity and
2051 consistency.)
2052
2053 [27] if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2054
2055 Page 259, rwlock.c, lines 39 and 40, in both lines, "==" should
2056 become "!=":
2057
2058 [39] return (status != 0 ? status
2059 [40] : (status1 != 0 ? status1 : status2));
2060*/
2061
2062/*
2063 * rwlock.h
2064 *
2065 * This header file describes the "reader/writer lock" synchronization
2066 * construct. The type rwlock_t describes the full state of the lock
2067 * including the POSIX 1003.1c synchronization objects necessary.
2068 *
2069 * A reader/writer lock allows a thread to lock shared data either for shared
2070 * read access or exclusive write access.
2071 *
2072 * The rwl_init() and rwl_destroy() functions, respectively, allow you to
2073 * initialize/create and destroy/free the reader/writer lock.
2074 */
2075
sewardja1ac5cb2002-05-27 13:00:05 +00002076/*
2077 * Structure describing a read-write lock.
2078 */
2079typedef struct {
2080 pthread_mutex_t mutex;
2081 pthread_cond_t read; /* wait for read */
2082 pthread_cond_t write; /* wait for write */
2083 int valid; /* set when valid */
2084 int r_active; /* readers active */
2085 int w_active; /* writer active */
2086 int r_wait; /* readers waiting */
2087 int w_wait; /* writers waiting */
2088 int pref_writer; /* != 0 --> prefer writer */
2089} vg_rwlock_t;
2090
2091#define VG_RWLOCK_VALID 0xfacade
2092
2093
2094/*
2095 * Support static initialization of barriers
2096 */
2097#define VG_RWL_INITIALIZER \
2098 {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \
2099 PTHREAD_COND_INITIALIZER, VG_RWLOCK_VALID, 0, 0, 0, 0, 1}
2100
2101
2102static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2103
2104static int rw_remap_used = 0;
2105static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2106static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2107
2108/* Take the address of a LinuxThreads rwlock_t and return the shadow
2109 address of our version. Further, if the LinuxThreads version
2110 appears to have been statically initialised, do the same to the one
2111 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2112 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2113 uninitialised and non-zero meaning initialised.
2114*/
2115static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2116{
2117 int res, i;
2118 vg_rwlock_t* vg_rwl;
2119 res = __pthread_mutex_lock(&rw_remap_mx);
2120 assert(res == 0);
2121
2122 for (i = 0; i < rw_remap_used; i++) {
2123 if (rw_remap_orig[i] == orig)
2124 break;
2125 }
2126 if (i == rw_remap_used) {
2127 if (rw_remap_used == VG_N_RWLOCKS) {
2128 res = pthread_mutex_unlock(&rw_remap_mx);
2129 assert(res == 0);
2130 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2131 }
2132 rw_remap_used++;
2133 rw_remap_orig[i] = orig;
2134 if (0) printf("allocated rwlock %d\n", i);
2135 }
2136 res = __pthread_mutex_unlock(&rw_remap_mx);
2137 assert(res == 0);
2138 vg_rwl = &rw_remap_new[i];
2139
2140 /* Mimic static initialisation of the original. */
2141 if (orig->__rw_readers == 0) {
2142 const vg_rwlock_t default_rwl = VG_RWL_INITIALIZER;
2143 orig->__rw_readers = 1;
2144 *vg_rwl = default_rwl;
2145 vg_rwl->pref_writer = 1;
2146 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
2147 vg_rwl->pref_writer = 0;
2148 }
2149
2150 return vg_rwl;
2151}
2152
2153
2154/*
2155 * rwlock.c
2156 *
2157 * This file implements the "read-write lock" synchronization
2158 * construct.
2159 *
2160 * A read-write lock allows a thread to lock shared data either
2161 * for shared read access or exclusive write access.
2162 *
2163 * The rwl_init() and rwl_destroy() functions, respectively,
2164 * allow you to initialize/create and destroy/free the
2165 * read-write lock.
2166 *
2167 * The rwl_readlock() function locks a read-write lock for
2168 * shared read access, and rwl_readunlock() releases the
2169 * lock. rwl_readtrylock() attempts to lock a read-write lock
2170 * for read access, and returns EBUSY instead of blocking.
2171 *
2172 * The rwl_writelock() function locks a read-write lock for
2173 * exclusive write access, and rwl_writeunlock() releases the
2174 * lock. rwl_writetrylock() attempts to lock a read-write lock
2175 * for write access, and returns EBUSY instead of blocking.
2176 */
2177
2178
2179/*
2180 * Initialize a read-write lock
2181 */
2182static int rwl_init ( vg_rwlock_t *rwl )
2183{
2184 int status;
2185
2186 rwl->r_active = 0;
2187 rwl->r_wait = rwl->w_wait = 0;
2188 rwl->w_active = 0;
2189 status = pthread_mutex_init (&rwl->mutex, NULL);
2190 if (status != 0)
2191 return status;
2192 status = pthread_cond_init (&rwl->read, NULL);
2193 if (status != 0) {
2194 /* if unable to create read CV, destroy mutex */
2195 pthread_mutex_destroy (&rwl->mutex);
2196 return status;
2197 }
2198 status = pthread_cond_init (&rwl->write, NULL);
2199 if (status != 0) {
2200 /* if unable to create write CV, destroy read CV and mutex */
2201 pthread_cond_destroy (&rwl->read);
2202 pthread_mutex_destroy (&rwl->mutex);
2203 return status;
2204 }
2205 rwl->valid = VG_RWLOCK_VALID;
2206 return 0;
2207}
2208
2209/*
2210 * Destroy a read-write lock
2211 */
2212static int rwl_destroy (vg_rwlock_t *rwl)
2213{
2214 int status, status1, status2;
2215
2216 if (rwl->valid != VG_RWLOCK_VALID)
2217 return EINVAL;
2218 status = pthread_mutex_lock (&rwl->mutex);
2219 if (status != 0)
2220 return status;
2221
2222 /*
2223 * Check whether any threads own the lock; report "BUSY" if
2224 * so.
2225 */
2226 if (rwl->r_active > 0 || rwl->w_active) {
2227 pthread_mutex_unlock (&rwl->mutex);
2228 return EBUSY;
2229 }
2230
2231 /*
2232 * Check whether any threads are known to be waiting; report
2233 * EBUSY if so.
2234 */
2235 if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2236 pthread_mutex_unlock (&rwl->mutex);
2237 return EBUSY;
2238 }
2239
2240 rwl->valid = 0;
2241 status = pthread_mutex_unlock (&rwl->mutex);
2242 if (status != 0)
2243 return status;
2244 status = pthread_mutex_destroy (&rwl->mutex);
2245 status1 = pthread_cond_destroy (&rwl->read);
2246 status2 = pthread_cond_destroy (&rwl->write);
2247 return (status != 0 ? status : (status1 != 0 ? status1 : status2));
2248}
2249
2250/*
2251 * Handle cleanup when the read lock condition variable
2252 * wait is cancelled.
2253 *
2254 * Simply record that the thread is no longer waiting,
2255 * and unlock the mutex.
2256 */
2257static void rwl_readcleanup (void *arg)
2258{
2259 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2260
2261 rwl->r_wait--;
2262 pthread_mutex_unlock (&rwl->mutex);
2263}
2264
2265/*
2266 * Lock a read-write lock for read access.
2267 */
2268static int rwl_readlock (vg_rwlock_t *rwl)
2269{
2270 int status;
2271
2272 if (rwl->valid != VG_RWLOCK_VALID)
2273 return EINVAL;
2274 status = pthread_mutex_lock (&rwl->mutex);
2275 if (status != 0)
2276 return status;
2277 if (rwl->w_active) {
2278 rwl->r_wait++;
2279 pthread_cleanup_push (rwl_readcleanup, (void*)rwl);
2280 while (rwl->w_active) {
2281 status = pthread_cond_wait (&rwl->read, &rwl->mutex);
2282 if (status != 0)
2283 break;
2284 }
2285 pthread_cleanup_pop (0);
2286 rwl->r_wait--;
2287 }
2288 if (status == 0)
2289 rwl->r_active++;
2290 pthread_mutex_unlock (&rwl->mutex);
2291 return status;
2292}
2293
2294/*
2295 * Attempt to lock a read-write lock for read access (don't
2296 * block if unavailable).
2297 */
2298static int rwl_readtrylock (vg_rwlock_t *rwl)
2299{
2300 int status, status2;
2301
2302 if (rwl->valid != VG_RWLOCK_VALID)
2303 return EINVAL;
2304 status = pthread_mutex_lock (&rwl->mutex);
2305 if (status != 0)
2306 return status;
2307 if (rwl->w_active)
2308 status = EBUSY;
2309 else
2310 rwl->r_active++;
2311 status2 = pthread_mutex_unlock (&rwl->mutex);
2312 return (status2 != 0 ? status2 : status);
2313}
2314
2315/*
2316 * Handle cleanup when the write lock condition variable
2317 * wait is cancelled.
2318 *
2319 * Simply record that the thread is no longer waiting,
2320 * and unlock the mutex.
2321 */
2322static void rwl_writecleanup (void *arg)
2323{
2324 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2325
2326 rwl->w_wait--;
2327 pthread_mutex_unlock (&rwl->mutex);
2328}
2329
2330/*
2331 * Lock a read-write lock for write access.
2332 */
2333static int rwl_writelock (vg_rwlock_t *rwl)
2334{
2335 int status;
2336
2337 if (rwl->valid != VG_RWLOCK_VALID)
2338 return EINVAL;
2339 status = pthread_mutex_lock (&rwl->mutex);
2340 if (status != 0)
2341 return status;
2342 if (rwl->w_active || rwl->r_active > 0) {
2343 rwl->w_wait++;
2344 pthread_cleanup_push (rwl_writecleanup, (void*)rwl);
2345 while (rwl->w_active || rwl->r_active > 0) {
2346 status = pthread_cond_wait (&rwl->write, &rwl->mutex);
2347 if (status != 0)
2348 break;
2349 }
2350 pthread_cleanup_pop (0);
2351 rwl->w_wait--;
2352 }
2353 if (status == 0)
2354 rwl->w_active = 1;
2355 pthread_mutex_unlock (&rwl->mutex);
2356 return status;
2357}
2358
2359/*
2360 * Attempt to lock a read-write lock for write access. Don't
2361 * block if unavailable.
2362 */
2363static int rwl_writetrylock (vg_rwlock_t *rwl)
2364{
2365 int status, status2;
2366
2367 if (rwl->valid != VG_RWLOCK_VALID)
2368 return EINVAL;
2369 status = pthread_mutex_lock (&rwl->mutex);
2370 if (status != 0)
2371 return status;
2372 if (rwl->w_active || rwl->r_active > 0)
2373 status = EBUSY;
2374 else
2375 rwl->w_active = 1;
2376 status2 = pthread_mutex_unlock (&rwl->mutex);
2377 return (status != 0 ? status : status2);
2378}
2379
2380/*
2381 * Unlock a read-write lock, using the r_active and w_active fields to
2382 * decide whether we're in a read or write lock.
2383 */
2384static int rwl_unlock (vg_rwlock_t *rwl)
2385{
2386 int status, status2;
2387
2388 if (rwl->valid != VG_RWLOCK_VALID)
2389 return EINVAL;
2390 status = pthread_mutex_lock (&rwl->mutex);
2391 if (status != 0)
2392 return status;
2393
2394 if (rwl->r_active > 0) {
2395
2396 /* READ case */
2397 assert(!rwl->w_active);
2398 rwl->r_active--;
2399 if (rwl->r_active == 0 && rwl->w_wait > 0)
2400 status = pthread_cond_signal (&rwl->write);
2401 /* END READ case */
2402
2403 } else {
2404
2405 /* WRITE case */
2406 assert(rwl->w_active);
2407 assert(rwl->r_active == 0);
2408 rwl->w_active = 0;
2409
2410 if (rwl->pref_writer) {
2411 /* Do writer-preference wakeups. */
2412 if (rwl->w_wait > 0) {
2413 status = pthread_cond_signal (&rwl->write);
2414 if (status != 0) {
2415 pthread_mutex_unlock (&rwl->mutex);
2416 return status;
2417 }
2418 } else if (rwl->r_wait > 0) {
2419 status = pthread_cond_broadcast (&rwl->read);
2420 if (status != 0) {
2421 pthread_mutex_unlock (&rwl->mutex);
2422 return status;
2423 }
2424 }
2425 } else {
2426 /* Do reader-preference wakeups. */
2427 if (rwl->r_wait > 0) {
2428 status = pthread_cond_broadcast (&rwl->read);
2429 if (status != 0) {
2430 pthread_mutex_unlock (&rwl->mutex);
2431 return status;
2432 }
2433 } else if (rwl->w_wait > 0) {
2434 status = pthread_cond_signal (&rwl->write);
2435 if (status != 0) {
2436 pthread_mutex_unlock (&rwl->mutex);
2437 return status;
2438 }
2439 }
2440 }
2441 /* END WRITE case */
2442
2443 }
2444
2445 status2 = pthread_mutex_unlock (&rwl->mutex);
2446 return (status2 == 0 ? status : status2);
2447}
2448
2449/* -------------------------------- */
2450
2451int pthread_rwlock_init ( pthread_rwlock_t* orig,
2452 const pthread_rwlockattr_t* attr )
2453{
2454 int res;
2455 vg_rwlock_t* rwl;
2456 if (0) printf ("pthread_rwlock_init\n");
2457 /* Force the remapper to initialise the shadow. */
2458 orig->__rw_readers = 0;
2459 /* Install the lock preference; the remapper needs to know it. */
2460 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2461 if (attr)
2462 orig->__rw_kind = attr->__lockkind;
2463 rwl = rw_remap ( orig );
2464 res = rwl_init ( rwl );
2465 return res;
2466}
2467
2468int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2469{
2470 int res;
2471 vg_rwlock_t* rwl;
2472 if (0) printf ("pthread_rwlock_destroy\n");
2473 rwl = rw_remap ( orig );
2474 res = rwl_destroy ( rwl );
2475 return res;
2476}
2477
2478int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2479{
2480 int res;
2481 vg_rwlock_t* rwl;
2482 if (0) printf ("pthread_rwlock_rdlock\n");
2483 rwl = rw_remap ( orig );
2484 res = rwl_readlock ( rwl );
2485 return res;
2486}
2487
2488int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2489{
2490 int res;
2491 vg_rwlock_t* rwl;
2492 if (0) printf ("pthread_rwlock_tryrdlock\n");
2493 rwl = rw_remap ( orig );
2494 res = rwl_readtrylock ( rwl );
2495 return res;
2496}
2497
2498int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2499{
2500 int res;
2501 vg_rwlock_t* rwl;
2502 if (0) printf ("pthread_rwlock_wrlock\n");
2503 rwl = rw_remap ( orig );
2504 res = rwl_writelock ( rwl );
2505 return res;
2506}
2507
2508int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2509{
2510 int res;
2511 vg_rwlock_t* rwl;
2512 if (0) printf ("pthread_rwlock_trywrlock\n");
2513 rwl = rw_remap ( orig );
2514 res = rwl_writetrylock ( rwl );
2515 return res;
2516}
2517
2518int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2519{
2520 int res;
2521 vg_rwlock_t* rwl;
2522 if (0) printf ("pthread_rwlock_unlock\n");
2523 rwl = rw_remap ( orig );
2524 res = rwl_unlock ( rwl );
2525 return res;
2526}
2527
2528
2529/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002530 B'stard.
2531 ------------------------------------------------------------------ */
2532
2533# define strong_alias(name, aliasname) \
2534 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2535
sewardj5905fae2002-04-26 13:25:00 +00002536# define weak_alias(name, aliasname) \
2537 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002538
sewardj5905fae2002-04-26 13:25:00 +00002539strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2540strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2541strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2542strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2543 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2544strong_alias(__pthread_mutex_init, pthread_mutex_init)
2545strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2546strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2547strong_alias(__pthread_once, pthread_once)
2548strong_alias(__pthread_atfork, pthread_atfork)
2549strong_alias(__pthread_key_create, pthread_key_create)
2550strong_alias(__pthread_getspecific, pthread_getspecific)
2551strong_alias(__pthread_setspecific, pthread_setspecific)
2552
sewardjd529a442002-05-04 19:49:21 +00002553#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002554strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002555#endif
2556
sewardj5905fae2002-04-26 13:25:00 +00002557strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002558strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002559strong_alias(lseek, __lseek)
2560strong_alias(open, __open)
2561strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002562strong_alias(read, __read)
2563strong_alias(wait, __wait)
2564strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002565strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002566strong_alias(send, __send)
2567
sewardj726c4122002-05-16 23:39:10 +00002568weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002569weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002570weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002571
sewardj5905fae2002-04-26 13:25:00 +00002572
sewardj3b13f0e2002-04-25 20:17:29 +00002573
2574/*--------------------------------------------------*/
2575
sewardj5905fae2002-04-26 13:25:00 +00002576weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002577weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002578weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002579
sewardja1ac5cb2002-05-27 13:00:05 +00002580weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2581weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2582weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2583weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2584
sewardj060b04f2002-04-26 21:01:13 +00002585
sewardj3b13f0e2002-04-25 20:17:29 +00002586/* I've no idea what these are, but they get called quite a lot.
2587 Anybody know? */
2588
2589#undef _IO_flockfile
2590void _IO_flockfile ( _IO_FILE * file )
2591{
sewardj853f55d2002-04-26 00:27:53 +00002592 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002593}
sewardj5905fae2002-04-26 13:25:00 +00002594weak_alias(_IO_flockfile, flockfile);
2595
sewardj3b13f0e2002-04-25 20:17:29 +00002596
2597#undef _IO_funlockfile
2598void _IO_funlockfile ( _IO_FILE * file )
2599{
sewardj853f55d2002-04-26 00:27:53 +00002600 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002601}
sewardj5905fae2002-04-26 13:25:00 +00002602weak_alias(_IO_funlockfile, funlockfile);
2603
sewardj3b13f0e2002-04-25 20:17:29 +00002604
sewardjd4f2c712002-04-30 10:20:10 +00002605/* This doesn't seem to be needed to simulate libpthread.so's external
2606 interface, but many people complain about its absence. */
2607
2608strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2609weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002610
2611
2612/*--------------------------------------------------------------------*/
2613/*--- end vg_libpthread.c ---*/
2614/*--------------------------------------------------------------------*/