blob: c92d54c8f5dc89689b80bb64b12d853b18efea67 [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{
sewardj9a664542002-05-29 20:22:17 +0000908 /* If we need this, implement it properly! */
909 vgPlain_unimp("__pthread_kill_other_threads_np");
910#if 0
sewardj853f55d2002-04-26 00:27:53 +0000911 int i, res, me;
sewardj68b2dd92002-05-10 21:03:56 +0000912 __pthread_mutex_lock(&massacre_mx);
sewardj853f55d2002-04-26 00:27:53 +0000913 me = pthread_self();
914 for (i = 1; i < VG_N_THREADS; i++) {
915 if (i == me) continue;
916 res = pthread_cancel(i);
sewardj436e0582002-04-26 14:31:40 +0000917 if (0 && res == 0)
sewardj853f55d2002-04-26 00:27:53 +0000918 printf("----------- NUKED %d\n", i);
919 }
sewardj68b2dd92002-05-10 21:03:56 +0000920 __pthread_mutex_unlock(&massacre_mx);
sewardj9a664542002-05-29 20:22:17 +0000921#endif
sewardj853f55d2002-04-26 00:27:53 +0000922}
923
sewardje663cb92002-04-12 10:26:32 +0000924
sewardjf8f819e2002-04-17 23:21:37 +0000925/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +0000926 SIGNALS
927 ------------------------------------------------ */
928
929#include <signal.h>
930
931int pthread_sigmask(int how, const sigset_t *newmask,
932 sigset_t *oldmask)
933{
934 int res;
935
936 /* A bit subtle, because the scheduler expects newmask and oldmask
937 to be vki_sigset_t* rather than sigset_t*, and the two are
938 different. Fortunately the first 64 bits of a sigset_t are
939 exactly a vki_sigset_t, so we just pass the pointers through
940 unmodified. Haaaack!
941
942 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +0000943 constants to VKI_ constants, so that the former do not have to
944 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +0000945
946 ensure_valgrind("pthread_sigmask");
947
948 switch (how) {
sewardj018f7622002-05-15 21:13:39 +0000949 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
950 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
951 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardjb48e5002002-05-13 00:16:03 +0000952 default: return EINVAL;
953 }
954
955 /* Crude check */
956 if (newmask == NULL)
957 return EFAULT;
958
959 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
960 VG_USERREQ__PTHREAD_SIGMASK,
961 how, newmask, oldmask, 0);
962
963 /* The scheduler tells us of any memory violations. */
964 return res == 0 ? 0 : EFAULT;
965}
966
967
968int sigwait ( const sigset_t* set, int* sig )
969{
970 int res;
971 ensure_valgrind("sigwait");
972 /* As with pthread_sigmask we deliberately confuse sigset_t with
973 vki_ksigset_t. */
974 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
975 VG_USERREQ__SIGWAIT,
976 set, sig, 0, 0);
977 return res;
978}
979
980
sewardj018f7622002-05-15 21:13:39 +0000981int pthread_kill(pthread_t thread, int signo)
982{
983 int res;
984 ensure_valgrind("pthread_kill");
985 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
986 VG_USERREQ__PTHREAD_KILL,
987 thread, signo, 0, 0);
988 return res;
989}
990
991
sewardj3665ded2002-05-16 16:57:25 +0000992/* Copied verbatim from Linuxthreads */
993/* Redefine raise() to send signal to calling thread only,
994 as per POSIX 1003.1c */
995int raise (int sig)
996{
997 int retcode = pthread_kill(pthread_self(), sig);
998 if (retcode == 0)
999 return 0;
1000 else {
1001 errno = retcode;
1002 return -1;
1003 }
1004}
1005
1006
sewardjb48e5002002-05-13 00:16:03 +00001007/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001008 THREAD-SPECIFICs
1009 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001010
sewardj5905fae2002-04-26 13:25:00 +00001011int __pthread_key_create(pthread_key_t *key,
1012 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001013{
sewardj5f07b662002-04-23 16:52:51 +00001014 int res;
1015 ensure_valgrind("pthread_key_create");
1016 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1017 VG_USERREQ__PTHREAD_KEY_CREATE,
1018 key, destr_function, 0, 0);
1019 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001020}
1021
1022int pthread_key_delete(pthread_key_t key)
1023{
sewardj436e0582002-04-26 14:31:40 +00001024 static int moans = N_MOANS;
1025 if (moans-- > 0)
1026 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +00001027 return 0;
1028}
1029
sewardj5905fae2002-04-26 13:25:00 +00001030int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001031{
sewardj5f07b662002-04-23 16:52:51 +00001032 int res;
1033 ensure_valgrind("pthread_setspecific");
1034 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1035 VG_USERREQ__PTHREAD_SETSPECIFIC,
1036 key, pointer, 0, 0);
1037 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001038}
1039
sewardj5905fae2002-04-26 13:25:00 +00001040void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001041{
sewardj5f07b662002-04-23 16:52:51 +00001042 int res;
1043 ensure_valgrind("pthread_getspecific");
1044 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1045 VG_USERREQ__PTHREAD_GETSPECIFIC,
1046 key, 0 , 0, 0);
1047 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001048}
1049
sewardjf8f819e2002-04-17 23:21:37 +00001050
1051/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001052 ONCEry
1053 ------------------------------------------------ */
1054
1055static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1056
1057
sewardj5905fae2002-04-26 13:25:00 +00001058int __pthread_once ( pthread_once_t *once_control,
1059 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001060{
1061 int res;
1062 ensure_valgrind("pthread_once");
1063
sewardj68b2dd92002-05-10 21:03:56 +00001064 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001065
sewardj68b2dd92002-05-10 21:03:56 +00001066 if (res != 0) {
1067 printf("res = %d\n",res);
sewardj89d3d852002-04-24 19:21:39 +00001068 barf("pthread_once: Looks like your program's "
1069 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001070 }
sewardj89d3d852002-04-24 19:21:39 +00001071
1072 if (*once_control == 0) {
1073 *once_control = 1;
1074 init_routine();
1075 }
1076
sewardj68b2dd92002-05-10 21:03:56 +00001077 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001078
1079 return 0;
1080}
1081
1082
1083/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001084 MISC
1085 ------------------------------------------------ */
1086
sewardj5905fae2002-04-26 13:25:00 +00001087int __pthread_atfork ( void (*prepare)(void),
1088 void (*parent)(void),
1089 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001090{
sewardjccef2e62002-05-29 19:26:32 +00001091 /* We have to do this properly or not at all; faking it isn't an
1092 option. */
1093 vgPlain_unimp("__pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +00001094}
1095
1096
sewardjbb990782002-05-08 02:01:14 +00001097__attribute__((weak))
1098void __pthread_initialize ( void )
1099{
sewardjbea1caa2002-05-10 23:20:58 +00001100 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001101}
1102
1103
sewardj853f55d2002-04-26 00:27:53 +00001104/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001105 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001106 ------------------------------------------------ */
1107
sewardj3b13f0e2002-04-25 20:17:29 +00001108#include <resolv.h>
1109static int thread_specific_errno[VG_N_THREADS];
1110static int thread_specific_h_errno[VG_N_THREADS];
1111static struct __res_state
1112 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001113
sewardj3b13f0e2002-04-25 20:17:29 +00001114int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001115{
1116 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001117 /* ensure_valgrind("__errno_location"); */
1118 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001119 VG_USERREQ__PTHREAD_GET_THREADID,
1120 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001121 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001122 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001123 barf("__errno_location: invalid ThreadId");
1124 return & thread_specific_errno[tid];
1125}
1126
1127int* __h_errno_location ( void )
1128{
1129 int tid;
1130 /* ensure_valgrind("__h_errno_location"); */
1131 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1132 VG_USERREQ__PTHREAD_GET_THREADID,
1133 0, 0, 0, 0);
1134 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001135 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001136 barf("__h_errno_location: invalid ThreadId");
1137 return & thread_specific_h_errno[tid];
1138}
1139
1140struct __res_state* __res_state ( void )
1141{
1142 int tid;
1143 /* ensure_valgrind("__res_state"); */
1144 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1145 VG_USERREQ__PTHREAD_GET_THREADID,
1146 0, 0, 0, 0);
1147 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001148 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001149 barf("__res_state: invalid ThreadId");
1150 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001151}
1152
1153
sewardj5716dbb2002-04-26 03:28:18 +00001154/* ---------------------------------------------------
1155 LIBC-PRIVATE SPECIFIC DATA
1156 ------------------------------------------------ */
1157
1158/* Relies on assumption that initial private data is NULL. This
1159 should be fixed somehow. */
1160
1161/* The allowable keys (indices) (all 2 of them).
1162 From sysdeps/pthread/bits/libc-tsd.h
1163*/
sewardj70adeb22002-04-27 01:35:38 +00001164#define N_LIBC_TSD_EXTRA_KEYS 1
1165
sewardj5716dbb2002-04-26 03:28:18 +00001166enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1167 _LIBC_TSD_KEY_DL_ERROR,
1168 _LIBC_TSD_KEY_N };
1169
1170/* Auto-initialising subsystem. libc_specifics_inited is set
1171 after initialisation. libc_specifics_inited_mx guards it. */
1172static int libc_specifics_inited = 0;
1173static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1174
1175/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001176static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1177 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001178
1179/* Initialise the keys, if they are not already initialise. */
1180static
1181void init_libc_tsd_keys ( void )
1182{
1183 int res, i;
1184 pthread_key_t k;
1185
1186 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1187 if (res != 0) barf("init_libc_tsd_keys: lock");
1188
1189 if (libc_specifics_inited == 0) {
1190 /* printf("INIT libc specifics\n"); */
1191 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001192 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001193 res = pthread_key_create(&k, NULL);
1194 if (res != 0) barf("init_libc_tsd_keys: create");
1195 libc_specifics_keys[i] = k;
1196 }
1197 }
1198
1199 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1200 if (res != 0) barf("init_libc_tsd_keys: unlock");
1201}
1202
1203
1204static int
1205libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1206 const void * pointer )
1207{
sewardj70adeb22002-04-27 01:35:38 +00001208 int res;
1209 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001210 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001211 if (key < _LIBC_TSD_KEY_MALLOC
1212 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001213 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001214 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1215 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001216 "valgrind's libpthread.so: libc_internal_tsd_set: "
1217 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001218 init_libc_tsd_keys();
1219 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1220 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1221 return 0;
1222}
1223
1224static void *
1225libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1226{
sewardj70adeb22002-04-27 01:35:38 +00001227 void* v;
1228 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001229 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001230 if (key < _LIBC_TSD_KEY_MALLOC
1231 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001232 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001233 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1234 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001235 "valgrind's libpthread.so: libc_internal_tsd_get: "
1236 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001237 init_libc_tsd_keys();
1238 v = pthread_getspecific(libc_specifics_keys[key]);
1239 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1240 return v;
1241}
1242
1243
1244
1245
sewardj70adeb22002-04-27 01:35:38 +00001246int (*__libc_internal_tsd_set)
1247 (enum __libc_tsd_key_t key, const void * pointer)
1248 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001249
sewardj70adeb22002-04-27 01:35:38 +00001250void* (*__libc_internal_tsd_get)
1251 (enum __libc_tsd_key_t key)
1252 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001253
1254
sewardje663cb92002-04-12 10:26:32 +00001255/* ---------------------------------------------------------------------
1256 These are here (I think) because they are deemed cancellation
1257 points by POSIX. For the moment we'll simply pass the call along
1258 to the corresponding thread-unaware (?) libc routine.
1259 ------------------------------------------------------------------ */
1260
sewardje663cb92002-04-12 10:26:32 +00001261#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001262#include <sys/types.h>
1263#include <sys/socket.h>
1264
sewardjd529a442002-05-04 19:49:21 +00001265#ifdef GLIBC_2_1
1266extern
1267int __sigaction
1268 (int signum,
1269 const struct sigaction *act,
1270 struct sigaction *oldact);
1271#else
sewardje663cb92002-04-12 10:26:32 +00001272extern
1273int __libc_sigaction
1274 (int signum,
1275 const struct sigaction *act,
1276 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001277#endif
sewardje663cb92002-04-12 10:26:32 +00001278int sigaction(int signum,
1279 const struct sigaction *act,
1280 struct sigaction *oldact)
1281{
sewardjd140e442002-05-29 01:21:19 +00001282 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001283# ifdef GLIBC_2_1
1284 return __sigaction(signum, act, oldact);
1285# else
sewardj45b4b372002-04-16 22:50:32 +00001286 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001287# endif
sewardje663cb92002-04-12 10:26:32 +00001288}
1289
1290
1291extern
1292int __libc_connect(int sockfd,
1293 const struct sockaddr *serv_addr,
1294 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001295__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001296int connect(int sockfd,
1297 const struct sockaddr *serv_addr,
1298 socklen_t addrlen)
1299{
sewardjd140e442002-05-29 01:21:19 +00001300 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001301 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001302}
1303
1304
1305extern
1306int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001307__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001308int fcntl(int fd, int cmd, long arg)
1309{
sewardjd140e442002-05-29 01:21:19 +00001310 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001311 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001312}
1313
1314
1315extern
1316ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001317__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001318ssize_t write(int fd, const void *buf, size_t count)
1319{
sewardjd140e442002-05-29 01:21:19 +00001320 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001321 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001322}
1323
1324
1325extern
1326ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001327__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001328ssize_t read(int fd, void *buf, size_t count)
1329{
sewardjd140e442002-05-29 01:21:19 +00001330 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001331 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001332}
1333
sewardjbe32e452002-04-24 20:29:58 +00001334
1335extern
sewardj853f55d2002-04-26 00:27:53 +00001336int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001337__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001338int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001339{
sewardjd140e442002-05-29 01:21:19 +00001340 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001341 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001342}
1343
sewardje663cb92002-04-12 10:26:32 +00001344
1345extern
sewardj853f55d2002-04-26 00:27:53 +00001346int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001347__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001348int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001349{
sewardjd140e442002-05-29 01:21:19 +00001350 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001351 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001352}
1353
1354
1355extern
1356int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001357__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001358int close(int fd)
1359{
sewardjd140e442002-05-29 01:21:19 +00001360 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001361 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001362}
1363
1364
1365extern
1366int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001367__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001368int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1369{
sewardjd140e442002-05-29 01:21:19 +00001370 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001371 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001372 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001373 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001374}
1375
1376
1377extern
1378pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001379pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001380{
sewardjd140e442002-05-29 01:21:19 +00001381 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001382 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001383}
1384
1385
1386extern
1387pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001388__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001389pid_t waitpid(pid_t pid, int *status, int options)
1390{
sewardjd140e442002-05-29 01:21:19 +00001391 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001392 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001393}
1394
1395
1396extern
1397int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001398__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001399int nanosleep(const struct timespec *req, struct timespec *rem)
1400{
sewardjd140e442002-05-29 01:21:19 +00001401 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001402 return __libc_nanosleep(req, rem);
1403}
1404
sewardjbe32e452002-04-24 20:29:58 +00001405
sewardje663cb92002-04-12 10:26:32 +00001406extern
1407int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001408__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001409int fsync(int fd)
1410{
sewardjd140e442002-05-29 01:21:19 +00001411 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001412 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001413}
1414
sewardjbe32e452002-04-24 20:29:58 +00001415
sewardj70c75362002-04-13 04:18:32 +00001416extern
1417off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001418__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001419off_t lseek(int fildes, off_t offset, int whence)
1420{
sewardjd140e442002-05-29 01:21:19 +00001421 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001422 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001423}
1424
sewardjbe32e452002-04-24 20:29:58 +00001425
1426extern
1427__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001428__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001429__off64_t lseek64(int fildes, __off64_t offset, int whence)
1430{
sewardjd140e442002-05-29 01:21:19 +00001431 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001432 return __libc_lseek64(fildes, offset, whence);
1433}
1434
1435
sewardj726c4122002-05-16 23:39:10 +00001436extern
1437ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1438 __off64_t __offset);
1439ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1440 __off64_t __offset)
1441{
sewardjd140e442002-05-29 01:21:19 +00001442 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001443 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1444}
1445
1446
sewardja18e2102002-05-18 10:43:22 +00001447extern
1448ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1449 __off64_t __offset);
1450ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1451 __off64_t __offset)
1452{
sewardjd140e442002-05-29 01:21:19 +00001453 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001454 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1455}
1456
sewardj726c4122002-05-16 23:39:10 +00001457
sewardj39b93b12002-05-18 10:56:27 +00001458extern
1459ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1460__attribute__((weak))
1461ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1462{
sewardjd140e442002-05-29 01:21:19 +00001463 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001464 return __libc_pwrite(fd, buf, count, offset);
1465}
1466
1467
1468extern
1469ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1470__attribute__((weak))
1471ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1472{
sewardjd140e442002-05-29 01:21:19 +00001473 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001474 return __libc_pread(fd, buf, count, offset);
1475}
1476
1477
sewardj6af4b5d2002-04-16 04:40:49 +00001478extern
1479void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001480/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001481void longjmp(jmp_buf env, int val)
1482{
sewardjd140e442002-05-29 01:21:19 +00001483 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001484 __libc_longjmp(env, val);
1485}
1486
sewardjbe32e452002-04-24 20:29:58 +00001487
sewardj6af4b5d2002-04-16 04:40:49 +00001488extern
1489int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001490__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001491int send(int s, const void *msg, size_t len, int flags)
1492{
sewardjd140e442002-05-29 01:21:19 +00001493 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001494 return __libc_send(s, msg, len, flags);
1495}
1496
sewardjbe32e452002-04-24 20:29:58 +00001497
sewardj1e8cdc92002-04-18 11:37:52 +00001498extern
1499int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001500__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001501int recv(int s, void *buf, size_t len, int flags)
1502{
sewardjd140e442002-05-29 01:21:19 +00001503 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001504 return __libc_recv(s, buf, len, flags);
1505}
1506
sewardjbe32e452002-04-24 20:29:58 +00001507
sewardj3665ded2002-05-16 16:57:25 +00001508extern
1509int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1510__attribute__((weak))
1511int sendmsg(int s, const struct msghdr *msg, int flags)
1512{
sewardjd140e442002-05-29 01:21:19 +00001513 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001514 return __libc_sendmsg(s, msg, flags);
1515}
1516
1517
sewardj796d6a22002-04-24 02:28:34 +00001518extern
sewardj436e0582002-04-26 14:31:40 +00001519int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1520 struct sockaddr *from, socklen_t *fromlen);
1521__attribute__((weak))
1522int recvfrom(int s, void *buf, size_t len, int flags,
1523 struct sockaddr *from, socklen_t *fromlen)
1524{
sewardjd140e442002-05-29 01:21:19 +00001525 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001526 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1527}
1528
1529
1530extern
sewardj796d6a22002-04-24 02:28:34 +00001531int __libc_sendto(int s, const void *msg, size_t len, int flags,
1532 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001533__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001534int sendto(int s, const void *msg, size_t len, int flags,
1535 const struct sockaddr *to, socklen_t tolen)
1536{
sewardjd140e442002-05-29 01:21:19 +00001537 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001538 return __libc_sendto(s, msg, len, flags, to, tolen);
1539}
1540
sewardjbe32e452002-04-24 20:29:58 +00001541
sewardj369b1702002-04-24 13:28:15 +00001542extern
1543int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001544__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001545int system(const char* str)
1546{
sewardjd140e442002-05-29 01:21:19 +00001547 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001548 return __libc_system(str);
1549}
1550
sewardjbe32e452002-04-24 20:29:58 +00001551
sewardjab0b1c32002-04-24 19:26:47 +00001552extern
1553pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001554__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001555pid_t wait(int *status)
1556{
sewardjd140e442002-05-29 01:21:19 +00001557 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00001558 return __libc_wait(status);
1559}
1560
sewardj45b4b372002-04-16 22:50:32 +00001561
sewardj67f1d582002-05-24 02:11:32 +00001562extern
1563int __libc_msync(const void *start, size_t length, int flags);
1564__attribute__((weak))
1565int msync(const void *start, size_t length, int flags)
1566{
sewardjd140e442002-05-29 01:21:19 +00001567 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00001568 return __libc_msync(start, length, flags);
1569}
1570
sewardj5905fae2002-04-26 13:25:00 +00001571
sewardj3b13f0e2002-04-25 20:17:29 +00001572/* ---------------------------------------------------------------------
1573 Nonblocking implementations of select() and poll(). This stuff will
1574 surely rot your mind.
1575 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001576
sewardj08a4c3f2002-04-13 03:45:44 +00001577/*--------------------------------------------------*/
1578
1579#include "vg_kerneliface.h"
1580
1581static
1582__inline__
1583int is_kerror ( int res )
1584{
1585 if (res >= -4095 && res <= -1)
1586 return 1;
1587 else
1588 return 0;
1589}
1590
1591
1592static
1593int my_do_syscall1 ( int syscallno, int arg1 )
1594{
1595 int __res;
1596 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1597 : "=a" (__res)
1598 : "0" (syscallno),
1599 "d" (arg1) );
1600 return __res;
1601}
1602
1603static
1604int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001605 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001606{
1607 int __res;
1608 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1609 : "=a" (__res)
1610 : "0" (syscallno),
1611 "d" (arg1),
1612 "c" (arg2) );
1613 return __res;
1614}
1615
1616static
sewardjf854f472002-04-21 12:19:41 +00001617int my_do_syscall3 ( int syscallno,
1618 int arg1, int arg2, int arg3 )
1619{
1620 int __res;
1621 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1622 : "=a" (__res)
1623 : "0" (syscallno),
1624 "S" (arg1),
1625 "c" (arg2),
1626 "d" (arg3) );
1627 return __res;
1628}
1629
1630static
sewardj08a4c3f2002-04-13 03:45:44 +00001631int do_syscall_select( int n,
1632 vki_fd_set* readfds,
1633 vki_fd_set* writefds,
1634 vki_fd_set* exceptfds,
1635 struct vki_timeval * timeout )
1636{
1637 int res;
1638 int args[5];
1639 args[0] = n;
1640 args[1] = (int)readfds;
1641 args[2] = (int)writefds;
1642 args[3] = (int)exceptfds;
1643 args[4] = (int)timeout;
1644 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001645 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001646}
1647
1648
1649/* This is a wrapper round select(), which makes it thread-safe,
1650 meaning that only this thread will block, rather than the entire
1651 process. This wrapper in turn depends on nanosleep() not to block
1652 the entire process, but I think (hope? suspect?) that POSIX
1653 pthreads guarantees that to be the case.
1654
1655 Basic idea is: modify the timeout parameter to select so that it
1656 returns immediately. Poll like this until select returns non-zero,
1657 indicating something interesting happened, or until our time is up.
1658 Space out the polls with nanosleeps of say 20 milliseconds, which
1659 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001660
1661 Assumes:
1662 * (checked via assert) types fd_set and vki_fd_set are identical.
1663 * (checked via assert) types timeval and vki_timeval are identical.
1664 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1665 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001666*/
sewardj08a4c3f2002-04-13 03:45:44 +00001667
sewardj5905fae2002-04-26 13:25:00 +00001668/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001669int select ( int n,
1670 fd_set *rfds,
1671 fd_set *wfds,
1672 fd_set *xfds,
1673 struct timeval *timeout )
1674{
sewardj5f07b662002-04-23 16:52:51 +00001675 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001676 int res;
1677 fd_set rfds_copy;
1678 fd_set wfds_copy;
1679 fd_set xfds_copy;
1680 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001681 struct vki_timeval zero_timeout;
1682 struct vki_timespec nanosleep_interval;
1683
sewardjd140e442002-05-29 01:21:19 +00001684 __my_pthread_testcancel();
1685
sewardj5f07b662002-04-23 16:52:51 +00001686 /* gcc's complains about ms_end being used uninitialised -- classic
1687 case it can't understand, where ms_end is both defined and used
1688 only if timeout != NULL. Hence ... */
1689 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001690
1691 /* We assume that the kernel and libc data layouts are identical
1692 for the following types. These asserts provide a crude
1693 check. */
1694 if (sizeof(fd_set) != sizeof(vki_fd_set)
1695 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1696 barf("valgrind's hacky non-blocking select(): data sizes error");
1697
sewardj5f07b662002-04-23 16:52:51 +00001698 /* Detect the current time and simultaneously find out if we are
1699 running on Valgrind. */
1700 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1701 VG_USERREQ__READ_MILLISECOND_TIMER,
1702 0, 0, 0, 0);
1703
1704 /* If a zero timeout specified, this call is harmless. Also go
1705 this route if we're not running on Valgrind, for whatever
1706 reason. */
1707 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1708 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001709 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001710 (vki_fd_set*)wfds,
1711 (vki_fd_set*)xfds,
1712 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001713 if (is_kerror(res)) {
1714 * (__errno_location()) = -res;
1715 return -1;
1716 } else {
1717 return res;
1718 }
1719 }
sewardj08a4c3f2002-04-13 03:45:44 +00001720
sewardj5f07b662002-04-23 16:52:51 +00001721 /* If a timeout was specified, set ms_end to be the end millisecond
1722 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001723 if (timeout) {
1724 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
1725 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001726 ms_end = ms_now;
1727 ms_end += (timeout->tv_usec / 1000);
1728 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001729 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +00001730 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001731 }
1732
1733 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1734
1735 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001736 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001737 while (1) {
1738 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +00001739 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1740 VG_USERREQ__READ_MILLISECOND_TIMER,
1741 0, 0, 0, 0);
1742 assert(ms_now != 0xFFFFFFFF);
1743 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +00001744 /* timeout; nothing interesting happened. */
1745 if (rfds) FD_ZERO(rfds);
1746 if (wfds) FD_ZERO(wfds);
1747 if (xfds) FD_ZERO(xfds);
1748 return 0;
1749 }
1750 }
1751
1752 /* These could be trashed each time round the loop, so restore
1753 them each time. */
1754 if (rfds) rfds_copy = *rfds;
1755 if (wfds) wfds_copy = *wfds;
1756 if (xfds) xfds_copy = *xfds;
1757
1758 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1759
1760 res = do_syscall_select( n,
1761 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1762 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1763 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1764 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001765 if (is_kerror(res)) {
1766 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001767 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001768 * (__errno_location()) = -res;
1769 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001770 }
1771 if (res > 0) {
1772 /* one or more fds is ready. Copy out resulting sets and
1773 return. */
1774 if (rfds) *rfds = rfds_copy;
1775 if (wfds) *wfds = wfds_copy;
1776 if (xfds) *xfds = xfds_copy;
1777 return res;
1778 }
1779 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1780 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001781 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001782 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001783 /* It's critical here that valgrind's nanosleep implementation
1784 is nonblocking. */
1785 (void)my_do_syscall2(__NR_nanosleep,
1786 (int)(&nanosleep_interval), (int)NULL);
1787 }
1788}
1789
1790
1791
1792
1793#include <sys/poll.h>
1794
sewardj72d58482002-04-24 02:20:20 +00001795#ifdef GLIBC_2_1
1796typedef unsigned long int nfds_t;
1797#endif
1798
sewardj705d3cb2002-05-23 13:13:12 +00001799
sewardj5905fae2002-04-26 13:25:00 +00001800/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00001801int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1802{
sewardj5f07b662002-04-23 16:52:51 +00001803 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001804 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001805 struct vki_timespec nanosleep_interval;
1806
sewardjd140e442002-05-29 01:21:19 +00001807 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00001808 ensure_valgrind("poll");
1809
sewardj5f07b662002-04-23 16:52:51 +00001810 /* Detect the current time and simultaneously find out if we are
1811 running on Valgrind. */
1812 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1813 VG_USERREQ__READ_MILLISECOND_TIMER,
1814 0, 0, 0, 0);
1815
sewardjf854f472002-04-21 12:19:41 +00001816 if (/* CHECK SIZES FOR struct pollfd */
1817 sizeof(struct timeval) != sizeof(struct vki_timeval))
1818 barf("valgrind's hacky non-blocking poll(): data sizes error");
1819
sewardj5f07b662002-04-23 16:52:51 +00001820 /* dummy initialisation to keep gcc -Wall happy */
1821 ms_end = 0;
1822
1823 /* If a zero timeout specified, this call is harmless. Also do
1824 this if not running on Valgrind. */
1825 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001826 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1827 if (is_kerror(res)) {
1828 * (__errno_location()) = -res;
1829 return -1;
1830 } else {
1831 return res;
1832 }
1833 }
1834
sewardj5f07b662002-04-23 16:52:51 +00001835 /* If a timeout was specified, set ms_end to be the end wallclock
1836 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001837 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00001838 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001839 }
1840
1841 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1842
1843 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1844 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001845 assert(__timeout != 0);
1846
sewardjf854f472002-04-21 12:19:41 +00001847 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001848 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001849 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1850 VG_USERREQ__READ_MILLISECOND_TIMER,
1851 0, 0, 0, 0);
1852 assert(ms_now != 0xFFFFFFFF);
1853 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001854 /* timeout; nothing interesting happened. */
1855 for (i = 0; i < __nfds; i++)
1856 __fds[i].revents = 0;
1857 return 0;
1858 }
1859 }
1860
sewardj5f07b662002-04-23 16:52:51 +00001861 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001862 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1863 if (is_kerror(res)) {
1864 /* Some kind of error. Set errno and return. */
1865 * (__errno_location()) = -res;
1866 return -1;
1867 }
1868 if (res > 0) {
1869 /* One or more fds is ready. Return now. */
1870 return res;
1871 }
1872 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1873 /* nanosleep and go round again */
1874 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001875 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001876 /* It's critical here that valgrind's nanosleep implementation
1877 is nonblocking. */
1878 (void)my_do_syscall2(__NR_nanosleep,
1879 (int)(&nanosleep_interval), (int)NULL);
1880 }
1881}
sewardj3b13f0e2002-04-25 20:17:29 +00001882
1883
sewardj705d3cb2002-05-23 13:13:12 +00001884/* Helper function used to make accept() non-blocking. Idea is to use
1885 the above nonblocking poll() to make this thread ONLY wait for the
1886 specified fd to become ready, and then return. */
1887static void wait_for_fd_to_be_readable_or_erring ( int fd )
1888{
1889 struct pollfd pfd;
sewardj6e6cbaa2002-05-24 02:12:52 +00001890 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardj705d3cb2002-05-23 13:13:12 +00001891 pfd.fd = fd;
1892 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
1893 /* ... but not POLLOUT, you may notice. */
1894 pfd.revents = 0;
1895 (void)poll(&pfd, 1, -1 /* forever */);
1896}
1897
1898
sewardj3b13f0e2002-04-25 20:17:29 +00001899/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00001900 Hacky implementation of semaphores.
1901 ------------------------------------------------------------------ */
1902
1903#include <semaphore.h>
1904
1905/* This is a terrible way to do the remapping. Plan is to import an
1906 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00001907
1908typedef
1909 struct {
1910 pthread_mutex_t se_mx;
1911 pthread_cond_t se_cv;
1912 int count;
1913 }
1914 vg_sem_t;
1915
1916static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
1917
1918static int se_remap_used = 0;
1919static sem_t* se_remap_orig[VG_N_SEMAPHORES];
1920static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
1921
1922static vg_sem_t* se_remap ( sem_t* orig )
1923{
1924 int res, i;
1925 res = __pthread_mutex_lock(&se_remap_mx);
1926 assert(res == 0);
1927
1928 for (i = 0; i < se_remap_used; i++) {
1929 if (se_remap_orig[i] == orig)
1930 break;
1931 }
1932 if (i == se_remap_used) {
1933 if (se_remap_used == VG_N_SEMAPHORES) {
1934 res = pthread_mutex_unlock(&se_remap_mx);
1935 assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00001936 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00001937 }
1938 se_remap_used++;
1939 se_remap_orig[i] = orig;
1940 /* printf("allocated semaphore %d\n", i); */
1941 }
1942 res = __pthread_mutex_unlock(&se_remap_mx);
1943 assert(res == 0);
1944 return &se_remap_new[i];
1945}
1946
1947
1948int sem_init(sem_t *sem, int pshared, unsigned int value)
1949{
1950 int res;
1951 vg_sem_t* vg_sem;
1952 ensure_valgrind("sem_init");
1953 if (pshared != 0) {
1954 errno = ENOSYS;
1955 return -1;
1956 }
1957 vg_sem = se_remap(sem);
1958 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
1959 assert(res == 0);
1960 res = pthread_cond_init(&vg_sem->se_cv, NULL);
1961 assert(res == 0);
1962 vg_sem->count = value;
1963 return 0;
1964}
1965
1966
1967int sem_wait ( sem_t* sem )
1968{
1969 int res;
1970 vg_sem_t* vg_sem;
1971 ensure_valgrind("sem_wait");
1972 vg_sem = se_remap(sem);
1973 res = __pthread_mutex_lock(&vg_sem->se_mx);
1974 assert(res == 0);
1975 while (vg_sem->count == 0) {
1976 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
1977 assert(res == 0);
1978 }
1979 vg_sem->count--;
1980 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1981 assert(res == 0);
1982 return 0;
1983}
1984
1985int sem_post ( sem_t* sem )
1986{
1987 int res;
1988 vg_sem_t* vg_sem;
1989 ensure_valgrind("sem_post");
1990 vg_sem = se_remap(sem);
1991 res = __pthread_mutex_lock(&vg_sem->se_mx);
1992 assert(res == 0);
1993 if (vg_sem->count == 0) {
1994 vg_sem->count++;
1995 res = pthread_cond_broadcast(&vg_sem->se_cv);
1996 assert(res == 0);
1997 } else {
1998 vg_sem->count++;
1999 }
2000 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2001 assert(res == 0);
2002 return 0;
2003}
2004
2005
2006int sem_trywait ( sem_t* sem )
2007{
2008 int ret, res;
2009 vg_sem_t* vg_sem;
2010 ensure_valgrind("sem_trywait");
2011 vg_sem = se_remap(sem);
2012 res = __pthread_mutex_lock(&vg_sem->se_mx);
2013 assert(res == 0);
2014 if (vg_sem->count > 0) {
2015 vg_sem->count--;
2016 ret = 0;
2017 } else {
2018 ret = -1;
2019 errno = EAGAIN;
2020 }
2021 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2022 assert(res == 0);
2023 return ret;
2024}
2025
2026
2027int sem_getvalue(sem_t* sem, int * sval)
2028{
2029 vg_sem_t* vg_sem;
2030 ensure_valgrind("sem_trywait");
2031 vg_sem = se_remap(sem);
2032 *sval = vg_sem->count;
2033 return 0;
2034}
2035
2036
2037int sem_destroy(sem_t * sem)
2038{
2039 kludged("sem_destroy");
2040 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2041 return 0;
2042}
2043
2044
2045/* ---------------------------------------------------------------------
sewardja1ac5cb2002-05-27 13:00:05 +00002046 Hacky implementation of reader-writer locks.
2047 ------------------------------------------------------------------ */
2048
2049/*
2050Errata from 7th printing:
2051
2052 Page 259, rwlock.c, line 27, the two "!=" should be ">", for
2053 consistency with other similar tests. (The values should never be
2054 negative; this isn't a fix, but an improvement to clarity and
2055 consistency.)
2056
2057 [27] if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2058
2059 Page 259, rwlock.c, lines 39 and 40, in both lines, "==" should
2060 become "!=":
2061
2062 [39] return (status != 0 ? status
2063 [40] : (status1 != 0 ? status1 : status2));
2064*/
2065
2066/*
2067 * rwlock.h
2068 *
2069 * This header file describes the "reader/writer lock" synchronization
2070 * construct. The type rwlock_t describes the full state of the lock
2071 * including the POSIX 1003.1c synchronization objects necessary.
2072 *
2073 * A reader/writer lock allows a thread to lock shared data either for shared
2074 * read access or exclusive write access.
2075 *
2076 * The rwl_init() and rwl_destroy() functions, respectively, allow you to
2077 * initialize/create and destroy/free the reader/writer lock.
2078 */
2079
sewardja1ac5cb2002-05-27 13:00:05 +00002080/*
2081 * Structure describing a read-write lock.
2082 */
2083typedef struct {
2084 pthread_mutex_t mutex;
2085 pthread_cond_t read; /* wait for read */
2086 pthread_cond_t write; /* wait for write */
2087 int valid; /* set when valid */
2088 int r_active; /* readers active */
2089 int w_active; /* writer active */
2090 int r_wait; /* readers waiting */
2091 int w_wait; /* writers waiting */
2092 int pref_writer; /* != 0 --> prefer writer */
2093} vg_rwlock_t;
2094
2095#define VG_RWLOCK_VALID 0xfacade
2096
2097
2098/*
2099 * Support static initialization of barriers
2100 */
2101#define VG_RWL_INITIALIZER \
2102 {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \
2103 PTHREAD_COND_INITIALIZER, VG_RWLOCK_VALID, 0, 0, 0, 0, 1}
2104
2105
2106static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2107
2108static int rw_remap_used = 0;
2109static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2110static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2111
2112/* Take the address of a LinuxThreads rwlock_t and return the shadow
2113 address of our version. Further, if the LinuxThreads version
2114 appears to have been statically initialised, do the same to the one
2115 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2116 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2117 uninitialised and non-zero meaning initialised.
2118*/
2119static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2120{
2121 int res, i;
2122 vg_rwlock_t* vg_rwl;
2123 res = __pthread_mutex_lock(&rw_remap_mx);
2124 assert(res == 0);
2125
2126 for (i = 0; i < rw_remap_used; i++) {
2127 if (rw_remap_orig[i] == orig)
2128 break;
2129 }
2130 if (i == rw_remap_used) {
2131 if (rw_remap_used == VG_N_RWLOCKS) {
2132 res = pthread_mutex_unlock(&rw_remap_mx);
2133 assert(res == 0);
2134 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2135 }
2136 rw_remap_used++;
2137 rw_remap_orig[i] = orig;
2138 if (0) printf("allocated rwlock %d\n", i);
2139 }
2140 res = __pthread_mutex_unlock(&rw_remap_mx);
2141 assert(res == 0);
2142 vg_rwl = &rw_remap_new[i];
2143
2144 /* Mimic static initialisation of the original. */
2145 if (orig->__rw_readers == 0) {
2146 const vg_rwlock_t default_rwl = VG_RWL_INITIALIZER;
2147 orig->__rw_readers = 1;
2148 *vg_rwl = default_rwl;
2149 vg_rwl->pref_writer = 1;
2150 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
2151 vg_rwl->pref_writer = 0;
2152 }
2153
2154 return vg_rwl;
2155}
2156
2157
2158/*
2159 * rwlock.c
2160 *
2161 * This file implements the "read-write lock" synchronization
2162 * construct.
2163 *
2164 * A read-write lock allows a thread to lock shared data either
2165 * for shared read access or exclusive write access.
2166 *
2167 * The rwl_init() and rwl_destroy() functions, respectively,
2168 * allow you to initialize/create and destroy/free the
2169 * read-write lock.
2170 *
2171 * The rwl_readlock() function locks a read-write lock for
2172 * shared read access, and rwl_readunlock() releases the
2173 * lock. rwl_readtrylock() attempts to lock a read-write lock
2174 * for read access, and returns EBUSY instead of blocking.
2175 *
2176 * The rwl_writelock() function locks a read-write lock for
2177 * exclusive write access, and rwl_writeunlock() releases the
2178 * lock. rwl_writetrylock() attempts to lock a read-write lock
2179 * for write access, and returns EBUSY instead of blocking.
2180 */
2181
2182
2183/*
2184 * Initialize a read-write lock
2185 */
2186static int rwl_init ( vg_rwlock_t *rwl )
2187{
2188 int status;
2189
2190 rwl->r_active = 0;
2191 rwl->r_wait = rwl->w_wait = 0;
2192 rwl->w_active = 0;
2193 status = pthread_mutex_init (&rwl->mutex, NULL);
2194 if (status != 0)
2195 return status;
2196 status = pthread_cond_init (&rwl->read, NULL);
2197 if (status != 0) {
2198 /* if unable to create read CV, destroy mutex */
2199 pthread_mutex_destroy (&rwl->mutex);
2200 return status;
2201 }
2202 status = pthread_cond_init (&rwl->write, NULL);
2203 if (status != 0) {
2204 /* if unable to create write CV, destroy read CV and mutex */
2205 pthread_cond_destroy (&rwl->read);
2206 pthread_mutex_destroy (&rwl->mutex);
2207 return status;
2208 }
2209 rwl->valid = VG_RWLOCK_VALID;
2210 return 0;
2211}
2212
2213/*
2214 * Destroy a read-write lock
2215 */
2216static int rwl_destroy (vg_rwlock_t *rwl)
2217{
2218 int status, status1, status2;
2219
2220 if (rwl->valid != VG_RWLOCK_VALID)
2221 return EINVAL;
2222 status = pthread_mutex_lock (&rwl->mutex);
2223 if (status != 0)
2224 return status;
2225
2226 /*
2227 * Check whether any threads own the lock; report "BUSY" if
2228 * so.
2229 */
2230 if (rwl->r_active > 0 || rwl->w_active) {
2231 pthread_mutex_unlock (&rwl->mutex);
2232 return EBUSY;
2233 }
2234
2235 /*
2236 * Check whether any threads are known to be waiting; report
2237 * EBUSY if so.
2238 */
2239 if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2240 pthread_mutex_unlock (&rwl->mutex);
2241 return EBUSY;
2242 }
2243
2244 rwl->valid = 0;
2245 status = pthread_mutex_unlock (&rwl->mutex);
2246 if (status != 0)
2247 return status;
2248 status = pthread_mutex_destroy (&rwl->mutex);
2249 status1 = pthread_cond_destroy (&rwl->read);
2250 status2 = pthread_cond_destroy (&rwl->write);
2251 return (status != 0 ? status : (status1 != 0 ? status1 : status2));
2252}
2253
2254/*
2255 * Handle cleanup when the read lock condition variable
2256 * wait is cancelled.
2257 *
2258 * Simply record that the thread is no longer waiting,
2259 * and unlock the mutex.
2260 */
2261static void rwl_readcleanup (void *arg)
2262{
2263 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2264
2265 rwl->r_wait--;
2266 pthread_mutex_unlock (&rwl->mutex);
2267}
2268
2269/*
2270 * Lock a read-write lock for read access.
2271 */
2272static int rwl_readlock (vg_rwlock_t *rwl)
2273{
2274 int status;
2275
2276 if (rwl->valid != VG_RWLOCK_VALID)
2277 return EINVAL;
2278 status = pthread_mutex_lock (&rwl->mutex);
2279 if (status != 0)
2280 return status;
2281 if (rwl->w_active) {
2282 rwl->r_wait++;
2283 pthread_cleanup_push (rwl_readcleanup, (void*)rwl);
2284 while (rwl->w_active) {
2285 status = pthread_cond_wait (&rwl->read, &rwl->mutex);
2286 if (status != 0)
2287 break;
2288 }
2289 pthread_cleanup_pop (0);
2290 rwl->r_wait--;
2291 }
2292 if (status == 0)
2293 rwl->r_active++;
2294 pthread_mutex_unlock (&rwl->mutex);
2295 return status;
2296}
2297
2298/*
2299 * Attempt to lock a read-write lock for read access (don't
2300 * block if unavailable).
2301 */
2302static int rwl_readtrylock (vg_rwlock_t *rwl)
2303{
2304 int status, status2;
2305
2306 if (rwl->valid != VG_RWLOCK_VALID)
2307 return EINVAL;
2308 status = pthread_mutex_lock (&rwl->mutex);
2309 if (status != 0)
2310 return status;
2311 if (rwl->w_active)
2312 status = EBUSY;
2313 else
2314 rwl->r_active++;
2315 status2 = pthread_mutex_unlock (&rwl->mutex);
2316 return (status2 != 0 ? status2 : status);
2317}
2318
2319/*
2320 * Handle cleanup when the write lock condition variable
2321 * wait is cancelled.
2322 *
2323 * Simply record that the thread is no longer waiting,
2324 * and unlock the mutex.
2325 */
2326static void rwl_writecleanup (void *arg)
2327{
2328 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2329
2330 rwl->w_wait--;
2331 pthread_mutex_unlock (&rwl->mutex);
2332}
2333
2334/*
2335 * Lock a read-write lock for write access.
2336 */
2337static int rwl_writelock (vg_rwlock_t *rwl)
2338{
2339 int status;
2340
2341 if (rwl->valid != VG_RWLOCK_VALID)
2342 return EINVAL;
2343 status = pthread_mutex_lock (&rwl->mutex);
2344 if (status != 0)
2345 return status;
2346 if (rwl->w_active || rwl->r_active > 0) {
2347 rwl->w_wait++;
2348 pthread_cleanup_push (rwl_writecleanup, (void*)rwl);
2349 while (rwl->w_active || rwl->r_active > 0) {
2350 status = pthread_cond_wait (&rwl->write, &rwl->mutex);
2351 if (status != 0)
2352 break;
2353 }
2354 pthread_cleanup_pop (0);
2355 rwl->w_wait--;
2356 }
2357 if (status == 0)
2358 rwl->w_active = 1;
2359 pthread_mutex_unlock (&rwl->mutex);
2360 return status;
2361}
2362
2363/*
2364 * Attempt to lock a read-write lock for write access. Don't
2365 * block if unavailable.
2366 */
2367static int rwl_writetrylock (vg_rwlock_t *rwl)
2368{
2369 int status, status2;
2370
2371 if (rwl->valid != VG_RWLOCK_VALID)
2372 return EINVAL;
2373 status = pthread_mutex_lock (&rwl->mutex);
2374 if (status != 0)
2375 return status;
2376 if (rwl->w_active || rwl->r_active > 0)
2377 status = EBUSY;
2378 else
2379 rwl->w_active = 1;
2380 status2 = pthread_mutex_unlock (&rwl->mutex);
2381 return (status != 0 ? status : status2);
2382}
2383
2384/*
2385 * Unlock a read-write lock, using the r_active and w_active fields to
2386 * decide whether we're in a read or write lock.
2387 */
2388static int rwl_unlock (vg_rwlock_t *rwl)
2389{
2390 int status, status2;
2391
2392 if (rwl->valid != VG_RWLOCK_VALID)
2393 return EINVAL;
2394 status = pthread_mutex_lock (&rwl->mutex);
2395 if (status != 0)
2396 return status;
2397
2398 if (rwl->r_active > 0) {
2399
2400 /* READ case */
2401 assert(!rwl->w_active);
2402 rwl->r_active--;
2403 if (rwl->r_active == 0 && rwl->w_wait > 0)
2404 status = pthread_cond_signal (&rwl->write);
2405 /* END READ case */
2406
2407 } else {
2408
2409 /* WRITE case */
2410 assert(rwl->w_active);
2411 assert(rwl->r_active == 0);
2412 rwl->w_active = 0;
2413
2414 if (rwl->pref_writer) {
2415 /* Do writer-preference wakeups. */
2416 if (rwl->w_wait > 0) {
2417 status = pthread_cond_signal (&rwl->write);
2418 if (status != 0) {
2419 pthread_mutex_unlock (&rwl->mutex);
2420 return status;
2421 }
2422 } else if (rwl->r_wait > 0) {
2423 status = pthread_cond_broadcast (&rwl->read);
2424 if (status != 0) {
2425 pthread_mutex_unlock (&rwl->mutex);
2426 return status;
2427 }
2428 }
2429 } else {
2430 /* Do reader-preference wakeups. */
2431 if (rwl->r_wait > 0) {
2432 status = pthread_cond_broadcast (&rwl->read);
2433 if (status != 0) {
2434 pthread_mutex_unlock (&rwl->mutex);
2435 return status;
2436 }
2437 } else if (rwl->w_wait > 0) {
2438 status = pthread_cond_signal (&rwl->write);
2439 if (status != 0) {
2440 pthread_mutex_unlock (&rwl->mutex);
2441 return status;
2442 }
2443 }
2444 }
2445 /* END WRITE case */
2446
2447 }
2448
2449 status2 = pthread_mutex_unlock (&rwl->mutex);
2450 return (status2 == 0 ? status : status2);
2451}
2452
2453/* -------------------------------- */
2454
2455int pthread_rwlock_init ( pthread_rwlock_t* orig,
2456 const pthread_rwlockattr_t* attr )
2457{
2458 int res;
2459 vg_rwlock_t* rwl;
2460 if (0) printf ("pthread_rwlock_init\n");
2461 /* Force the remapper to initialise the shadow. */
2462 orig->__rw_readers = 0;
2463 /* Install the lock preference; the remapper needs to know it. */
2464 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2465 if (attr)
2466 orig->__rw_kind = attr->__lockkind;
2467 rwl = rw_remap ( orig );
2468 res = rwl_init ( rwl );
2469 return res;
2470}
2471
2472int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2473{
2474 int res;
2475 vg_rwlock_t* rwl;
2476 if (0) printf ("pthread_rwlock_destroy\n");
2477 rwl = rw_remap ( orig );
2478 res = rwl_destroy ( rwl );
2479 return res;
2480}
2481
2482int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2483{
2484 int res;
2485 vg_rwlock_t* rwl;
2486 if (0) printf ("pthread_rwlock_rdlock\n");
2487 rwl = rw_remap ( orig );
2488 res = rwl_readlock ( rwl );
2489 return res;
2490}
2491
2492int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2493{
2494 int res;
2495 vg_rwlock_t* rwl;
2496 if (0) printf ("pthread_rwlock_tryrdlock\n");
2497 rwl = rw_remap ( orig );
2498 res = rwl_readtrylock ( rwl );
2499 return res;
2500}
2501
2502int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2503{
2504 int res;
2505 vg_rwlock_t* rwl;
2506 if (0) printf ("pthread_rwlock_wrlock\n");
2507 rwl = rw_remap ( orig );
2508 res = rwl_writelock ( rwl );
2509 return res;
2510}
2511
2512int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2513{
2514 int res;
2515 vg_rwlock_t* rwl;
2516 if (0) printf ("pthread_rwlock_trywrlock\n");
2517 rwl = rw_remap ( orig );
2518 res = rwl_writetrylock ( rwl );
2519 return res;
2520}
2521
2522int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2523{
2524 int res;
2525 vg_rwlock_t* rwl;
2526 if (0) printf ("pthread_rwlock_unlock\n");
2527 rwl = rw_remap ( orig );
2528 res = rwl_unlock ( rwl );
2529 return res;
2530}
2531
2532
2533/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002534 B'stard.
2535 ------------------------------------------------------------------ */
2536
2537# define strong_alias(name, aliasname) \
2538 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2539
sewardj5905fae2002-04-26 13:25:00 +00002540# define weak_alias(name, aliasname) \
2541 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002542
sewardj5905fae2002-04-26 13:25:00 +00002543strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2544strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2545strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2546strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2547 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2548strong_alias(__pthread_mutex_init, pthread_mutex_init)
2549strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2550strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2551strong_alias(__pthread_once, pthread_once)
2552strong_alias(__pthread_atfork, pthread_atfork)
2553strong_alias(__pthread_key_create, pthread_key_create)
2554strong_alias(__pthread_getspecific, pthread_getspecific)
2555strong_alias(__pthread_setspecific, pthread_setspecific)
2556
sewardjd529a442002-05-04 19:49:21 +00002557#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002558strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002559#endif
2560
sewardj5905fae2002-04-26 13:25:00 +00002561strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002562strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002563strong_alias(lseek, __lseek)
2564strong_alias(open, __open)
2565strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002566strong_alias(read, __read)
2567strong_alias(wait, __wait)
2568strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002569strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002570strong_alias(send, __send)
2571
sewardj726c4122002-05-16 23:39:10 +00002572weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002573weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002574weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002575
sewardj5905fae2002-04-26 13:25:00 +00002576
sewardj3b13f0e2002-04-25 20:17:29 +00002577
2578/*--------------------------------------------------*/
2579
sewardj5905fae2002-04-26 13:25:00 +00002580weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002581weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002582weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002583
sewardja1ac5cb2002-05-27 13:00:05 +00002584weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2585weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2586weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2587weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2588
sewardj060b04f2002-04-26 21:01:13 +00002589
sewardj3b13f0e2002-04-25 20:17:29 +00002590/* I've no idea what these are, but they get called quite a lot.
2591 Anybody know? */
2592
2593#undef _IO_flockfile
2594void _IO_flockfile ( _IO_FILE * file )
2595{
sewardj853f55d2002-04-26 00:27:53 +00002596 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002597}
sewardj5905fae2002-04-26 13:25:00 +00002598weak_alias(_IO_flockfile, flockfile);
2599
sewardj3b13f0e2002-04-25 20:17:29 +00002600
2601#undef _IO_funlockfile
2602void _IO_funlockfile ( _IO_FILE * file )
2603{
sewardj853f55d2002-04-26 00:27:53 +00002604 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002605}
sewardj5905fae2002-04-26 13:25:00 +00002606weak_alias(_IO_funlockfile, funlockfile);
2607
sewardj3b13f0e2002-04-25 20:17:29 +00002608
sewardjd4f2c712002-04-30 10:20:10 +00002609/* This doesn't seem to be needed to simulate libpthread.so's external
2610 interface, but many people complain about its absence. */
2611
2612strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2613weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002614
2615
2616/*--------------------------------------------------------------------*/
2617/*--- end vg_libpthread.c ---*/
2618/*--------------------------------------------------------------------*/