blob: 8d5ef2f368dad6c059c684792f0ac5ed6d75434b [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));
801 assert(ull_ms_end_after_1970 >= ull_ms_now_after_1970);
802 ms_end
803 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
804 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
805 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
806 cond, mutex, ms_end, 0);
807 return res;
808}
809
810
sewardj3b5d8862002-04-20 13:53:23 +0000811int pthread_cond_signal(pthread_cond_t *cond)
812{
813 int res;
814 ensure_valgrind("pthread_cond_signal");
815 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
816 VG_USERREQ__PTHREAD_COND_SIGNAL,
817 cond, 0, 0, 0);
818 return res;
819}
820
821int pthread_cond_broadcast(pthread_cond_t *cond)
822{
823 int res;
824 ensure_valgrind("pthread_cond_broadcast");
825 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
826 VG_USERREQ__PTHREAD_COND_BROADCAST,
827 cond, 0, 0, 0);
828 return res;
829}
830
sewardj6072c362002-04-19 14:40:57 +0000831
832/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000833 CANCELLATION
834 ------------------------------------------------ */
835
sewardj853f55d2002-04-26 00:27:53 +0000836int pthread_setcancelstate(int state, int *oldstate)
837{
sewardj20917d82002-05-28 01:36:45 +0000838 int res;
839 ensure_valgrind("pthread_setcancelstate");
840 if (state != PTHREAD_CANCEL_ENABLE
841 && state != PTHREAD_CANCEL_DISABLE)
842 return EINVAL;
843 assert(-1 != PTHREAD_CANCEL_ENABLE);
844 assert(-1 != PTHREAD_CANCEL_DISABLE);
845 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
846 VG_USERREQ__SET_CANCELSTATE,
847 state, 0, 0, 0);
848 assert(res != -1);
849 if (oldstate)
850 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +0000851 return 0;
852}
853
sewardje663cb92002-04-12 10:26:32 +0000854int pthread_setcanceltype(int type, int *oldtype)
855{
sewardj20917d82002-05-28 01:36:45 +0000856 int res;
857 ensure_valgrind("pthread_setcanceltype");
858 if (type != PTHREAD_CANCEL_DEFERRED
859 && type != PTHREAD_CANCEL_ASYNCHRONOUS)
860 return EINVAL;
861 assert(-1 != PTHREAD_CANCEL_DEFERRED);
862 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
863 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
864 VG_USERREQ__SET_CANCELTYPE,
865 type, 0, 0, 0);
866 assert(res != -1);
867 if (oldtype)
868 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +0000869 return 0;
870}
871
sewardje663cb92002-04-12 10:26:32 +0000872int pthread_cancel(pthread_t thread)
873{
874 int res;
875 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +0000876 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
877 VG_USERREQ__SET_CANCELPEND,
878 thread, &thread_exit_wrapper, 0, 0);
879 assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +0000880 return res;
881}
882
sewardjd140e442002-05-29 01:21:19 +0000883static __inline__
884void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +0000885{
sewardj20917d82002-05-28 01:36:45 +0000886 int res;
887 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
888 VG_USERREQ__TESTCANCEL,
889 0, 0, 0, 0);
890 assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +0000891}
892
sewardjd140e442002-05-29 01:21:19 +0000893void pthread_testcancel ( void )
894{
895 __my_pthread_testcancel();
896}
897
sewardj20917d82002-05-28 01:36:45 +0000898
sewardj853f55d2002-04-26 00:27:53 +0000899/*-------------------*/
sewardjccef2e62002-05-29 19:26:32 +0000900/* If this is indeed used by LinuxThreads to implement thread nuking
901 post fork and pre exec, we should really nuke em, not do
902 pthread_cancel. */
sewardj853f55d2002-04-26 00:27:53 +0000903static pthread_mutex_t massacre_mx = PTHREAD_MUTEX_INITIALIZER;
904
905void __pthread_kill_other_threads_np ( void )
906{
907 int i, res, me;
sewardj68b2dd92002-05-10 21:03:56 +0000908 __pthread_mutex_lock(&massacre_mx);
sewardj853f55d2002-04-26 00:27:53 +0000909 me = pthread_self();
910 for (i = 1; i < VG_N_THREADS; i++) {
911 if (i == me) continue;
912 res = pthread_cancel(i);
sewardj436e0582002-04-26 14:31:40 +0000913 if (0 && res == 0)
sewardj853f55d2002-04-26 00:27:53 +0000914 printf("----------- NUKED %d\n", i);
915 }
sewardj68b2dd92002-05-10 21:03:56 +0000916 __pthread_mutex_unlock(&massacre_mx);
sewardj853f55d2002-04-26 00:27:53 +0000917}
918
sewardje663cb92002-04-12 10:26:32 +0000919
sewardjf8f819e2002-04-17 23:21:37 +0000920/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +0000921 SIGNALS
922 ------------------------------------------------ */
923
924#include <signal.h>
925
926int pthread_sigmask(int how, const sigset_t *newmask,
927 sigset_t *oldmask)
928{
929 int res;
930
931 /* A bit subtle, because the scheduler expects newmask and oldmask
932 to be vki_sigset_t* rather than sigset_t*, and the two are
933 different. Fortunately the first 64 bits of a sigset_t are
934 exactly a vki_sigset_t, so we just pass the pointers through
935 unmodified. Haaaack!
936
937 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +0000938 constants to VKI_ constants, so that the former do not have to
939 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +0000940
941 ensure_valgrind("pthread_sigmask");
942
943 switch (how) {
sewardj018f7622002-05-15 21:13:39 +0000944 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
945 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
946 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardjb48e5002002-05-13 00:16:03 +0000947 default: return EINVAL;
948 }
949
950 /* Crude check */
951 if (newmask == NULL)
952 return EFAULT;
953
954 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
955 VG_USERREQ__PTHREAD_SIGMASK,
956 how, newmask, oldmask, 0);
957
958 /* The scheduler tells us of any memory violations. */
959 return res == 0 ? 0 : EFAULT;
960}
961
962
963int sigwait ( const sigset_t* set, int* sig )
964{
965 int res;
966 ensure_valgrind("sigwait");
967 /* As with pthread_sigmask we deliberately confuse sigset_t with
968 vki_ksigset_t. */
969 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
970 VG_USERREQ__SIGWAIT,
971 set, sig, 0, 0);
972 return res;
973}
974
975
sewardj018f7622002-05-15 21:13:39 +0000976int pthread_kill(pthread_t thread, int signo)
977{
978 int res;
979 ensure_valgrind("pthread_kill");
980 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
981 VG_USERREQ__PTHREAD_KILL,
982 thread, signo, 0, 0);
983 return res;
984}
985
986
sewardj3665ded2002-05-16 16:57:25 +0000987/* Copied verbatim from Linuxthreads */
988/* Redefine raise() to send signal to calling thread only,
989 as per POSIX 1003.1c */
990int raise (int sig)
991{
992 int retcode = pthread_kill(pthread_self(), sig);
993 if (retcode == 0)
994 return 0;
995 else {
996 errno = retcode;
997 return -1;
998 }
999}
1000
1001
sewardjb48e5002002-05-13 00:16:03 +00001002/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001003 THREAD-SPECIFICs
1004 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001005
sewardj5905fae2002-04-26 13:25:00 +00001006int __pthread_key_create(pthread_key_t *key,
1007 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001008{
sewardj5f07b662002-04-23 16:52:51 +00001009 int res;
1010 ensure_valgrind("pthread_key_create");
1011 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1012 VG_USERREQ__PTHREAD_KEY_CREATE,
1013 key, destr_function, 0, 0);
1014 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001015}
1016
1017int pthread_key_delete(pthread_key_t key)
1018{
sewardj436e0582002-04-26 14:31:40 +00001019 static int moans = N_MOANS;
1020 if (moans-- > 0)
1021 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +00001022 return 0;
1023}
1024
sewardj5905fae2002-04-26 13:25:00 +00001025int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001026{
sewardj5f07b662002-04-23 16:52:51 +00001027 int res;
1028 ensure_valgrind("pthread_setspecific");
1029 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1030 VG_USERREQ__PTHREAD_SETSPECIFIC,
1031 key, pointer, 0, 0);
1032 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001033}
1034
sewardj5905fae2002-04-26 13:25:00 +00001035void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001036{
sewardj5f07b662002-04-23 16:52:51 +00001037 int res;
1038 ensure_valgrind("pthread_getspecific");
1039 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1040 VG_USERREQ__PTHREAD_GETSPECIFIC,
1041 key, 0 , 0, 0);
1042 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001043}
1044
sewardjf8f819e2002-04-17 23:21:37 +00001045
1046/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001047 ONCEry
1048 ------------------------------------------------ */
1049
1050static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1051
1052
sewardj5905fae2002-04-26 13:25:00 +00001053int __pthread_once ( pthread_once_t *once_control,
1054 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001055{
1056 int res;
1057 ensure_valgrind("pthread_once");
1058
sewardj68b2dd92002-05-10 21:03:56 +00001059 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001060
sewardj68b2dd92002-05-10 21:03:56 +00001061 if (res != 0) {
1062 printf("res = %d\n",res);
sewardj89d3d852002-04-24 19:21:39 +00001063 barf("pthread_once: Looks like your program's "
1064 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001065 }
sewardj89d3d852002-04-24 19:21:39 +00001066
1067 if (*once_control == 0) {
1068 *once_control = 1;
1069 init_routine();
1070 }
1071
sewardj68b2dd92002-05-10 21:03:56 +00001072 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001073
1074 return 0;
1075}
1076
1077
1078/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001079 MISC
1080 ------------------------------------------------ */
1081
sewardj5905fae2002-04-26 13:25:00 +00001082int __pthread_atfork ( void (*prepare)(void),
1083 void (*parent)(void),
1084 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001085{
sewardjccef2e62002-05-29 19:26:32 +00001086 /* We have to do this properly or not at all; faking it isn't an
1087 option. */
1088 vgPlain_unimp("__pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +00001089}
1090
1091
sewardjbb990782002-05-08 02:01:14 +00001092__attribute__((weak))
1093void __pthread_initialize ( void )
1094{
sewardjbea1caa2002-05-10 23:20:58 +00001095 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001096}
1097
1098
sewardj853f55d2002-04-26 00:27:53 +00001099/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001100 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001101 ------------------------------------------------ */
1102
sewardj3b13f0e2002-04-25 20:17:29 +00001103#include <resolv.h>
1104static int thread_specific_errno[VG_N_THREADS];
1105static int thread_specific_h_errno[VG_N_THREADS];
1106static struct __res_state
1107 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001108
sewardj3b13f0e2002-04-25 20:17:29 +00001109int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001110{
1111 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001112 /* ensure_valgrind("__errno_location"); */
1113 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001114 VG_USERREQ__PTHREAD_GET_THREADID,
1115 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001116 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001117 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001118 barf("__errno_location: invalid ThreadId");
1119 return & thread_specific_errno[tid];
1120}
1121
1122int* __h_errno_location ( void )
1123{
1124 int tid;
1125 /* ensure_valgrind("__h_errno_location"); */
1126 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1127 VG_USERREQ__PTHREAD_GET_THREADID,
1128 0, 0, 0, 0);
1129 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001130 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001131 barf("__h_errno_location: invalid ThreadId");
1132 return & thread_specific_h_errno[tid];
1133}
1134
1135struct __res_state* __res_state ( void )
1136{
1137 int tid;
1138 /* ensure_valgrind("__res_state"); */
1139 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1140 VG_USERREQ__PTHREAD_GET_THREADID,
1141 0, 0, 0, 0);
1142 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001143 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001144 barf("__res_state: invalid ThreadId");
1145 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001146}
1147
1148
sewardj5716dbb2002-04-26 03:28:18 +00001149/* ---------------------------------------------------
1150 LIBC-PRIVATE SPECIFIC DATA
1151 ------------------------------------------------ */
1152
1153/* Relies on assumption that initial private data is NULL. This
1154 should be fixed somehow. */
1155
1156/* The allowable keys (indices) (all 2 of them).
1157 From sysdeps/pthread/bits/libc-tsd.h
1158*/
sewardj70adeb22002-04-27 01:35:38 +00001159#define N_LIBC_TSD_EXTRA_KEYS 1
1160
sewardj5716dbb2002-04-26 03:28:18 +00001161enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1162 _LIBC_TSD_KEY_DL_ERROR,
1163 _LIBC_TSD_KEY_N };
1164
1165/* Auto-initialising subsystem. libc_specifics_inited is set
1166 after initialisation. libc_specifics_inited_mx guards it. */
1167static int libc_specifics_inited = 0;
1168static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1169
1170/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001171static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1172 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001173
1174/* Initialise the keys, if they are not already initialise. */
1175static
1176void init_libc_tsd_keys ( void )
1177{
1178 int res, i;
1179 pthread_key_t k;
1180
1181 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1182 if (res != 0) barf("init_libc_tsd_keys: lock");
1183
1184 if (libc_specifics_inited == 0) {
1185 /* printf("INIT libc specifics\n"); */
1186 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001187 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001188 res = pthread_key_create(&k, NULL);
1189 if (res != 0) barf("init_libc_tsd_keys: create");
1190 libc_specifics_keys[i] = k;
1191 }
1192 }
1193
1194 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1195 if (res != 0) barf("init_libc_tsd_keys: unlock");
1196}
1197
1198
1199static int
1200libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1201 const void * pointer )
1202{
sewardj70adeb22002-04-27 01:35:38 +00001203 int res;
1204 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001205 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001206 if (key < _LIBC_TSD_KEY_MALLOC
1207 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001208 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001209 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1210 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001211 "valgrind's libpthread.so: libc_internal_tsd_set: "
1212 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001213 init_libc_tsd_keys();
1214 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1215 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1216 return 0;
1217}
1218
1219static void *
1220libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1221{
sewardj70adeb22002-04-27 01:35:38 +00001222 void* v;
1223 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001224 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001225 if (key < _LIBC_TSD_KEY_MALLOC
1226 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001227 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001228 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1229 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001230 "valgrind's libpthread.so: libc_internal_tsd_get: "
1231 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001232 init_libc_tsd_keys();
1233 v = pthread_getspecific(libc_specifics_keys[key]);
1234 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1235 return v;
1236}
1237
1238
1239
1240
sewardj70adeb22002-04-27 01:35:38 +00001241int (*__libc_internal_tsd_set)
1242 (enum __libc_tsd_key_t key, const void * pointer)
1243 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001244
sewardj70adeb22002-04-27 01:35:38 +00001245void* (*__libc_internal_tsd_get)
1246 (enum __libc_tsd_key_t key)
1247 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001248
1249
sewardje663cb92002-04-12 10:26:32 +00001250/* ---------------------------------------------------------------------
1251 These are here (I think) because they are deemed cancellation
1252 points by POSIX. For the moment we'll simply pass the call along
1253 to the corresponding thread-unaware (?) libc routine.
1254 ------------------------------------------------------------------ */
1255
sewardje663cb92002-04-12 10:26:32 +00001256#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001257#include <sys/types.h>
1258#include <sys/socket.h>
1259
sewardjd529a442002-05-04 19:49:21 +00001260#ifdef GLIBC_2_1
1261extern
1262int __sigaction
1263 (int signum,
1264 const struct sigaction *act,
1265 struct sigaction *oldact);
1266#else
sewardje663cb92002-04-12 10:26:32 +00001267extern
1268int __libc_sigaction
1269 (int signum,
1270 const struct sigaction *act,
1271 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001272#endif
sewardje663cb92002-04-12 10:26:32 +00001273int sigaction(int signum,
1274 const struct sigaction *act,
1275 struct sigaction *oldact)
1276{
sewardjd140e442002-05-29 01:21:19 +00001277 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001278# ifdef GLIBC_2_1
1279 return __sigaction(signum, act, oldact);
1280# else
sewardj45b4b372002-04-16 22:50:32 +00001281 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001282# endif
sewardje663cb92002-04-12 10:26:32 +00001283}
1284
1285
1286extern
1287int __libc_connect(int sockfd,
1288 const struct sockaddr *serv_addr,
1289 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001290__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001291int connect(int sockfd,
1292 const struct sockaddr *serv_addr,
1293 socklen_t addrlen)
1294{
sewardjd140e442002-05-29 01:21:19 +00001295 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001296 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001297}
1298
1299
1300extern
1301int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001302__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001303int fcntl(int fd, int cmd, long arg)
1304{
sewardjd140e442002-05-29 01:21:19 +00001305 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001306 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001307}
1308
1309
1310extern
1311ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001312__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001313ssize_t write(int fd, const void *buf, size_t count)
1314{
sewardjd140e442002-05-29 01:21:19 +00001315 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001316 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001317}
1318
1319
1320extern
1321ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001322__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001323ssize_t read(int fd, void *buf, size_t count)
1324{
sewardjd140e442002-05-29 01:21:19 +00001325 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001326 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001327}
1328
sewardjbe32e452002-04-24 20:29:58 +00001329
1330extern
sewardj853f55d2002-04-26 00:27:53 +00001331int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001332__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001333int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001334{
sewardjd140e442002-05-29 01:21:19 +00001335 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001336 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001337}
1338
sewardje663cb92002-04-12 10:26:32 +00001339
1340extern
sewardj853f55d2002-04-26 00:27:53 +00001341int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001342__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001343int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001344{
sewardjd140e442002-05-29 01:21:19 +00001345 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001346 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001347}
1348
1349
1350extern
1351int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001352__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001353int close(int fd)
1354{
sewardjd140e442002-05-29 01:21:19 +00001355 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001356 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001357}
1358
1359
1360extern
1361int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001362__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001363int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1364{
sewardjd140e442002-05-29 01:21:19 +00001365 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001366 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001367 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001368 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001369}
1370
1371
1372extern
1373pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001374pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001375{
sewardjd140e442002-05-29 01:21:19 +00001376 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001377 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001378}
1379
1380
1381extern
1382pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001383__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001384pid_t waitpid(pid_t pid, int *status, int options)
1385{
sewardjd140e442002-05-29 01:21:19 +00001386 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001387 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001388}
1389
1390
1391extern
1392int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001393__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001394int nanosleep(const struct timespec *req, struct timespec *rem)
1395{
sewardjd140e442002-05-29 01:21:19 +00001396 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001397 return __libc_nanosleep(req, rem);
1398}
1399
sewardjbe32e452002-04-24 20:29:58 +00001400
sewardje663cb92002-04-12 10:26:32 +00001401extern
1402int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001403__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001404int fsync(int fd)
1405{
sewardjd140e442002-05-29 01:21:19 +00001406 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001407 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001408}
1409
sewardjbe32e452002-04-24 20:29:58 +00001410
sewardj70c75362002-04-13 04:18:32 +00001411extern
1412off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001413__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001414off_t lseek(int fildes, off_t offset, int whence)
1415{
sewardjd140e442002-05-29 01:21:19 +00001416 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001417 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001418}
1419
sewardjbe32e452002-04-24 20:29:58 +00001420
1421extern
1422__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001423__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001424__off64_t lseek64(int fildes, __off64_t offset, int whence)
1425{
sewardjd140e442002-05-29 01:21:19 +00001426 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001427 return __libc_lseek64(fildes, offset, whence);
1428}
1429
1430
sewardj726c4122002-05-16 23:39:10 +00001431extern
1432ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1433 __off64_t __offset);
1434ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1435 __off64_t __offset)
1436{
sewardjd140e442002-05-29 01:21:19 +00001437 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001438 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1439}
1440
1441
sewardja18e2102002-05-18 10:43:22 +00001442extern
1443ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1444 __off64_t __offset);
1445ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1446 __off64_t __offset)
1447{
sewardjd140e442002-05-29 01:21:19 +00001448 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001449 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1450}
1451
sewardj726c4122002-05-16 23:39:10 +00001452
sewardj39b93b12002-05-18 10:56:27 +00001453extern
1454ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1455__attribute__((weak))
1456ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1457{
sewardjd140e442002-05-29 01:21:19 +00001458 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001459 return __libc_pwrite(fd, buf, count, offset);
1460}
1461
1462
1463extern
1464ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1465__attribute__((weak))
1466ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1467{
sewardjd140e442002-05-29 01:21:19 +00001468 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001469 return __libc_pread(fd, buf, count, offset);
1470}
1471
1472
sewardj6af4b5d2002-04-16 04:40:49 +00001473extern
1474void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001475/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001476void longjmp(jmp_buf env, int val)
1477{
sewardjd140e442002-05-29 01:21:19 +00001478 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001479 __libc_longjmp(env, val);
1480}
1481
sewardjbe32e452002-04-24 20:29:58 +00001482
sewardj6af4b5d2002-04-16 04:40:49 +00001483extern
1484int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001485__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001486int send(int s, const void *msg, size_t len, int flags)
1487{
sewardjd140e442002-05-29 01:21:19 +00001488 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001489 return __libc_send(s, msg, len, flags);
1490}
1491
sewardjbe32e452002-04-24 20:29:58 +00001492
sewardj1e8cdc92002-04-18 11:37:52 +00001493extern
1494int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001495__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001496int recv(int s, void *buf, size_t len, int flags)
1497{
sewardjd140e442002-05-29 01:21:19 +00001498 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001499 return __libc_recv(s, buf, len, flags);
1500}
1501
sewardjbe32e452002-04-24 20:29:58 +00001502
sewardj3665ded2002-05-16 16:57:25 +00001503extern
1504int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1505__attribute__((weak))
1506int sendmsg(int s, const struct msghdr *msg, int flags)
1507{
sewardjd140e442002-05-29 01:21:19 +00001508 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001509 return __libc_sendmsg(s, msg, flags);
1510}
1511
1512
sewardj796d6a22002-04-24 02:28:34 +00001513extern
sewardj436e0582002-04-26 14:31:40 +00001514int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1515 struct sockaddr *from, socklen_t *fromlen);
1516__attribute__((weak))
1517int recvfrom(int s, void *buf, size_t len, int flags,
1518 struct sockaddr *from, socklen_t *fromlen)
1519{
sewardjd140e442002-05-29 01:21:19 +00001520 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001521 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1522}
1523
1524
1525extern
sewardj796d6a22002-04-24 02:28:34 +00001526int __libc_sendto(int s, const void *msg, size_t len, int flags,
1527 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001528__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001529int sendto(int s, const void *msg, size_t len, int flags,
1530 const struct sockaddr *to, socklen_t tolen)
1531{
sewardjd140e442002-05-29 01:21:19 +00001532 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001533 return __libc_sendto(s, msg, len, flags, to, tolen);
1534}
1535
sewardjbe32e452002-04-24 20:29:58 +00001536
sewardj369b1702002-04-24 13:28:15 +00001537extern
1538int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001539__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001540int system(const char* str)
1541{
sewardjd140e442002-05-29 01:21:19 +00001542 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001543 return __libc_system(str);
1544}
1545
sewardjbe32e452002-04-24 20:29:58 +00001546
sewardjab0b1c32002-04-24 19:26:47 +00001547extern
1548pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001549__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001550pid_t wait(int *status)
1551{
sewardjd140e442002-05-29 01:21:19 +00001552 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00001553 return __libc_wait(status);
1554}
1555
sewardj45b4b372002-04-16 22:50:32 +00001556
sewardj67f1d582002-05-24 02:11:32 +00001557extern
1558int __libc_msync(const void *start, size_t length, int flags);
1559__attribute__((weak))
1560int msync(const void *start, size_t length, int flags)
1561{
sewardjd140e442002-05-29 01:21:19 +00001562 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00001563 return __libc_msync(start, length, flags);
1564}
1565
sewardj5905fae2002-04-26 13:25:00 +00001566
sewardj3b13f0e2002-04-25 20:17:29 +00001567/* ---------------------------------------------------------------------
1568 Nonblocking implementations of select() and poll(). This stuff will
1569 surely rot your mind.
1570 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001571
sewardj08a4c3f2002-04-13 03:45:44 +00001572/*--------------------------------------------------*/
1573
1574#include "vg_kerneliface.h"
1575
1576static
1577__inline__
1578int is_kerror ( int res )
1579{
1580 if (res >= -4095 && res <= -1)
1581 return 1;
1582 else
1583 return 0;
1584}
1585
1586
1587static
1588int my_do_syscall1 ( int syscallno, int arg1 )
1589{
1590 int __res;
1591 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1592 : "=a" (__res)
1593 : "0" (syscallno),
1594 "d" (arg1) );
1595 return __res;
1596}
1597
1598static
1599int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001600 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001601{
1602 int __res;
1603 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1604 : "=a" (__res)
1605 : "0" (syscallno),
1606 "d" (arg1),
1607 "c" (arg2) );
1608 return __res;
1609}
1610
1611static
sewardjf854f472002-04-21 12:19:41 +00001612int my_do_syscall3 ( int syscallno,
1613 int arg1, int arg2, int arg3 )
1614{
1615 int __res;
1616 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1617 : "=a" (__res)
1618 : "0" (syscallno),
1619 "S" (arg1),
1620 "c" (arg2),
1621 "d" (arg3) );
1622 return __res;
1623}
1624
1625static
sewardj08a4c3f2002-04-13 03:45:44 +00001626int do_syscall_select( int n,
1627 vki_fd_set* readfds,
1628 vki_fd_set* writefds,
1629 vki_fd_set* exceptfds,
1630 struct vki_timeval * timeout )
1631{
1632 int res;
1633 int args[5];
1634 args[0] = n;
1635 args[1] = (int)readfds;
1636 args[2] = (int)writefds;
1637 args[3] = (int)exceptfds;
1638 args[4] = (int)timeout;
1639 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001640 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001641}
1642
1643
1644/* This is a wrapper round select(), which makes it thread-safe,
1645 meaning that only this thread will block, rather than the entire
1646 process. This wrapper in turn depends on nanosleep() not to block
1647 the entire process, but I think (hope? suspect?) that POSIX
1648 pthreads guarantees that to be the case.
1649
1650 Basic idea is: modify the timeout parameter to select so that it
1651 returns immediately. Poll like this until select returns non-zero,
1652 indicating something interesting happened, or until our time is up.
1653 Space out the polls with nanosleeps of say 20 milliseconds, which
1654 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001655
1656 Assumes:
1657 * (checked via assert) types fd_set and vki_fd_set are identical.
1658 * (checked via assert) types timeval and vki_timeval are identical.
1659 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1660 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001661*/
sewardj08a4c3f2002-04-13 03:45:44 +00001662
sewardj5905fae2002-04-26 13:25:00 +00001663/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001664int select ( int n,
1665 fd_set *rfds,
1666 fd_set *wfds,
1667 fd_set *xfds,
1668 struct timeval *timeout )
1669{
sewardj5f07b662002-04-23 16:52:51 +00001670 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001671 int res;
1672 fd_set rfds_copy;
1673 fd_set wfds_copy;
1674 fd_set xfds_copy;
1675 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001676 struct vki_timeval zero_timeout;
1677 struct vki_timespec nanosleep_interval;
1678
sewardjd140e442002-05-29 01:21:19 +00001679 __my_pthread_testcancel();
1680
sewardj5f07b662002-04-23 16:52:51 +00001681 /* gcc's complains about ms_end being used uninitialised -- classic
1682 case it can't understand, where ms_end is both defined and used
1683 only if timeout != NULL. Hence ... */
1684 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001685
1686 /* We assume that the kernel and libc data layouts are identical
1687 for the following types. These asserts provide a crude
1688 check. */
1689 if (sizeof(fd_set) != sizeof(vki_fd_set)
1690 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1691 barf("valgrind's hacky non-blocking select(): data sizes error");
1692
sewardj5f07b662002-04-23 16:52:51 +00001693 /* Detect the current time and simultaneously find out if we are
1694 running on Valgrind. */
1695 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1696 VG_USERREQ__READ_MILLISECOND_TIMER,
1697 0, 0, 0, 0);
1698
1699 /* If a zero timeout specified, this call is harmless. Also go
1700 this route if we're not running on Valgrind, for whatever
1701 reason. */
1702 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1703 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001704 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001705 (vki_fd_set*)wfds,
1706 (vki_fd_set*)xfds,
1707 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001708 if (is_kerror(res)) {
1709 * (__errno_location()) = -res;
1710 return -1;
1711 } else {
1712 return res;
1713 }
1714 }
sewardj08a4c3f2002-04-13 03:45:44 +00001715
sewardj5f07b662002-04-23 16:52:51 +00001716 /* If a timeout was specified, set ms_end to be the end millisecond
1717 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001718 if (timeout) {
1719 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
1720 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001721 ms_end = ms_now;
1722 ms_end += (timeout->tv_usec / 1000);
1723 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001724 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +00001725 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001726 }
1727
1728 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1729
1730 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001731 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001732 while (1) {
1733 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +00001734 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1735 VG_USERREQ__READ_MILLISECOND_TIMER,
1736 0, 0, 0, 0);
1737 assert(ms_now != 0xFFFFFFFF);
1738 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +00001739 /* timeout; nothing interesting happened. */
1740 if (rfds) FD_ZERO(rfds);
1741 if (wfds) FD_ZERO(wfds);
1742 if (xfds) FD_ZERO(xfds);
1743 return 0;
1744 }
1745 }
1746
1747 /* These could be trashed each time round the loop, so restore
1748 them each time. */
1749 if (rfds) rfds_copy = *rfds;
1750 if (wfds) wfds_copy = *wfds;
1751 if (xfds) xfds_copy = *xfds;
1752
1753 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1754
1755 res = do_syscall_select( n,
1756 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1757 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1758 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1759 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001760 if (is_kerror(res)) {
1761 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001762 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001763 * (__errno_location()) = -res;
1764 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001765 }
1766 if (res > 0) {
1767 /* one or more fds is ready. Copy out resulting sets and
1768 return. */
1769 if (rfds) *rfds = rfds_copy;
1770 if (wfds) *wfds = wfds_copy;
1771 if (xfds) *xfds = xfds_copy;
1772 return res;
1773 }
1774 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1775 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001776 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001777 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001778 /* It's critical here that valgrind's nanosleep implementation
1779 is nonblocking. */
1780 (void)my_do_syscall2(__NR_nanosleep,
1781 (int)(&nanosleep_interval), (int)NULL);
1782 }
1783}
1784
1785
1786
1787
1788#include <sys/poll.h>
1789
sewardj72d58482002-04-24 02:20:20 +00001790#ifdef GLIBC_2_1
1791typedef unsigned long int nfds_t;
1792#endif
1793
sewardj705d3cb2002-05-23 13:13:12 +00001794
sewardj5905fae2002-04-26 13:25:00 +00001795/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00001796int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1797{
sewardj5f07b662002-04-23 16:52:51 +00001798 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001799 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001800 struct vki_timespec nanosleep_interval;
1801
sewardjd140e442002-05-29 01:21:19 +00001802 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00001803 ensure_valgrind("poll");
1804
sewardj5f07b662002-04-23 16:52:51 +00001805 /* Detect the current time and simultaneously find out if we are
1806 running on Valgrind. */
1807 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1808 VG_USERREQ__READ_MILLISECOND_TIMER,
1809 0, 0, 0, 0);
1810
sewardjf854f472002-04-21 12:19:41 +00001811 if (/* CHECK SIZES FOR struct pollfd */
1812 sizeof(struct timeval) != sizeof(struct vki_timeval))
1813 barf("valgrind's hacky non-blocking poll(): data sizes error");
1814
sewardj5f07b662002-04-23 16:52:51 +00001815 /* dummy initialisation to keep gcc -Wall happy */
1816 ms_end = 0;
1817
1818 /* If a zero timeout specified, this call is harmless. Also do
1819 this if not running on Valgrind. */
1820 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001821 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1822 if (is_kerror(res)) {
1823 * (__errno_location()) = -res;
1824 return -1;
1825 } else {
1826 return res;
1827 }
1828 }
1829
sewardj5f07b662002-04-23 16:52:51 +00001830 /* If a timeout was specified, set ms_end to be the end wallclock
1831 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001832 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00001833 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001834 }
1835
1836 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1837
1838 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1839 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001840 assert(__timeout != 0);
1841
sewardjf854f472002-04-21 12:19:41 +00001842 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001843 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001844 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1845 VG_USERREQ__READ_MILLISECOND_TIMER,
1846 0, 0, 0, 0);
1847 assert(ms_now != 0xFFFFFFFF);
1848 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001849 /* timeout; nothing interesting happened. */
1850 for (i = 0; i < __nfds; i++)
1851 __fds[i].revents = 0;
1852 return 0;
1853 }
1854 }
1855
sewardj5f07b662002-04-23 16:52:51 +00001856 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001857 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1858 if (is_kerror(res)) {
1859 /* Some kind of error. Set errno and return. */
1860 * (__errno_location()) = -res;
1861 return -1;
1862 }
1863 if (res > 0) {
1864 /* One or more fds is ready. Return now. */
1865 return res;
1866 }
1867 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1868 /* nanosleep and go round again */
1869 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001870 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001871 /* It's critical here that valgrind's nanosleep implementation
1872 is nonblocking. */
1873 (void)my_do_syscall2(__NR_nanosleep,
1874 (int)(&nanosleep_interval), (int)NULL);
1875 }
1876}
sewardj3b13f0e2002-04-25 20:17:29 +00001877
1878
sewardj705d3cb2002-05-23 13:13:12 +00001879/* Helper function used to make accept() non-blocking. Idea is to use
1880 the above nonblocking poll() to make this thread ONLY wait for the
1881 specified fd to become ready, and then return. */
1882static void wait_for_fd_to_be_readable_or_erring ( int fd )
1883{
1884 struct pollfd pfd;
sewardj6e6cbaa2002-05-24 02:12:52 +00001885 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardj705d3cb2002-05-23 13:13:12 +00001886 pfd.fd = fd;
1887 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
1888 /* ... but not POLLOUT, you may notice. */
1889 pfd.revents = 0;
1890 (void)poll(&pfd, 1, -1 /* forever */);
1891}
1892
1893
sewardj3b13f0e2002-04-25 20:17:29 +00001894/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00001895 Hacky implementation of semaphores.
1896 ------------------------------------------------------------------ */
1897
1898#include <semaphore.h>
1899
1900/* This is a terrible way to do the remapping. Plan is to import an
1901 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00001902
1903typedef
1904 struct {
1905 pthread_mutex_t se_mx;
1906 pthread_cond_t se_cv;
1907 int count;
1908 }
1909 vg_sem_t;
1910
1911static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
1912
1913static int se_remap_used = 0;
1914static sem_t* se_remap_orig[VG_N_SEMAPHORES];
1915static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
1916
1917static vg_sem_t* se_remap ( sem_t* orig )
1918{
1919 int res, i;
1920 res = __pthread_mutex_lock(&se_remap_mx);
1921 assert(res == 0);
1922
1923 for (i = 0; i < se_remap_used; i++) {
1924 if (se_remap_orig[i] == orig)
1925 break;
1926 }
1927 if (i == se_remap_used) {
1928 if (se_remap_used == VG_N_SEMAPHORES) {
1929 res = pthread_mutex_unlock(&se_remap_mx);
1930 assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00001931 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00001932 }
1933 se_remap_used++;
1934 se_remap_orig[i] = orig;
1935 /* printf("allocated semaphore %d\n", i); */
1936 }
1937 res = __pthread_mutex_unlock(&se_remap_mx);
1938 assert(res == 0);
1939 return &se_remap_new[i];
1940}
1941
1942
1943int sem_init(sem_t *sem, int pshared, unsigned int value)
1944{
1945 int res;
1946 vg_sem_t* vg_sem;
1947 ensure_valgrind("sem_init");
1948 if (pshared != 0) {
1949 errno = ENOSYS;
1950 return -1;
1951 }
1952 vg_sem = se_remap(sem);
1953 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
1954 assert(res == 0);
1955 res = pthread_cond_init(&vg_sem->se_cv, NULL);
1956 assert(res == 0);
1957 vg_sem->count = value;
1958 return 0;
1959}
1960
1961
1962int sem_wait ( sem_t* sem )
1963{
1964 int res;
1965 vg_sem_t* vg_sem;
1966 ensure_valgrind("sem_wait");
1967 vg_sem = se_remap(sem);
1968 res = __pthread_mutex_lock(&vg_sem->se_mx);
1969 assert(res == 0);
1970 while (vg_sem->count == 0) {
1971 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
1972 assert(res == 0);
1973 }
1974 vg_sem->count--;
1975 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1976 assert(res == 0);
1977 return 0;
1978}
1979
1980int sem_post ( sem_t* sem )
1981{
1982 int res;
1983 vg_sem_t* vg_sem;
1984 ensure_valgrind("sem_post");
1985 vg_sem = se_remap(sem);
1986 res = __pthread_mutex_lock(&vg_sem->se_mx);
1987 assert(res == 0);
1988 if (vg_sem->count == 0) {
1989 vg_sem->count++;
1990 res = pthread_cond_broadcast(&vg_sem->se_cv);
1991 assert(res == 0);
1992 } else {
1993 vg_sem->count++;
1994 }
1995 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1996 assert(res == 0);
1997 return 0;
1998}
1999
2000
2001int sem_trywait ( sem_t* sem )
2002{
2003 int ret, res;
2004 vg_sem_t* vg_sem;
2005 ensure_valgrind("sem_trywait");
2006 vg_sem = se_remap(sem);
2007 res = __pthread_mutex_lock(&vg_sem->se_mx);
2008 assert(res == 0);
2009 if (vg_sem->count > 0) {
2010 vg_sem->count--;
2011 ret = 0;
2012 } else {
2013 ret = -1;
2014 errno = EAGAIN;
2015 }
2016 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2017 assert(res == 0);
2018 return ret;
2019}
2020
2021
2022int sem_getvalue(sem_t* sem, int * sval)
2023{
2024 vg_sem_t* vg_sem;
2025 ensure_valgrind("sem_trywait");
2026 vg_sem = se_remap(sem);
2027 *sval = vg_sem->count;
2028 return 0;
2029}
2030
2031
2032int sem_destroy(sem_t * sem)
2033{
2034 kludged("sem_destroy");
2035 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2036 return 0;
2037}
2038
2039
2040/* ---------------------------------------------------------------------
sewardja1ac5cb2002-05-27 13:00:05 +00002041 Hacky implementation of reader-writer locks.
2042 ------------------------------------------------------------------ */
2043
2044/*
2045Errata from 7th printing:
2046
2047 Page 259, rwlock.c, line 27, the two "!=" should be ">", for
2048 consistency with other similar tests. (The values should never be
2049 negative; this isn't a fix, but an improvement to clarity and
2050 consistency.)
2051
2052 [27] if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2053
2054 Page 259, rwlock.c, lines 39 and 40, in both lines, "==" should
2055 become "!=":
2056
2057 [39] return (status != 0 ? status
2058 [40] : (status1 != 0 ? status1 : status2));
2059*/
2060
2061/*
2062 * rwlock.h
2063 *
2064 * This header file describes the "reader/writer lock" synchronization
2065 * construct. The type rwlock_t describes the full state of the lock
2066 * including the POSIX 1003.1c synchronization objects necessary.
2067 *
2068 * A reader/writer lock allows a thread to lock shared data either for shared
2069 * read access or exclusive write access.
2070 *
2071 * The rwl_init() and rwl_destroy() functions, respectively, allow you to
2072 * initialize/create and destroy/free the reader/writer lock.
2073 */
2074
sewardja1ac5cb2002-05-27 13:00:05 +00002075/*
2076 * Structure describing a read-write lock.
2077 */
2078typedef struct {
2079 pthread_mutex_t mutex;
2080 pthread_cond_t read; /* wait for read */
2081 pthread_cond_t write; /* wait for write */
2082 int valid; /* set when valid */
2083 int r_active; /* readers active */
2084 int w_active; /* writer active */
2085 int r_wait; /* readers waiting */
2086 int w_wait; /* writers waiting */
2087 int pref_writer; /* != 0 --> prefer writer */
2088} vg_rwlock_t;
2089
2090#define VG_RWLOCK_VALID 0xfacade
2091
2092
2093/*
2094 * Support static initialization of barriers
2095 */
2096#define VG_RWL_INITIALIZER \
2097 {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \
2098 PTHREAD_COND_INITIALIZER, VG_RWLOCK_VALID, 0, 0, 0, 0, 1}
2099
2100
2101static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2102
2103static int rw_remap_used = 0;
2104static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2105static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2106
2107/* Take the address of a LinuxThreads rwlock_t and return the shadow
2108 address of our version. Further, if the LinuxThreads version
2109 appears to have been statically initialised, do the same to the one
2110 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2111 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2112 uninitialised and non-zero meaning initialised.
2113*/
2114static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2115{
2116 int res, i;
2117 vg_rwlock_t* vg_rwl;
2118 res = __pthread_mutex_lock(&rw_remap_mx);
2119 assert(res == 0);
2120
2121 for (i = 0; i < rw_remap_used; i++) {
2122 if (rw_remap_orig[i] == orig)
2123 break;
2124 }
2125 if (i == rw_remap_used) {
2126 if (rw_remap_used == VG_N_RWLOCKS) {
2127 res = pthread_mutex_unlock(&rw_remap_mx);
2128 assert(res == 0);
2129 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2130 }
2131 rw_remap_used++;
2132 rw_remap_orig[i] = orig;
2133 if (0) printf("allocated rwlock %d\n", i);
2134 }
2135 res = __pthread_mutex_unlock(&rw_remap_mx);
2136 assert(res == 0);
2137 vg_rwl = &rw_remap_new[i];
2138
2139 /* Mimic static initialisation of the original. */
2140 if (orig->__rw_readers == 0) {
2141 const vg_rwlock_t default_rwl = VG_RWL_INITIALIZER;
2142 orig->__rw_readers = 1;
2143 *vg_rwl = default_rwl;
2144 vg_rwl->pref_writer = 1;
2145 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
2146 vg_rwl->pref_writer = 0;
2147 }
2148
2149 return vg_rwl;
2150}
2151
2152
2153/*
2154 * rwlock.c
2155 *
2156 * This file implements the "read-write lock" synchronization
2157 * construct.
2158 *
2159 * A read-write lock allows a thread to lock shared data either
2160 * for shared read access or exclusive write access.
2161 *
2162 * The rwl_init() and rwl_destroy() functions, respectively,
2163 * allow you to initialize/create and destroy/free the
2164 * read-write lock.
2165 *
2166 * The rwl_readlock() function locks a read-write lock for
2167 * shared read access, and rwl_readunlock() releases the
2168 * lock. rwl_readtrylock() attempts to lock a read-write lock
2169 * for read access, and returns EBUSY instead of blocking.
2170 *
2171 * The rwl_writelock() function locks a read-write lock for
2172 * exclusive write access, and rwl_writeunlock() releases the
2173 * lock. rwl_writetrylock() attempts to lock a read-write lock
2174 * for write access, and returns EBUSY instead of blocking.
2175 */
2176
2177
2178/*
2179 * Initialize a read-write lock
2180 */
2181static int rwl_init ( vg_rwlock_t *rwl )
2182{
2183 int status;
2184
2185 rwl->r_active = 0;
2186 rwl->r_wait = rwl->w_wait = 0;
2187 rwl->w_active = 0;
2188 status = pthread_mutex_init (&rwl->mutex, NULL);
2189 if (status != 0)
2190 return status;
2191 status = pthread_cond_init (&rwl->read, NULL);
2192 if (status != 0) {
2193 /* if unable to create read CV, destroy mutex */
2194 pthread_mutex_destroy (&rwl->mutex);
2195 return status;
2196 }
2197 status = pthread_cond_init (&rwl->write, NULL);
2198 if (status != 0) {
2199 /* if unable to create write CV, destroy read CV and mutex */
2200 pthread_cond_destroy (&rwl->read);
2201 pthread_mutex_destroy (&rwl->mutex);
2202 return status;
2203 }
2204 rwl->valid = VG_RWLOCK_VALID;
2205 return 0;
2206}
2207
2208/*
2209 * Destroy a read-write lock
2210 */
2211static int rwl_destroy (vg_rwlock_t *rwl)
2212{
2213 int status, status1, status2;
2214
2215 if (rwl->valid != VG_RWLOCK_VALID)
2216 return EINVAL;
2217 status = pthread_mutex_lock (&rwl->mutex);
2218 if (status != 0)
2219 return status;
2220
2221 /*
2222 * Check whether any threads own the lock; report "BUSY" if
2223 * so.
2224 */
2225 if (rwl->r_active > 0 || rwl->w_active) {
2226 pthread_mutex_unlock (&rwl->mutex);
2227 return EBUSY;
2228 }
2229
2230 /*
2231 * Check whether any threads are known to be waiting; report
2232 * EBUSY if so.
2233 */
2234 if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2235 pthread_mutex_unlock (&rwl->mutex);
2236 return EBUSY;
2237 }
2238
2239 rwl->valid = 0;
2240 status = pthread_mutex_unlock (&rwl->mutex);
2241 if (status != 0)
2242 return status;
2243 status = pthread_mutex_destroy (&rwl->mutex);
2244 status1 = pthread_cond_destroy (&rwl->read);
2245 status2 = pthread_cond_destroy (&rwl->write);
2246 return (status != 0 ? status : (status1 != 0 ? status1 : status2));
2247}
2248
2249/*
2250 * Handle cleanup when the read lock condition variable
2251 * wait is cancelled.
2252 *
2253 * Simply record that the thread is no longer waiting,
2254 * and unlock the mutex.
2255 */
2256static void rwl_readcleanup (void *arg)
2257{
2258 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2259
2260 rwl->r_wait--;
2261 pthread_mutex_unlock (&rwl->mutex);
2262}
2263
2264/*
2265 * Lock a read-write lock for read access.
2266 */
2267static int rwl_readlock (vg_rwlock_t *rwl)
2268{
2269 int status;
2270
2271 if (rwl->valid != VG_RWLOCK_VALID)
2272 return EINVAL;
2273 status = pthread_mutex_lock (&rwl->mutex);
2274 if (status != 0)
2275 return status;
2276 if (rwl->w_active) {
2277 rwl->r_wait++;
2278 pthread_cleanup_push (rwl_readcleanup, (void*)rwl);
2279 while (rwl->w_active) {
2280 status = pthread_cond_wait (&rwl->read, &rwl->mutex);
2281 if (status != 0)
2282 break;
2283 }
2284 pthread_cleanup_pop (0);
2285 rwl->r_wait--;
2286 }
2287 if (status == 0)
2288 rwl->r_active++;
2289 pthread_mutex_unlock (&rwl->mutex);
2290 return status;
2291}
2292
2293/*
2294 * Attempt to lock a read-write lock for read access (don't
2295 * block if unavailable).
2296 */
2297static int rwl_readtrylock (vg_rwlock_t *rwl)
2298{
2299 int status, status2;
2300
2301 if (rwl->valid != VG_RWLOCK_VALID)
2302 return EINVAL;
2303 status = pthread_mutex_lock (&rwl->mutex);
2304 if (status != 0)
2305 return status;
2306 if (rwl->w_active)
2307 status = EBUSY;
2308 else
2309 rwl->r_active++;
2310 status2 = pthread_mutex_unlock (&rwl->mutex);
2311 return (status2 != 0 ? status2 : status);
2312}
2313
2314/*
2315 * Handle cleanup when the write lock condition variable
2316 * wait is cancelled.
2317 *
2318 * Simply record that the thread is no longer waiting,
2319 * and unlock the mutex.
2320 */
2321static void rwl_writecleanup (void *arg)
2322{
2323 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2324
2325 rwl->w_wait--;
2326 pthread_mutex_unlock (&rwl->mutex);
2327}
2328
2329/*
2330 * Lock a read-write lock for write access.
2331 */
2332static int rwl_writelock (vg_rwlock_t *rwl)
2333{
2334 int status;
2335
2336 if (rwl->valid != VG_RWLOCK_VALID)
2337 return EINVAL;
2338 status = pthread_mutex_lock (&rwl->mutex);
2339 if (status != 0)
2340 return status;
2341 if (rwl->w_active || rwl->r_active > 0) {
2342 rwl->w_wait++;
2343 pthread_cleanup_push (rwl_writecleanup, (void*)rwl);
2344 while (rwl->w_active || rwl->r_active > 0) {
2345 status = pthread_cond_wait (&rwl->write, &rwl->mutex);
2346 if (status != 0)
2347 break;
2348 }
2349 pthread_cleanup_pop (0);
2350 rwl->w_wait--;
2351 }
2352 if (status == 0)
2353 rwl->w_active = 1;
2354 pthread_mutex_unlock (&rwl->mutex);
2355 return status;
2356}
2357
2358/*
2359 * Attempt to lock a read-write lock for write access. Don't
2360 * block if unavailable.
2361 */
2362static int rwl_writetrylock (vg_rwlock_t *rwl)
2363{
2364 int status, status2;
2365
2366 if (rwl->valid != VG_RWLOCK_VALID)
2367 return EINVAL;
2368 status = pthread_mutex_lock (&rwl->mutex);
2369 if (status != 0)
2370 return status;
2371 if (rwl->w_active || rwl->r_active > 0)
2372 status = EBUSY;
2373 else
2374 rwl->w_active = 1;
2375 status2 = pthread_mutex_unlock (&rwl->mutex);
2376 return (status != 0 ? status : status2);
2377}
2378
2379/*
2380 * Unlock a read-write lock, using the r_active and w_active fields to
2381 * decide whether we're in a read or write lock.
2382 */
2383static int rwl_unlock (vg_rwlock_t *rwl)
2384{
2385 int status, status2;
2386
2387 if (rwl->valid != VG_RWLOCK_VALID)
2388 return EINVAL;
2389 status = pthread_mutex_lock (&rwl->mutex);
2390 if (status != 0)
2391 return status;
2392
2393 if (rwl->r_active > 0) {
2394
2395 /* READ case */
2396 assert(!rwl->w_active);
2397 rwl->r_active--;
2398 if (rwl->r_active == 0 && rwl->w_wait > 0)
2399 status = pthread_cond_signal (&rwl->write);
2400 /* END READ case */
2401
2402 } else {
2403
2404 /* WRITE case */
2405 assert(rwl->w_active);
2406 assert(rwl->r_active == 0);
2407 rwl->w_active = 0;
2408
2409 if (rwl->pref_writer) {
2410 /* Do writer-preference wakeups. */
2411 if (rwl->w_wait > 0) {
2412 status = pthread_cond_signal (&rwl->write);
2413 if (status != 0) {
2414 pthread_mutex_unlock (&rwl->mutex);
2415 return status;
2416 }
2417 } else if (rwl->r_wait > 0) {
2418 status = pthread_cond_broadcast (&rwl->read);
2419 if (status != 0) {
2420 pthread_mutex_unlock (&rwl->mutex);
2421 return status;
2422 }
2423 }
2424 } else {
2425 /* Do reader-preference wakeups. */
2426 if (rwl->r_wait > 0) {
2427 status = pthread_cond_broadcast (&rwl->read);
2428 if (status != 0) {
2429 pthread_mutex_unlock (&rwl->mutex);
2430 return status;
2431 }
2432 } else if (rwl->w_wait > 0) {
2433 status = pthread_cond_signal (&rwl->write);
2434 if (status != 0) {
2435 pthread_mutex_unlock (&rwl->mutex);
2436 return status;
2437 }
2438 }
2439 }
2440 /* END WRITE case */
2441
2442 }
2443
2444 status2 = pthread_mutex_unlock (&rwl->mutex);
2445 return (status2 == 0 ? status : status2);
2446}
2447
2448/* -------------------------------- */
2449
2450int pthread_rwlock_init ( pthread_rwlock_t* orig,
2451 const pthread_rwlockattr_t* attr )
2452{
2453 int res;
2454 vg_rwlock_t* rwl;
2455 if (0) printf ("pthread_rwlock_init\n");
2456 /* Force the remapper to initialise the shadow. */
2457 orig->__rw_readers = 0;
2458 /* Install the lock preference; the remapper needs to know it. */
2459 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2460 if (attr)
2461 orig->__rw_kind = attr->__lockkind;
2462 rwl = rw_remap ( orig );
2463 res = rwl_init ( rwl );
2464 return res;
2465}
2466
2467int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2468{
2469 int res;
2470 vg_rwlock_t* rwl;
2471 if (0) printf ("pthread_rwlock_destroy\n");
2472 rwl = rw_remap ( orig );
2473 res = rwl_destroy ( rwl );
2474 return res;
2475}
2476
2477int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2478{
2479 int res;
2480 vg_rwlock_t* rwl;
2481 if (0) printf ("pthread_rwlock_rdlock\n");
2482 rwl = rw_remap ( orig );
2483 res = rwl_readlock ( rwl );
2484 return res;
2485}
2486
2487int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2488{
2489 int res;
2490 vg_rwlock_t* rwl;
2491 if (0) printf ("pthread_rwlock_tryrdlock\n");
2492 rwl = rw_remap ( orig );
2493 res = rwl_readtrylock ( rwl );
2494 return res;
2495}
2496
2497int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2498{
2499 int res;
2500 vg_rwlock_t* rwl;
2501 if (0) printf ("pthread_rwlock_wrlock\n");
2502 rwl = rw_remap ( orig );
2503 res = rwl_writelock ( rwl );
2504 return res;
2505}
2506
2507int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2508{
2509 int res;
2510 vg_rwlock_t* rwl;
2511 if (0) printf ("pthread_rwlock_trywrlock\n");
2512 rwl = rw_remap ( orig );
2513 res = rwl_writetrylock ( rwl );
2514 return res;
2515}
2516
2517int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2518{
2519 int res;
2520 vg_rwlock_t* rwl;
2521 if (0) printf ("pthread_rwlock_unlock\n");
2522 rwl = rw_remap ( orig );
2523 res = rwl_unlock ( rwl );
2524 return res;
2525}
2526
2527
2528/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002529 B'stard.
2530 ------------------------------------------------------------------ */
2531
2532# define strong_alias(name, aliasname) \
2533 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2534
sewardj5905fae2002-04-26 13:25:00 +00002535# define weak_alias(name, aliasname) \
2536 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002537
sewardj5905fae2002-04-26 13:25:00 +00002538strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2539strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2540strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2541strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2542 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2543strong_alias(__pthread_mutex_init, pthread_mutex_init)
2544strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2545strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2546strong_alias(__pthread_once, pthread_once)
2547strong_alias(__pthread_atfork, pthread_atfork)
2548strong_alias(__pthread_key_create, pthread_key_create)
2549strong_alias(__pthread_getspecific, pthread_getspecific)
2550strong_alias(__pthread_setspecific, pthread_setspecific)
2551
sewardjd529a442002-05-04 19:49:21 +00002552#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002553strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002554#endif
2555
sewardj5905fae2002-04-26 13:25:00 +00002556strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002557strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002558strong_alias(lseek, __lseek)
2559strong_alias(open, __open)
2560strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002561strong_alias(read, __read)
2562strong_alias(wait, __wait)
2563strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002564strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002565strong_alias(send, __send)
2566
sewardj726c4122002-05-16 23:39:10 +00002567weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002568weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002569weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002570
sewardj5905fae2002-04-26 13:25:00 +00002571
sewardj3b13f0e2002-04-25 20:17:29 +00002572
2573/*--------------------------------------------------*/
2574
sewardj5905fae2002-04-26 13:25:00 +00002575weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002576weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002577weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002578
sewardja1ac5cb2002-05-27 13:00:05 +00002579weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2580weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2581weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2582weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2583
sewardj060b04f2002-04-26 21:01:13 +00002584
sewardj3b13f0e2002-04-25 20:17:29 +00002585/* I've no idea what these are, but they get called quite a lot.
2586 Anybody know? */
2587
2588#undef _IO_flockfile
2589void _IO_flockfile ( _IO_FILE * file )
2590{
sewardj853f55d2002-04-26 00:27:53 +00002591 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002592}
sewardj5905fae2002-04-26 13:25:00 +00002593weak_alias(_IO_flockfile, flockfile);
2594
sewardj3b13f0e2002-04-25 20:17:29 +00002595
2596#undef _IO_funlockfile
2597void _IO_funlockfile ( _IO_FILE * file )
2598{
sewardj853f55d2002-04-26 00:27:53 +00002599 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002600}
sewardj5905fae2002-04-26 13:25:00 +00002601weak_alias(_IO_funlockfile, funlockfile);
2602
sewardj3b13f0e2002-04-25 20:17:29 +00002603
sewardjd4f2c712002-04-30 10:20:10 +00002604/* This doesn't seem to be needed to simulate libpthread.so's external
2605 interface, but many people complain about its absence. */
2606
2607strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2608weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002609
2610
2611/*--------------------------------------------------------------------*/
2612/*--- end vg_libpthread.c ---*/
2613/*--------------------------------------------------------------------*/