blob: 953f3d146fd85123c5d8c4ecb83bda5cfeb67f4e [file] [log] [blame]
sewardje663cb92002-04-12 10:26:32 +00001
sewardj439d45e2002-05-03 20:43:10 +00002/*--------------------------------------------------------------------*/
3/*--- A replacement for the standard libpthread.so. ---*/
4/*--- vg_libpthread.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, an x86 protected-mode emulator
9 designed for debugging and profiling binaries on x86-Unixes.
10
11 Copyright (C) 2000-2002 Julian Seward
12 jseward@acm.org
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file LICENSE.
30*/
31
32/* ALL THIS CODE RUNS ON THE SIMULATED CPU.
33
34 This is a replacement for the standard libpthread.so. It is loaded
sewardje663cb92002-04-12 10:26:32 +000035 as part of the client's image (if required) and directs pthread
36 calls through to Valgrind's request mechanism.
37
38 A couple of caveats.
39
40 1. Since it's a binary-compatible replacement for an existing library,
41 we must take care to used exactly the same data layouts, etc, as
42 the standard pthread.so does.
43
44 2. Since this runs as part of the client, there are no specific
45 restrictions on what headers etc we can include, so long as
46 this libpthread.so does not end up having dependencies on .so's
47 which the real one doesn't.
48
49 Later ... it appears we cannot call file-related stuff in libc here,
50 perhaps fair enough. Be careful what you call from here. Even exit()
51 doesn't work (gives infinite recursion and then stack overflow); hence
52 myexit(). Also fprintf doesn't seem safe.
53*/
54
55#include "valgrind.h" /* For the request-passing mechanism */
56#include "vg_include.h" /* For the VG_USERREQ__* constants */
57
sewardja1ac5cb2002-05-27 13:00:05 +000058#define __USE_UNIX98
59#include <sys/types.h>
60#include <pthread.h>
61#undef __USE_UNIX98
62
sewardje663cb92002-04-12 10:26:32 +000063#include <unistd.h>
64#include <string.h>
sewardj2a1dcce2002-04-22 12:45:25 +000065#ifdef GLIBC_2_1
66#include <sys/time.h>
67#endif
sewardje663cb92002-04-12 10:26:32 +000068
sewardj705d3cb2002-05-23 13:13:12 +000069
70/* ---------------------------------------------------------------------
71 Forwardses.
72 ------------------------------------------------------------------ */
73
74static void wait_for_fd_to_be_readable_or_erring ( int fd );
75
76
sewardje663cb92002-04-12 10:26:32 +000077/* ---------------------------------------------------------------------
78 Helpers. We have to be pretty self-sufficient.
79 ------------------------------------------------------------------ */
80
sewardj436e0582002-04-26 14:31:40 +000081/* Number of times any given error message is printed. */
82#define N_MOANS 3
83
sewardj45b4b372002-04-16 22:50:32 +000084/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
85 Returns 0 (none) if not running on Valgrind. */
86static
87int get_pt_trace_level ( void )
88{
89 int res;
90 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
91 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
92 0, 0, 0, 0);
93 return res;
94}
95
96
sewardje663cb92002-04-12 10:26:32 +000097static
98void myexit ( int arg )
99{
sewardj45b4b372002-04-16 22:50:32 +0000100 int __res;
sewardje663cb92002-04-12 10:26:32 +0000101 __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
102 : "=a" (__res)
103 : "0" (__NR_exit),
104 "c" (arg) );
sewardj45b4b372002-04-16 22:50:32 +0000105 /* We don't bother to mention the fact that this asm trashes %ebx,
106 since it won't return. If you ever do let it return ... fix
107 this! */
sewardje663cb92002-04-12 10:26:32 +0000108}
109
110
sewardj68b2dd92002-05-10 21:03:56 +0000111/* We need this guy -- it's in valgrind.so. */
112extern void VG_(startup) ( void );
113
114
115/* Just start up Valgrind if it's not already going. VG_(startup)()
116 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000117static __inline__
sewardje663cb92002-04-12 10:26:32 +0000118void ensure_valgrind ( char* caller )
119{
sewardj68b2dd92002-05-10 21:03:56 +0000120 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000121}
122
sewardjbea1caa2002-05-10 23:20:58 +0000123/* While we're at it ... hook our own startup function into this
124 game. */
125__asm__ (
126 ".section .init\n"
127 "\tcall vgPlain_startup"
128);
129
sewardje663cb92002-04-12 10:26:32 +0000130
131static
sewardj3b5d8862002-04-20 13:53:23 +0000132__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +0000133void barf ( char* str )
134{
135 char buf[100];
136 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000137 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000138 strcat(buf, str);
139 strcat(buf, "\n\n");
140 write(2, buf, strlen(buf));
141 myexit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000142 /* We have to persuade gcc into believing this doesn't return. */
143 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000144}
145
146
sewardj2a3d28c2002-04-14 13:27:00 +0000147static void ignored ( char* msg )
148{
sewardj436e0582002-04-26 14:31:40 +0000149 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000150 char* ig = "valgrind's libpthread.so: IGNORED call to: ";
sewardj45b4b372002-04-16 22:50:32 +0000151 write(2, ig, strlen(ig));
152 write(2, msg, strlen(msg));
153 ig = "\n";
154 write(2, ig, strlen(ig));
155 }
sewardj2a3d28c2002-04-14 13:27:00 +0000156}
157
sewardj30671ff2002-04-21 00:13:57 +0000158static void kludged ( char* msg )
159{
sewardj436e0582002-04-26 14:31:40 +0000160 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000161 char* ig = "valgrind's libpthread.so: KLUDGED call to: ";
162 write(2, ig, strlen(ig));
163 write(2, msg, strlen(msg));
164 ig = "\n";
165 write(2, ig, strlen(ig));
166 }
167}
168
169static void not_inside ( char* msg )
170{
sewardj68b2dd92002-05-10 21:03:56 +0000171 VG_(startup)();
sewardj30671ff2002-04-21 00:13:57 +0000172}
173
sewardjccef2e62002-05-29 19:26:32 +0000174__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000175void vgPlain_unimp ( char* what )
176{
sewardj439d45e2002-05-03 20:43:10 +0000177 char* ig = "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ";
sewardj3b13f0e2002-04-25 20:17:29 +0000178 write(2, ig, strlen(ig));
179 write(2, what, strlen(what));
180 ig = "\n";
181 write(2, ig, strlen(ig));
182 barf("Please report this bug to me at: jseward@acm.org");
183}
184
sewardje663cb92002-04-12 10:26:32 +0000185
186/* ---------------------------------------------------------------------
187 Pass pthread_ calls to Valgrind's request mechanism.
188 ------------------------------------------------------------------ */
189
sewardjf8f819e2002-04-17 23:21:37 +0000190#include <stdio.h>
191#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000192#include <assert.h>
193#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000194
sewardja1ac5cb2002-05-27 13:00:05 +0000195
sewardjf8f819e2002-04-17 23:21:37 +0000196/* ---------------------------------------------------
197 THREAD ATTRIBUTES
198 ------------------------------------------------ */
199
sewardj6af4b5d2002-04-16 04:40:49 +0000200int pthread_attr_init(pthread_attr_t *attr)
201{
sewardj7989d0c2002-05-28 11:00:01 +0000202 /* Just initialise the fields which we might look at. */
203 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj6af4b5d2002-04-16 04:40:49 +0000204 return 0;
205}
206
207int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
208{
sewardj7989d0c2002-05-28 11:00:01 +0000209 if (detachstate != PTHREAD_CREATE_JOINABLE
210 && detachstate != PTHREAD_CREATE_DETACHED)
211 return EINVAL;
212 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000213 return 0;
214}
215
sewardj30671ff2002-04-21 00:13:57 +0000216int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
217{
sewardj436e0582002-04-26 14:31:40 +0000218 static int moans = N_MOANS;
219 if (moans-- > 0)
220 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000221 return 0;
222}
sewardj6af4b5d2002-04-16 04:40:49 +0000223
sewardj0286dd52002-05-16 20:51:15 +0000224__attribute__((weak))
225int pthread_attr_setstacksize (pthread_attr_t *__attr,
226 size_t __stacksize)
227{
sewardja18e2102002-05-18 10:43:22 +0000228 size_t limit;
sewardj0286dd52002-05-16 20:51:15 +0000229 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000230 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
231 - 1000; /* paranoia */
232 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000233 return 0;
234 barf("pthread_attr_setstacksize: "
235 "requested size >= VG_PTHREAD_STACK_SIZE\n "
236 "edit vg_include.h and rebuild.");
237}
238
239
sewardj30671ff2002-04-21 00:13:57 +0000240/* This is completely bogus. */
241int pthread_attr_getschedparam(const pthread_attr_t *attr,
242 struct sched_param *param)
243{
sewardj436e0582002-04-26 14:31:40 +0000244 static int moans = N_MOANS;
245 if (moans-- > 0)
246 kludged("pthread_attr_getschedparam");
sewardj72d58482002-04-24 02:20:20 +0000247# ifdef GLIBC_2_1
248 if (param) param->sched_priority = 0; /* who knows */
249# else
sewardj30671ff2002-04-21 00:13:57 +0000250 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000251# endif
sewardj30671ff2002-04-21 00:13:57 +0000252 return 0;
253}
254
255int pthread_attr_setschedparam(pthread_attr_t *attr,
256 const struct sched_param *param)
257{
sewardj436e0582002-04-26 14:31:40 +0000258 static int moans = N_MOANS;
259 if (moans-- > 0)
260 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000261 return 0;
262}
263
264int pthread_attr_destroy(pthread_attr_t *attr)
265{
sewardj436e0582002-04-26 14:31:40 +0000266 static int moans = N_MOANS;
267 if (moans-- > 0)
268 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000269 return 0;
270}
sewardjf8f819e2002-04-17 23:21:37 +0000271
sewardj20917d82002-05-28 01:36:45 +0000272/* ---------------------------------------------------
273 Helper functions for running a thread
274 and for clearing up afterwards.
275 ------------------------------------------------ */
276
277/* All exiting threads eventually pass through here, bearing the
278 return value, or PTHREAD_CANCELED, in ret_val. */
279static
280__attribute__((noreturn))
281void thread_exit_wrapper ( void* ret_val )
282{
sewardj870497a2002-05-29 01:06:47 +0000283 int detached, res;
284 CleanupEntry cu;
285 pthread_key_t key;
286
sewardj20917d82002-05-28 01:36:45 +0000287 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000288 while (1) {
289 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
290 VG_USERREQ__CLEANUP_POP,
291 &cu, 0, 0, 0);
292 if (res == -1) break; /* stack empty */
293 assert(res == 0);
294 if (0) printf("running exit cleanup handler");
295 cu.fn ( cu.arg );
296 }
297
sewardj870497a2002-05-29 01:06:47 +0000298 /* Run this thread's key finalizers. Really this should be run
299 PTHREAD_DESTRUCTOR_ITERATIONS times. */
300 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
301 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
302 VG_USERREQ__GET_KEY_D_AND_S,
303 key, &cu, 0, 0 );
304 if (res == 0) {
305 /* valid key */
306 if (cu.fn && cu.arg)
307 cu.fn /* destructor for key */
308 ( cu.arg /* specific for key for this thread */ );
309 continue;
310 }
311 assert(res == -1);
312 }
sewardj20917d82002-05-28 01:36:45 +0000313
314 /* Decide on my final disposition. */
315 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
316 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000317 2 /* get */, pthread_self(), 0, 0);
sewardj20917d82002-05-28 01:36:45 +0000318 assert(detached == 0 || detached == 1);
319
320 if (detached) {
321 /* Detached; I just quit right now. */
322 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
323 VG_USERREQ__QUIT, 0, 0, 0, 0);
324 } else {
325 /* Not detached; so I wait for a joiner. */
326 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
327 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
328 }
329 /* NOTREACHED */
330 barf("thread_exit_wrapper: still alive?!");
331}
332
333
334/* This function is a wrapper function for running a thread. It runs
335 the root function specified in pthread_create, and then, should the
336 root function return a value, it arranges to run the thread's
337 cleanup handlers and exit correctly. */
338
339/* Struct used to convey info from pthread_create to
340 thread_wrapper. */
341typedef
342 struct {
343 pthread_attr_t* attr;
344 void* (*root_fn) ( void* );
345 void* arg;
346 }
347 NewThreadInfo;
348
349
350/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
351 not return. Note that this runs in the new thread, not the
352 parent. */
353static
354__attribute__((noreturn))
355void thread_wrapper ( NewThreadInfo* info )
356{
357 int res;
358 pthread_attr_t* attr;
359 void* (*root_fn) ( void* );
360 void* arg;
361 void* ret_val;
362
363 attr = info->attr;
364 root_fn = info->root_fn;
365 arg = info->arg;
366
sewardj20917d82002-05-28 01:36:45 +0000367 /* Free up the arg block that pthread_create malloced. */
368 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
369 VG_USERREQ__FREE, info, 0, 0, 0);
370 assert(res == 0);
371
sewardj7989d0c2002-05-28 11:00:01 +0000372 /* Minimally observe the attributes supplied. */
373 if (attr) {
374 assert(attr->__detachstate == PTHREAD_CREATE_DETACHED
375 || attr->__detachstate == PTHREAD_CREATE_JOINABLE);
376 if (attr->__detachstate == PTHREAD_CREATE_DETACHED)
377 pthread_detach(pthread_self());
378 }
379
sewardj20917d82002-05-28 01:36:45 +0000380 /* The root function might not return. But if it does we simply
381 move along to thread_exit_wrapper. All other ways out for the
382 thread (cancellation, or calling pthread_exit) lead there
383 too. */
384 ret_val = root_fn(arg);
385 thread_exit_wrapper(ret_val);
386 /* NOTREACHED */
387}
388
389
sewardjf8f819e2002-04-17 23:21:37 +0000390/* ---------------------------------------------------
391 THREADs
392 ------------------------------------------------ */
393
sewardjff42d1d2002-05-22 13:17:31 +0000394__attribute__((weak))
395int pthread_yield ( void )
396{
397 int res;
398 ensure_valgrind("pthread_yield");
399 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
400 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
401 return 0;
402}
403
404
sewardj6072c362002-04-19 14:40:57 +0000405int pthread_equal(pthread_t thread1, pthread_t thread2)
406{
407 return thread1 == thread2 ? 1 : 0;
408}
409
410
sewardj20917d82002-05-28 01:36:45 +0000411/* Bundle up the args into a malloc'd block and create a new thread
412 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000413int
414pthread_create (pthread_t *__restrict __thread,
415 __const pthread_attr_t *__restrict __attr,
416 void *(*__start_routine) (void *),
417 void *__restrict __arg)
418{
sewardj20917d82002-05-28 01:36:45 +0000419 int tid_child;
420 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000421
sewardj20917d82002-05-28 01:36:45 +0000422 ensure_valgrind("pthread_create");
423
424 /* Allocate space for the arg block. thread_wrapper will free
425 it. */
426 VALGRIND_MAGIC_SEQUENCE(info, NULL /* default */,
427 VG_USERREQ__MALLOC,
428 sizeof(NewThreadInfo), 0, 0, 0);
429 assert(info != NULL);
430
431 info->attr = (pthread_attr_t*)__attr;
432 info->root_fn = __start_routine;
433 info->arg = __arg;
434 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
435 VG_USERREQ__APPLY_IN_NEW_THREAD,
436 &thread_wrapper, info, 0, 0);
437 assert(tid_child != VG_INVALID_THREADID);
438
439 if (__thread)
440 *__thread = tid_child;
441 return 0; /* success */
442}
sewardje663cb92002-04-12 10:26:32 +0000443
444
445int
446pthread_join (pthread_t __th, void **__thread_return)
447{
448 int res;
449 ensure_valgrind("pthread_join");
450 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
451 VG_USERREQ__PTHREAD_JOIN,
452 __th, __thread_return, 0, 0);
453 return res;
454}
455
456
sewardj3b5d8862002-04-20 13:53:23 +0000457void pthread_exit(void *retval)
458{
sewardj3b5d8862002-04-20 13:53:23 +0000459 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000460 /* Simple! */
461 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000462}
463
sewardje663cb92002-04-12 10:26:32 +0000464
sewardj3b13f0e2002-04-25 20:17:29 +0000465pthread_t pthread_self(void)
sewardje663cb92002-04-12 10:26:32 +0000466{
467 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000468 ensure_valgrind("pthread_self");
sewardj439d45e2002-05-03 20:43:10 +0000469 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardje663cb92002-04-12 10:26:32 +0000470 VG_USERREQ__PTHREAD_GET_THREADID,
471 0, 0, 0, 0);
sewardj439d45e2002-05-03 20:43:10 +0000472 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000473 barf("pthread_self: invalid ThreadId");
474 return tid;
sewardje663cb92002-04-12 10:26:32 +0000475}
476
477
sewardj853f55d2002-04-26 00:27:53 +0000478int pthread_detach(pthread_t th)
479{
sewardj20917d82002-05-28 01:36:45 +0000480 int res;
481 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000482 /* First we enquire as to the current detach state. */
483 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000484 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000485 2 /* get */, th, 0, 0);
486 if (res == -1) /* not found */
487 return ESRCH;
488 if (res == 1) /* already detached */
489 return EINVAL;
490 if (res == 0) {
491 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
492 VG_USERREQ__SET_OR_GET_DETACH,
493 1 /* set */, th, 0, 0);
494 assert(res == 0);
495 return 0;
496 }
497 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000498}
499
500
sewardjf8f819e2002-04-17 23:21:37 +0000501/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000502 CLEANUP STACKS
503 ------------------------------------------------ */
504
505void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
506 void (*__routine) (void *),
507 void *__arg)
508{
509 int res;
510 CleanupEntry cu;
511 ensure_valgrind("_pthread_cleanup_push");
512 cu.fn = __routine;
513 cu.arg = __arg;
514 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
515 VG_USERREQ__CLEANUP_PUSH,
516 &cu, 0, 0, 0);
517 assert(res == 0);
518}
519
520
521void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
522 void (*__routine) (void *),
523 void *__arg)
524{
525 /* As _pthread_cleanup_push, but first save the thread's original
526 cancellation type in __buffer and set it to Deferred. */
527 int orig_ctype;
528 ensure_valgrind("_pthread_cleanup_push_defer");
529 /* Set to Deferred, and put the old cancellation type in res. */
530 assert(-1 != PTHREAD_CANCEL_DEFERRED);
531 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
532 assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
533 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
534 VG_USERREQ__SET_CANCELTYPE,
535 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
536 assert(orig_ctype != -1);
537 *((int*)(__buffer)) = orig_ctype;
538 /* Now push the cleanup. */
539 _pthread_cleanup_push(NULL, __routine, __arg);
540}
541
542
543void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
544 int __execute)
545{
546 int res;
547 CleanupEntry cu;
548 ensure_valgrind("_pthread_cleanup_push");
549 cu.fn = cu.arg = NULL; /* paranoia */
550 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
551 VG_USERREQ__CLEANUP_POP,
552 &cu, 0, 0, 0);
553 if (res == 0) {
554 /* pop succeeded */
555 if (__execute) {
556 cu.fn ( cu.arg );
557 }
558 return;
559 }
560 if (res == -1) {
561 /* stack underflow */
562 return;
563 }
564 barf("_pthread_cleanup_pop");
565}
566
567
568void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
569 int __execute)
570{
571 int orig_ctype, fake_ctype;
572 /* As _pthread_cleanup_pop, but after popping/running the handler,
573 restore the thread's original cancellation type from the first
574 word of __buffer. */
575 _pthread_cleanup_pop(NULL, __execute);
576 orig_ctype = *((int*)(__buffer));
577 assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
578 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
579 assert(-1 != PTHREAD_CANCEL_DEFERRED);
580 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
581 assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
582 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
583 VG_USERREQ__SET_CANCELTYPE,
584 orig_ctype, 0, 0, 0);
585 assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
586}
587
588
589/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000590 MUTEX ATTRIBUTES
591 ------------------------------------------------ */
592
sewardj5905fae2002-04-26 13:25:00 +0000593int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000594{
sewardjf8f819e2002-04-17 23:21:37 +0000595 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000596 return 0;
sewardje663cb92002-04-12 10:26:32 +0000597}
598
sewardj5905fae2002-04-26 13:25:00 +0000599int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000600{
601 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000602# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000603 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000604 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000605# endif
sewardja1679dd2002-05-10 22:31:40 +0000606# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000607 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000608# endif
sewardjf8f819e2002-04-17 23:21:37 +0000609 case PTHREAD_MUTEX_RECURSIVE_NP:
610 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000611 attr->__mutexkind = type;
612 return 0;
613 default:
614 return EINVAL;
615 }
616}
617
sewardj5905fae2002-04-26 13:25:00 +0000618int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000619{
620 return 0;
621}
622
623
624/* ---------------------------------------------------
625 MUTEXes
626 ------------------------------------------------ */
627
sewardj5905fae2002-04-26 13:25:00 +0000628int __pthread_mutex_init(pthread_mutex_t *mutex,
629 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000630{
sewardj604ec3c2002-04-18 22:38:41 +0000631 mutex->__m_count = 0;
632 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
633 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
634 if (mutexattr)
635 mutex->__m_kind = mutexattr->__mutexkind;
636 return 0;
sewardje663cb92002-04-12 10:26:32 +0000637}
638
sewardj439d45e2002-05-03 20:43:10 +0000639
sewardj5905fae2002-04-26 13:25:00 +0000640int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000641{
642 int res;
sewardj436e0582002-04-26 14:31:40 +0000643 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000644 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000645 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
646 VG_USERREQ__PTHREAD_MUTEX_LOCK,
647 mutex, 0, 0, 0);
648 return res;
sewardj439d45e2002-05-03 20:43:10 +0000649 } else {
650 if (moans-- > 0)
651 not_inside("pthread_mutex_lock");
652 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000653 }
654}
655
sewardj439d45e2002-05-03 20:43:10 +0000656
sewardj5905fae2002-04-26 13:25:00 +0000657int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000658{
659 int res;
sewardj436e0582002-04-26 14:31:40 +0000660 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000661 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000662 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
663 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
664 mutex, 0, 0, 0);
665 return res;
sewardj439d45e2002-05-03 20:43:10 +0000666 } else {
667 if (moans-- > 0)
668 not_inside("pthread_mutex_trylock");
669 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000670 }
671}
672
sewardj439d45e2002-05-03 20:43:10 +0000673
sewardj5905fae2002-04-26 13:25:00 +0000674int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000675{
676 int res;
sewardj436e0582002-04-26 14:31:40 +0000677 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000678 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000679 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
680 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
681 mutex, 0, 0, 0);
682 return res;
sewardj439d45e2002-05-03 20:43:10 +0000683 } else {
684 if (moans-- > 0)
685 not_inside("pthread_mutex_unlock");
686 return 0;
sewardje663cb92002-04-12 10:26:32 +0000687 }
688}
689
sewardj439d45e2002-05-03 20:43:10 +0000690
sewardj5905fae2002-04-26 13:25:00 +0000691int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000692{
sewardj604ec3c2002-04-18 22:38:41 +0000693 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
694 need to involve it. */
695 if (mutex->__m_count > 0)
696 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000697 mutex->__m_count = 0;
698 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
699 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000700 return 0;
sewardje663cb92002-04-12 10:26:32 +0000701}
702
703
sewardjf8f819e2002-04-17 23:21:37 +0000704/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000705 CONDITION VARIABLES
706 ------------------------------------------------ */
707
708/* LinuxThreads supports no attributes for conditions. Hence ... */
709
710int pthread_condattr_init(pthread_condattr_t *attr)
711{
712 return 0;
713}
714
sewardj0738a592002-04-20 13:59:33 +0000715int pthread_condattr_destroy(pthread_condattr_t *attr)
716{
717 return 0;
718}
sewardj6072c362002-04-19 14:40:57 +0000719
720int pthread_cond_init( pthread_cond_t *cond,
721 const pthread_condattr_t *cond_attr)
722{
723 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
724 return 0;
725}
726
sewardjf854f472002-04-21 12:19:41 +0000727int pthread_cond_destroy(pthread_cond_t *cond)
728{
729 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000730 static int moans = N_MOANS;
731 if (moans-- > 0)
732 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000733 return 0;
734}
sewardj6072c362002-04-19 14:40:57 +0000735
736/* ---------------------------------------------------
737 SCHEDULING
738 ------------------------------------------------ */
739
740/* This is completely bogus. */
741int pthread_getschedparam(pthread_t target_thread,
742 int *policy,
743 struct sched_param *param)
744{
sewardj436e0582002-04-26 14:31:40 +0000745 static int moans = N_MOANS;
746 if (moans-- > 0)
747 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000748 if (policy) *policy = SCHED_OTHER;
sewardj2a1dcce2002-04-22 12:45:25 +0000749# ifdef GLIBC_2_1
750 if (param) param->sched_priority = 0; /* who knows */
751# else
sewardj6072c362002-04-19 14:40:57 +0000752 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000753# endif
sewardj6072c362002-04-19 14:40:57 +0000754 return 0;
755}
756
757int pthread_setschedparam(pthread_t target_thread,
758 int policy,
759 const struct sched_param *param)
760{
sewardj436e0582002-04-26 14:31:40 +0000761 static int moans = N_MOANS;
762 if (moans-- > 0)
763 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000764 return 0;
765}
766
sewardj3b5d8862002-04-20 13:53:23 +0000767int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
768{
769 int res;
770 ensure_valgrind("pthread_cond_wait");
771 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
772 VG_USERREQ__PTHREAD_COND_WAIT,
773 cond, mutex, 0, 0);
774 return res;
775}
776
sewardj5f07b662002-04-23 16:52:51 +0000777int pthread_cond_timedwait ( pthread_cond_t *cond,
778 pthread_mutex_t *mutex,
779 const struct timespec *abstime )
780{
781 int res;
782 unsigned int ms_now, ms_end;
783 struct timeval timeval_now;
784 unsigned long long int ull_ms_now_after_1970;
785 unsigned long long int ull_ms_end_after_1970;
786
787 ensure_valgrind("pthread_cond_timedwait");
788 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
789 VG_USERREQ__READ_MILLISECOND_TIMER,
790 0, 0, 0, 0);
791 assert(ms_now != 0xFFFFFFFF);
792 res = gettimeofday(&timeval_now, NULL);
793 assert(res == 0);
794
795 ull_ms_now_after_1970
796 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
797 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
798 ull_ms_end_after_1970
799 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
800 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +0000801 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
802 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +0000803 ms_end
804 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
805 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
806 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
807 cond, mutex, ms_end, 0);
808 return res;
809}
810
811
sewardj3b5d8862002-04-20 13:53:23 +0000812int pthread_cond_signal(pthread_cond_t *cond)
813{
814 int res;
815 ensure_valgrind("pthread_cond_signal");
816 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
817 VG_USERREQ__PTHREAD_COND_SIGNAL,
818 cond, 0, 0, 0);
819 return res;
820}
821
822int pthread_cond_broadcast(pthread_cond_t *cond)
823{
824 int res;
825 ensure_valgrind("pthread_cond_broadcast");
826 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
827 VG_USERREQ__PTHREAD_COND_BROADCAST,
828 cond, 0, 0, 0);
829 return res;
830}
831
sewardj6072c362002-04-19 14:40:57 +0000832
833/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000834 CANCELLATION
835 ------------------------------------------------ */
836
sewardj853f55d2002-04-26 00:27:53 +0000837int pthread_setcancelstate(int state, int *oldstate)
838{
sewardj20917d82002-05-28 01:36:45 +0000839 int res;
840 ensure_valgrind("pthread_setcancelstate");
841 if (state != PTHREAD_CANCEL_ENABLE
842 && state != PTHREAD_CANCEL_DISABLE)
843 return EINVAL;
844 assert(-1 != PTHREAD_CANCEL_ENABLE);
845 assert(-1 != PTHREAD_CANCEL_DISABLE);
846 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
847 VG_USERREQ__SET_CANCELSTATE,
848 state, 0, 0, 0);
849 assert(res != -1);
850 if (oldstate)
851 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +0000852 return 0;
853}
854
sewardje663cb92002-04-12 10:26:32 +0000855int pthread_setcanceltype(int type, int *oldtype)
856{
sewardj20917d82002-05-28 01:36:45 +0000857 int res;
858 ensure_valgrind("pthread_setcanceltype");
859 if (type != PTHREAD_CANCEL_DEFERRED
860 && type != PTHREAD_CANCEL_ASYNCHRONOUS)
861 return EINVAL;
862 assert(-1 != PTHREAD_CANCEL_DEFERRED);
863 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
864 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
865 VG_USERREQ__SET_CANCELTYPE,
866 type, 0, 0, 0);
867 assert(res != -1);
868 if (oldtype)
869 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +0000870 return 0;
871}
872
sewardje663cb92002-04-12 10:26:32 +0000873int pthread_cancel(pthread_t thread)
874{
875 int res;
876 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +0000877 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
878 VG_USERREQ__SET_CANCELPEND,
879 thread, &thread_exit_wrapper, 0, 0);
880 assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +0000881 return res;
882}
883
sewardjd140e442002-05-29 01:21:19 +0000884static __inline__
885void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +0000886{
sewardj20917d82002-05-28 01:36:45 +0000887 int res;
888 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
889 VG_USERREQ__TESTCANCEL,
890 0, 0, 0, 0);
891 assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +0000892}
893
sewardjd140e442002-05-29 01:21:19 +0000894void pthread_testcancel ( void )
895{
896 __my_pthread_testcancel();
897}
898
sewardj20917d82002-05-28 01:36:45 +0000899
sewardjef037c72002-05-30 00:40:03 +0000900/* Not really sure what this is for. I suspect for doing the POSIX
901 requirements for fork() and exec(). We do this internally anyway
902 whenever those syscalls are observed, so this could be superfluous,
903 but hey ...
904*/
sewardj853f55d2002-04-26 00:27:53 +0000905void __pthread_kill_other_threads_np ( void )
906{
sewardjef037c72002-05-30 00:40:03 +0000907 int res;
908 ensure_valgrind("__pthread_kill_other_threads_np");
909 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
910 VG_USERREQ__NUKE_OTHER_THREADS,
911 0, 0, 0, 0);
912 assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +0000913}
914
sewardje663cb92002-04-12 10:26:32 +0000915
sewardjf8f819e2002-04-17 23:21:37 +0000916/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +0000917 SIGNALS
918 ------------------------------------------------ */
919
920#include <signal.h>
921
922int pthread_sigmask(int how, const sigset_t *newmask,
923 sigset_t *oldmask)
924{
925 int res;
926
927 /* A bit subtle, because the scheduler expects newmask and oldmask
928 to be vki_sigset_t* rather than sigset_t*, and the two are
929 different. Fortunately the first 64 bits of a sigset_t are
930 exactly a vki_sigset_t, so we just pass the pointers through
931 unmodified. Haaaack!
932
933 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +0000934 constants to VKI_ constants, so that the former do not have to
935 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +0000936
937 ensure_valgrind("pthread_sigmask");
938
939 switch (how) {
sewardj018f7622002-05-15 21:13:39 +0000940 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
941 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
942 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardjb48e5002002-05-13 00:16:03 +0000943 default: return EINVAL;
944 }
945
946 /* Crude check */
947 if (newmask == NULL)
948 return EFAULT;
949
950 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
951 VG_USERREQ__PTHREAD_SIGMASK,
952 how, newmask, oldmask, 0);
953
954 /* The scheduler tells us of any memory violations. */
955 return res == 0 ? 0 : EFAULT;
956}
957
958
959int sigwait ( const sigset_t* set, int* sig )
960{
961 int res;
962 ensure_valgrind("sigwait");
963 /* As with pthread_sigmask we deliberately confuse sigset_t with
964 vki_ksigset_t. */
965 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
966 VG_USERREQ__SIGWAIT,
967 set, sig, 0, 0);
968 return res;
969}
970
971
sewardj018f7622002-05-15 21:13:39 +0000972int pthread_kill(pthread_t thread, int signo)
973{
974 int res;
975 ensure_valgrind("pthread_kill");
976 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
977 VG_USERREQ__PTHREAD_KILL,
978 thread, signo, 0, 0);
979 return res;
980}
981
982
sewardj3665ded2002-05-16 16:57:25 +0000983/* Copied verbatim from Linuxthreads */
984/* Redefine raise() to send signal to calling thread only,
985 as per POSIX 1003.1c */
986int raise (int sig)
987{
988 int retcode = pthread_kill(pthread_self(), sig);
989 if (retcode == 0)
990 return 0;
991 else {
992 errno = retcode;
993 return -1;
994 }
995}
996
997
sewardjb48e5002002-05-13 00:16:03 +0000998/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000999 THREAD-SPECIFICs
1000 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001001
sewardj5905fae2002-04-26 13:25:00 +00001002int __pthread_key_create(pthread_key_t *key,
1003 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001004{
sewardj5f07b662002-04-23 16:52:51 +00001005 int res;
1006 ensure_valgrind("pthread_key_create");
1007 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1008 VG_USERREQ__PTHREAD_KEY_CREATE,
1009 key, destr_function, 0, 0);
1010 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001011}
1012
1013int pthread_key_delete(pthread_key_t key)
1014{
sewardj436e0582002-04-26 14:31:40 +00001015 static int moans = N_MOANS;
1016 if (moans-- > 0)
1017 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +00001018 return 0;
1019}
1020
sewardj5905fae2002-04-26 13:25:00 +00001021int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001022{
sewardj5f07b662002-04-23 16:52:51 +00001023 int res;
1024 ensure_valgrind("pthread_setspecific");
1025 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1026 VG_USERREQ__PTHREAD_SETSPECIFIC,
1027 key, pointer, 0, 0);
1028 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001029}
1030
sewardj5905fae2002-04-26 13:25:00 +00001031void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001032{
sewardj5f07b662002-04-23 16:52:51 +00001033 int res;
1034 ensure_valgrind("pthread_getspecific");
1035 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1036 VG_USERREQ__PTHREAD_GETSPECIFIC,
1037 key, 0 , 0, 0);
1038 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001039}
1040
sewardjf8f819e2002-04-17 23:21:37 +00001041
1042/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001043 ONCEry
1044 ------------------------------------------------ */
1045
1046static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1047
1048
sewardj5905fae2002-04-26 13:25:00 +00001049int __pthread_once ( pthread_once_t *once_control,
1050 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001051{
1052 int res;
1053 ensure_valgrind("pthread_once");
1054
sewardj68b2dd92002-05-10 21:03:56 +00001055 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001056
sewardj68b2dd92002-05-10 21:03:56 +00001057 if (res != 0) {
1058 printf("res = %d\n",res);
sewardj89d3d852002-04-24 19:21:39 +00001059 barf("pthread_once: Looks like your program's "
1060 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001061 }
sewardj89d3d852002-04-24 19:21:39 +00001062
1063 if (*once_control == 0) {
1064 *once_control = 1;
1065 init_routine();
1066 }
1067
sewardj68b2dd92002-05-10 21:03:56 +00001068 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001069
1070 return 0;
1071}
1072
1073
1074/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001075 MISC
1076 ------------------------------------------------ */
1077
sewardj5905fae2002-04-26 13:25:00 +00001078int __pthread_atfork ( void (*prepare)(void),
1079 void (*parent)(void),
1080 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001081{
sewardjccef2e62002-05-29 19:26:32 +00001082 /* We have to do this properly or not at all; faking it isn't an
1083 option. */
1084 vgPlain_unimp("__pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +00001085}
1086
1087
sewardjbb990782002-05-08 02:01:14 +00001088__attribute__((weak))
1089void __pthread_initialize ( void )
1090{
sewardjbea1caa2002-05-10 23:20:58 +00001091 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001092}
1093
1094
sewardj853f55d2002-04-26 00:27:53 +00001095/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001096 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001097 ------------------------------------------------ */
1098
sewardj3b13f0e2002-04-25 20:17:29 +00001099#include <resolv.h>
1100static int thread_specific_errno[VG_N_THREADS];
1101static int thread_specific_h_errno[VG_N_THREADS];
1102static struct __res_state
1103 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001104
sewardj3b13f0e2002-04-25 20:17:29 +00001105int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001106{
1107 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001108 /* ensure_valgrind("__errno_location"); */
1109 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001110 VG_USERREQ__PTHREAD_GET_THREADID,
1111 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001112 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001113 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001114 barf("__errno_location: invalid ThreadId");
1115 return & thread_specific_errno[tid];
1116}
1117
1118int* __h_errno_location ( void )
1119{
1120 int tid;
1121 /* ensure_valgrind("__h_errno_location"); */
1122 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1123 VG_USERREQ__PTHREAD_GET_THREADID,
1124 0, 0, 0, 0);
1125 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001126 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001127 barf("__h_errno_location: invalid ThreadId");
1128 return & thread_specific_h_errno[tid];
1129}
1130
1131struct __res_state* __res_state ( void )
1132{
1133 int tid;
1134 /* ensure_valgrind("__res_state"); */
1135 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1136 VG_USERREQ__PTHREAD_GET_THREADID,
1137 0, 0, 0, 0);
1138 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001139 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001140 barf("__res_state: invalid ThreadId");
1141 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001142}
1143
1144
sewardj5716dbb2002-04-26 03:28:18 +00001145/* ---------------------------------------------------
1146 LIBC-PRIVATE SPECIFIC DATA
1147 ------------------------------------------------ */
1148
1149/* Relies on assumption that initial private data is NULL. This
1150 should be fixed somehow. */
1151
1152/* The allowable keys (indices) (all 2 of them).
1153 From sysdeps/pthread/bits/libc-tsd.h
1154*/
sewardj70adeb22002-04-27 01:35:38 +00001155#define N_LIBC_TSD_EXTRA_KEYS 1
1156
sewardj5716dbb2002-04-26 03:28:18 +00001157enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1158 _LIBC_TSD_KEY_DL_ERROR,
1159 _LIBC_TSD_KEY_N };
1160
1161/* Auto-initialising subsystem. libc_specifics_inited is set
1162 after initialisation. libc_specifics_inited_mx guards it. */
1163static int libc_specifics_inited = 0;
1164static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1165
1166/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001167static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1168 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001169
1170/* Initialise the keys, if they are not already initialise. */
1171static
1172void init_libc_tsd_keys ( void )
1173{
1174 int res, i;
1175 pthread_key_t k;
1176
1177 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1178 if (res != 0) barf("init_libc_tsd_keys: lock");
1179
1180 if (libc_specifics_inited == 0) {
1181 /* printf("INIT libc specifics\n"); */
1182 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001183 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001184 res = pthread_key_create(&k, NULL);
1185 if (res != 0) barf("init_libc_tsd_keys: create");
1186 libc_specifics_keys[i] = k;
1187 }
1188 }
1189
1190 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1191 if (res != 0) barf("init_libc_tsd_keys: unlock");
1192}
1193
1194
1195static int
1196libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1197 const void * pointer )
1198{
sewardj70adeb22002-04-27 01:35:38 +00001199 int res;
1200 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001201 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001202 if (key < _LIBC_TSD_KEY_MALLOC
1203 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001204 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001205 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1206 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001207 "valgrind's libpthread.so: libc_internal_tsd_set: "
1208 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001209 init_libc_tsd_keys();
1210 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1211 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1212 return 0;
1213}
1214
1215static void *
1216libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1217{
sewardj70adeb22002-04-27 01:35:38 +00001218 void* v;
1219 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001220 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001221 if (key < _LIBC_TSD_KEY_MALLOC
1222 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001223 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001224 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1225 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001226 "valgrind's libpthread.so: libc_internal_tsd_get: "
1227 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001228 init_libc_tsd_keys();
1229 v = pthread_getspecific(libc_specifics_keys[key]);
1230 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1231 return v;
1232}
1233
1234
1235
1236
sewardj70adeb22002-04-27 01:35:38 +00001237int (*__libc_internal_tsd_set)
1238 (enum __libc_tsd_key_t key, const void * pointer)
1239 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001240
sewardj70adeb22002-04-27 01:35:38 +00001241void* (*__libc_internal_tsd_get)
1242 (enum __libc_tsd_key_t key)
1243 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001244
1245
sewardje663cb92002-04-12 10:26:32 +00001246/* ---------------------------------------------------------------------
1247 These are here (I think) because they are deemed cancellation
1248 points by POSIX. For the moment we'll simply pass the call along
1249 to the corresponding thread-unaware (?) libc routine.
1250 ------------------------------------------------------------------ */
1251
sewardje663cb92002-04-12 10:26:32 +00001252#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001253#include <sys/types.h>
1254#include <sys/socket.h>
1255
sewardjd529a442002-05-04 19:49:21 +00001256#ifdef GLIBC_2_1
1257extern
1258int __sigaction
1259 (int signum,
1260 const struct sigaction *act,
1261 struct sigaction *oldact);
1262#else
sewardje663cb92002-04-12 10:26:32 +00001263extern
1264int __libc_sigaction
1265 (int signum,
1266 const struct sigaction *act,
1267 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001268#endif
sewardje663cb92002-04-12 10:26:32 +00001269int sigaction(int signum,
1270 const struct sigaction *act,
1271 struct sigaction *oldact)
1272{
sewardjd140e442002-05-29 01:21:19 +00001273 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001274# ifdef GLIBC_2_1
1275 return __sigaction(signum, act, oldact);
1276# else
sewardj45b4b372002-04-16 22:50:32 +00001277 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001278# endif
sewardje663cb92002-04-12 10:26:32 +00001279}
1280
1281
1282extern
1283int __libc_connect(int sockfd,
1284 const struct sockaddr *serv_addr,
1285 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001286__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001287int connect(int sockfd,
1288 const struct sockaddr *serv_addr,
1289 socklen_t addrlen)
1290{
sewardjd140e442002-05-29 01:21:19 +00001291 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001292 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001293}
1294
1295
1296extern
1297int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001298__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001299int fcntl(int fd, int cmd, long arg)
1300{
sewardjd140e442002-05-29 01:21:19 +00001301 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001302 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001303}
1304
1305
1306extern
1307ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001308__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001309ssize_t write(int fd, const void *buf, size_t count)
1310{
sewardjd140e442002-05-29 01:21:19 +00001311 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001312 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001313}
1314
1315
1316extern
1317ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001318__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001319ssize_t read(int fd, void *buf, size_t count)
1320{
sewardjd140e442002-05-29 01:21:19 +00001321 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001322 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001323}
1324
sewardjbe32e452002-04-24 20:29:58 +00001325
1326extern
sewardj853f55d2002-04-26 00:27:53 +00001327int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001328__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001329int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001330{
sewardjd140e442002-05-29 01:21:19 +00001331 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001332 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001333}
1334
sewardje663cb92002-04-12 10:26:32 +00001335
1336extern
sewardj853f55d2002-04-26 00:27:53 +00001337int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001338__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001339int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001340{
sewardjd140e442002-05-29 01:21:19 +00001341 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001342 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001343}
1344
1345
1346extern
1347int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001348__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001349int close(int fd)
1350{
sewardjd140e442002-05-29 01:21:19 +00001351 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001352 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001353}
1354
1355
1356extern
1357int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001358__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001359int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1360{
sewardjd140e442002-05-29 01:21:19 +00001361 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001362 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001363 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001364 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001365}
1366
1367
1368extern
1369pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001370pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001371{
sewardjd140e442002-05-29 01:21:19 +00001372 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001373 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001374}
1375
1376
1377extern
1378pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001379__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001380pid_t waitpid(pid_t pid, int *status, int options)
1381{
sewardjd140e442002-05-29 01:21:19 +00001382 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001383 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001384}
1385
1386
1387extern
1388int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001389__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001390int nanosleep(const struct timespec *req, struct timespec *rem)
1391{
sewardjd140e442002-05-29 01:21:19 +00001392 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001393 return __libc_nanosleep(req, rem);
1394}
1395
sewardjbe32e452002-04-24 20:29:58 +00001396
sewardje663cb92002-04-12 10:26:32 +00001397extern
1398int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001399__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001400int fsync(int fd)
1401{
sewardjd140e442002-05-29 01:21:19 +00001402 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001403 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001404}
1405
sewardjbe32e452002-04-24 20:29:58 +00001406
sewardj70c75362002-04-13 04:18:32 +00001407extern
1408off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001409__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001410off_t lseek(int fildes, off_t offset, int whence)
1411{
sewardjd140e442002-05-29 01:21:19 +00001412 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001413 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001414}
1415
sewardjbe32e452002-04-24 20:29:58 +00001416
1417extern
1418__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001419__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001420__off64_t lseek64(int fildes, __off64_t offset, int whence)
1421{
sewardjd140e442002-05-29 01:21:19 +00001422 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001423 return __libc_lseek64(fildes, offset, whence);
1424}
1425
1426
sewardj726c4122002-05-16 23:39:10 +00001427extern
1428ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1429 __off64_t __offset);
1430ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1431 __off64_t __offset)
1432{
sewardjd140e442002-05-29 01:21:19 +00001433 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001434 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1435}
1436
1437
sewardja18e2102002-05-18 10:43:22 +00001438extern
1439ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1440 __off64_t __offset);
1441ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1442 __off64_t __offset)
1443{
sewardjd140e442002-05-29 01:21:19 +00001444 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001445 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1446}
1447
sewardj726c4122002-05-16 23:39:10 +00001448
sewardj39b93b12002-05-18 10:56:27 +00001449extern
1450ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1451__attribute__((weak))
1452ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1453{
sewardjd140e442002-05-29 01:21:19 +00001454 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001455 return __libc_pwrite(fd, buf, count, offset);
1456}
1457
1458
1459extern
1460ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1461__attribute__((weak))
1462ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1463{
sewardjd140e442002-05-29 01:21:19 +00001464 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001465 return __libc_pread(fd, buf, count, offset);
1466}
1467
1468
sewardj6af4b5d2002-04-16 04:40:49 +00001469extern
1470void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001471/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001472void longjmp(jmp_buf env, int val)
1473{
sewardjd140e442002-05-29 01:21:19 +00001474 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001475 __libc_longjmp(env, val);
1476}
1477
sewardjbe32e452002-04-24 20:29:58 +00001478
sewardj6af4b5d2002-04-16 04:40:49 +00001479extern
1480int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001481__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001482int send(int s, const void *msg, size_t len, int flags)
1483{
sewardjd140e442002-05-29 01:21:19 +00001484 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001485 return __libc_send(s, msg, len, flags);
1486}
1487
sewardjbe32e452002-04-24 20:29:58 +00001488
sewardj1e8cdc92002-04-18 11:37:52 +00001489extern
1490int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001491__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001492int recv(int s, void *buf, size_t len, int flags)
1493{
sewardjd140e442002-05-29 01:21:19 +00001494 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001495 return __libc_recv(s, buf, len, flags);
1496}
1497
sewardjbe32e452002-04-24 20:29:58 +00001498
sewardj3665ded2002-05-16 16:57:25 +00001499extern
1500int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1501__attribute__((weak))
1502int sendmsg(int s, const struct msghdr *msg, int flags)
1503{
sewardjd140e442002-05-29 01:21:19 +00001504 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001505 return __libc_sendmsg(s, msg, flags);
1506}
1507
1508
sewardj796d6a22002-04-24 02:28:34 +00001509extern
sewardj436e0582002-04-26 14:31:40 +00001510int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1511 struct sockaddr *from, socklen_t *fromlen);
1512__attribute__((weak))
1513int recvfrom(int s, void *buf, size_t len, int flags,
1514 struct sockaddr *from, socklen_t *fromlen)
1515{
sewardjd140e442002-05-29 01:21:19 +00001516 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001517 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1518}
1519
1520
1521extern
sewardj796d6a22002-04-24 02:28:34 +00001522int __libc_sendto(int s, const void *msg, size_t len, int flags,
1523 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001524__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001525int sendto(int s, const void *msg, size_t len, int flags,
1526 const struct sockaddr *to, socklen_t tolen)
1527{
sewardjd140e442002-05-29 01:21:19 +00001528 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001529 return __libc_sendto(s, msg, len, flags, to, tolen);
1530}
1531
sewardjbe32e452002-04-24 20:29:58 +00001532
sewardj369b1702002-04-24 13:28:15 +00001533extern
1534int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001535__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001536int system(const char* str)
1537{
sewardjd140e442002-05-29 01:21:19 +00001538 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001539 return __libc_system(str);
1540}
1541
sewardjbe32e452002-04-24 20:29:58 +00001542
sewardjab0b1c32002-04-24 19:26:47 +00001543extern
1544pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001545__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001546pid_t wait(int *status)
1547{
sewardjd140e442002-05-29 01:21:19 +00001548 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00001549 return __libc_wait(status);
1550}
1551
sewardj45b4b372002-04-16 22:50:32 +00001552
sewardj67f1d582002-05-24 02:11:32 +00001553extern
1554int __libc_msync(const void *start, size_t length, int flags);
1555__attribute__((weak))
1556int msync(const void *start, size_t length, int flags)
1557{
sewardjd140e442002-05-29 01:21:19 +00001558 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00001559 return __libc_msync(start, length, flags);
1560}
1561
sewardj5905fae2002-04-26 13:25:00 +00001562
sewardj3b13f0e2002-04-25 20:17:29 +00001563/* ---------------------------------------------------------------------
1564 Nonblocking implementations of select() and poll(). This stuff will
1565 surely rot your mind.
1566 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001567
sewardj08a4c3f2002-04-13 03:45:44 +00001568/*--------------------------------------------------*/
1569
1570#include "vg_kerneliface.h"
1571
1572static
1573__inline__
1574int is_kerror ( int res )
1575{
1576 if (res >= -4095 && res <= -1)
1577 return 1;
1578 else
1579 return 0;
1580}
1581
1582
1583static
1584int my_do_syscall1 ( int syscallno, int arg1 )
1585{
1586 int __res;
1587 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1588 : "=a" (__res)
1589 : "0" (syscallno),
1590 "d" (arg1) );
1591 return __res;
1592}
1593
1594static
1595int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001596 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001597{
1598 int __res;
1599 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1600 : "=a" (__res)
1601 : "0" (syscallno),
1602 "d" (arg1),
1603 "c" (arg2) );
1604 return __res;
1605}
1606
1607static
sewardjf854f472002-04-21 12:19:41 +00001608int my_do_syscall3 ( int syscallno,
1609 int arg1, int arg2, int arg3 )
1610{
1611 int __res;
1612 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1613 : "=a" (__res)
1614 : "0" (syscallno),
1615 "S" (arg1),
1616 "c" (arg2),
1617 "d" (arg3) );
1618 return __res;
1619}
1620
1621static
sewardj08a4c3f2002-04-13 03:45:44 +00001622int do_syscall_select( int n,
1623 vki_fd_set* readfds,
1624 vki_fd_set* writefds,
1625 vki_fd_set* exceptfds,
1626 struct vki_timeval * timeout )
1627{
1628 int res;
1629 int args[5];
1630 args[0] = n;
1631 args[1] = (int)readfds;
1632 args[2] = (int)writefds;
1633 args[3] = (int)exceptfds;
1634 args[4] = (int)timeout;
1635 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001636 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001637}
1638
1639
1640/* This is a wrapper round select(), which makes it thread-safe,
1641 meaning that only this thread will block, rather than the entire
1642 process. This wrapper in turn depends on nanosleep() not to block
1643 the entire process, but I think (hope? suspect?) that POSIX
1644 pthreads guarantees that to be the case.
1645
1646 Basic idea is: modify the timeout parameter to select so that it
1647 returns immediately. Poll like this until select returns non-zero,
1648 indicating something interesting happened, or until our time is up.
1649 Space out the polls with nanosleeps of say 20 milliseconds, which
1650 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001651
1652 Assumes:
1653 * (checked via assert) types fd_set and vki_fd_set are identical.
1654 * (checked via assert) types timeval and vki_timeval are identical.
1655 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1656 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001657*/
sewardj08a4c3f2002-04-13 03:45:44 +00001658
sewardj5905fae2002-04-26 13:25:00 +00001659/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001660int select ( int n,
1661 fd_set *rfds,
1662 fd_set *wfds,
1663 fd_set *xfds,
1664 struct timeval *timeout )
1665{
sewardj5f07b662002-04-23 16:52:51 +00001666 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001667 int res;
1668 fd_set rfds_copy;
1669 fd_set wfds_copy;
1670 fd_set xfds_copy;
1671 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001672 struct vki_timeval zero_timeout;
1673 struct vki_timespec nanosleep_interval;
1674
sewardjd140e442002-05-29 01:21:19 +00001675 __my_pthread_testcancel();
1676
sewardj5f07b662002-04-23 16:52:51 +00001677 /* gcc's complains about ms_end being used uninitialised -- classic
1678 case it can't understand, where ms_end is both defined and used
1679 only if timeout != NULL. Hence ... */
1680 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001681
1682 /* We assume that the kernel and libc data layouts are identical
1683 for the following types. These asserts provide a crude
1684 check. */
1685 if (sizeof(fd_set) != sizeof(vki_fd_set)
1686 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1687 barf("valgrind's hacky non-blocking select(): data sizes error");
1688
sewardj5f07b662002-04-23 16:52:51 +00001689 /* Detect the current time and simultaneously find out if we are
1690 running on Valgrind. */
1691 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1692 VG_USERREQ__READ_MILLISECOND_TIMER,
1693 0, 0, 0, 0);
1694
1695 /* If a zero timeout specified, this call is harmless. Also go
1696 this route if we're not running on Valgrind, for whatever
1697 reason. */
1698 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1699 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001700 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001701 (vki_fd_set*)wfds,
1702 (vki_fd_set*)xfds,
1703 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001704 if (is_kerror(res)) {
1705 * (__errno_location()) = -res;
1706 return -1;
1707 } else {
1708 return res;
1709 }
1710 }
sewardj08a4c3f2002-04-13 03:45:44 +00001711
sewardj5f07b662002-04-23 16:52:51 +00001712 /* If a timeout was specified, set ms_end to be the end millisecond
1713 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001714 if (timeout) {
1715 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
1716 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001717 ms_end = ms_now;
1718 ms_end += (timeout->tv_usec / 1000);
1719 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001720 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +00001721 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001722 }
1723
1724 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1725
1726 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001727 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001728 while (1) {
1729 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +00001730 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1731 VG_USERREQ__READ_MILLISECOND_TIMER,
1732 0, 0, 0, 0);
1733 assert(ms_now != 0xFFFFFFFF);
1734 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +00001735 /* timeout; nothing interesting happened. */
1736 if (rfds) FD_ZERO(rfds);
1737 if (wfds) FD_ZERO(wfds);
1738 if (xfds) FD_ZERO(xfds);
1739 return 0;
1740 }
1741 }
1742
1743 /* These could be trashed each time round the loop, so restore
1744 them each time. */
1745 if (rfds) rfds_copy = *rfds;
1746 if (wfds) wfds_copy = *wfds;
1747 if (xfds) xfds_copy = *xfds;
1748
1749 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1750
1751 res = do_syscall_select( n,
1752 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1753 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1754 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1755 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001756 if (is_kerror(res)) {
1757 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001758 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001759 * (__errno_location()) = -res;
1760 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001761 }
1762 if (res > 0) {
1763 /* one or more fds is ready. Copy out resulting sets and
1764 return. */
1765 if (rfds) *rfds = rfds_copy;
1766 if (wfds) *wfds = wfds_copy;
1767 if (xfds) *xfds = xfds_copy;
1768 return res;
1769 }
1770 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1771 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001772 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001773 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001774 /* It's critical here that valgrind's nanosleep implementation
1775 is nonblocking. */
1776 (void)my_do_syscall2(__NR_nanosleep,
1777 (int)(&nanosleep_interval), (int)NULL);
1778 }
1779}
1780
1781
1782
1783
1784#include <sys/poll.h>
1785
sewardj72d58482002-04-24 02:20:20 +00001786#ifdef GLIBC_2_1
1787typedef unsigned long int nfds_t;
1788#endif
1789
sewardj705d3cb2002-05-23 13:13:12 +00001790
sewardj5905fae2002-04-26 13:25:00 +00001791/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00001792int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1793{
sewardj5f07b662002-04-23 16:52:51 +00001794 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001795 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001796 struct vki_timespec nanosleep_interval;
1797
sewardjd140e442002-05-29 01:21:19 +00001798 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00001799 ensure_valgrind("poll");
1800
sewardj5f07b662002-04-23 16:52:51 +00001801 /* Detect the current time and simultaneously find out if we are
1802 running on Valgrind. */
1803 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1804 VG_USERREQ__READ_MILLISECOND_TIMER,
1805 0, 0, 0, 0);
1806
sewardjf854f472002-04-21 12:19:41 +00001807 if (/* CHECK SIZES FOR struct pollfd */
1808 sizeof(struct timeval) != sizeof(struct vki_timeval))
1809 barf("valgrind's hacky non-blocking poll(): data sizes error");
1810
sewardj5f07b662002-04-23 16:52:51 +00001811 /* dummy initialisation to keep gcc -Wall happy */
1812 ms_end = 0;
1813
1814 /* If a zero timeout specified, this call is harmless. Also do
1815 this if not running on Valgrind. */
1816 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001817 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1818 if (is_kerror(res)) {
1819 * (__errno_location()) = -res;
1820 return -1;
1821 } else {
1822 return res;
1823 }
1824 }
1825
sewardj5f07b662002-04-23 16:52:51 +00001826 /* If a timeout was specified, set ms_end to be the end wallclock
1827 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001828 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00001829 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001830 }
1831
1832 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1833
1834 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1835 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001836 assert(__timeout != 0);
1837
sewardjf854f472002-04-21 12:19:41 +00001838 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001839 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001840 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1841 VG_USERREQ__READ_MILLISECOND_TIMER,
1842 0, 0, 0, 0);
1843 assert(ms_now != 0xFFFFFFFF);
1844 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001845 /* timeout; nothing interesting happened. */
1846 for (i = 0; i < __nfds; i++)
1847 __fds[i].revents = 0;
1848 return 0;
1849 }
1850 }
1851
sewardj5f07b662002-04-23 16:52:51 +00001852 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001853 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1854 if (is_kerror(res)) {
1855 /* Some kind of error. Set errno and return. */
1856 * (__errno_location()) = -res;
1857 return -1;
1858 }
1859 if (res > 0) {
1860 /* One or more fds is ready. Return now. */
1861 return res;
1862 }
1863 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1864 /* nanosleep and go round again */
1865 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001866 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001867 /* It's critical here that valgrind's nanosleep implementation
1868 is nonblocking. */
1869 (void)my_do_syscall2(__NR_nanosleep,
1870 (int)(&nanosleep_interval), (int)NULL);
1871 }
1872}
sewardj3b13f0e2002-04-25 20:17:29 +00001873
1874
sewardj705d3cb2002-05-23 13:13:12 +00001875/* Helper function used to make accept() non-blocking. Idea is to use
1876 the above nonblocking poll() to make this thread ONLY wait for the
1877 specified fd to become ready, and then return. */
1878static void wait_for_fd_to_be_readable_or_erring ( int fd )
1879{
1880 struct pollfd pfd;
sewardj6e6cbaa2002-05-24 02:12:52 +00001881 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardj705d3cb2002-05-23 13:13:12 +00001882 pfd.fd = fd;
1883 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
1884 /* ... but not POLLOUT, you may notice. */
1885 pfd.revents = 0;
1886 (void)poll(&pfd, 1, -1 /* forever */);
1887}
1888
1889
sewardj3b13f0e2002-04-25 20:17:29 +00001890/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00001891 Hacky implementation of semaphores.
1892 ------------------------------------------------------------------ */
1893
1894#include <semaphore.h>
1895
1896/* This is a terrible way to do the remapping. Plan is to import an
1897 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00001898
1899typedef
1900 struct {
1901 pthread_mutex_t se_mx;
1902 pthread_cond_t se_cv;
1903 int count;
1904 }
1905 vg_sem_t;
1906
1907static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
1908
1909static int se_remap_used = 0;
1910static sem_t* se_remap_orig[VG_N_SEMAPHORES];
1911static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
1912
1913static vg_sem_t* se_remap ( sem_t* orig )
1914{
1915 int res, i;
1916 res = __pthread_mutex_lock(&se_remap_mx);
1917 assert(res == 0);
1918
1919 for (i = 0; i < se_remap_used; i++) {
1920 if (se_remap_orig[i] == orig)
1921 break;
1922 }
1923 if (i == se_remap_used) {
1924 if (se_remap_used == VG_N_SEMAPHORES) {
1925 res = pthread_mutex_unlock(&se_remap_mx);
1926 assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00001927 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00001928 }
1929 se_remap_used++;
1930 se_remap_orig[i] = orig;
1931 /* printf("allocated semaphore %d\n", i); */
1932 }
1933 res = __pthread_mutex_unlock(&se_remap_mx);
1934 assert(res == 0);
1935 return &se_remap_new[i];
1936}
1937
1938
1939int sem_init(sem_t *sem, int pshared, unsigned int value)
1940{
1941 int res;
1942 vg_sem_t* vg_sem;
1943 ensure_valgrind("sem_init");
1944 if (pshared != 0) {
1945 errno = ENOSYS;
1946 return -1;
1947 }
1948 vg_sem = se_remap(sem);
1949 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
1950 assert(res == 0);
1951 res = pthread_cond_init(&vg_sem->se_cv, NULL);
1952 assert(res == 0);
1953 vg_sem->count = value;
1954 return 0;
1955}
1956
1957
1958int sem_wait ( sem_t* sem )
1959{
1960 int res;
1961 vg_sem_t* vg_sem;
1962 ensure_valgrind("sem_wait");
1963 vg_sem = se_remap(sem);
1964 res = __pthread_mutex_lock(&vg_sem->se_mx);
1965 assert(res == 0);
1966 while (vg_sem->count == 0) {
1967 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
1968 assert(res == 0);
1969 }
1970 vg_sem->count--;
1971 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1972 assert(res == 0);
1973 return 0;
1974}
1975
1976int sem_post ( sem_t* sem )
1977{
1978 int res;
1979 vg_sem_t* vg_sem;
1980 ensure_valgrind("sem_post");
1981 vg_sem = se_remap(sem);
1982 res = __pthread_mutex_lock(&vg_sem->se_mx);
1983 assert(res == 0);
1984 if (vg_sem->count == 0) {
1985 vg_sem->count++;
1986 res = pthread_cond_broadcast(&vg_sem->se_cv);
1987 assert(res == 0);
1988 } else {
1989 vg_sem->count++;
1990 }
1991 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1992 assert(res == 0);
1993 return 0;
1994}
1995
1996
1997int sem_trywait ( sem_t* sem )
1998{
1999 int ret, res;
2000 vg_sem_t* vg_sem;
2001 ensure_valgrind("sem_trywait");
2002 vg_sem = se_remap(sem);
2003 res = __pthread_mutex_lock(&vg_sem->se_mx);
2004 assert(res == 0);
2005 if (vg_sem->count > 0) {
2006 vg_sem->count--;
2007 ret = 0;
2008 } else {
2009 ret = -1;
2010 errno = EAGAIN;
2011 }
2012 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2013 assert(res == 0);
2014 return ret;
2015}
2016
2017
2018int sem_getvalue(sem_t* sem, int * sval)
2019{
2020 vg_sem_t* vg_sem;
2021 ensure_valgrind("sem_trywait");
2022 vg_sem = se_remap(sem);
2023 *sval = vg_sem->count;
2024 return 0;
2025}
2026
2027
2028int sem_destroy(sem_t * sem)
2029{
2030 kludged("sem_destroy");
2031 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2032 return 0;
2033}
2034
2035
2036/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002037 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002038 ------------------------------------------------------------------ */
2039
sewardj2d8b3f02002-06-01 14:14:19 +00002040typedef
2041 struct {
2042 int initted; /* != 0 --> in use; sanity check only */
2043 int prefer_w; /* != 0 --> prefer writer */
2044 int nwait_r; /* # of waiting readers */
2045 int nwait_w; /* # of waiting writers */
2046 pthread_cond_t cv_r; /* for signalling readers */
2047 pthread_cond_t cv_w; /* for signalling writers */
2048 pthread_mutex_t mx;
2049 int status;
2050 /* allowed range for status: >= -1. -1 means 1 writer currently
2051 active, >= 0 means N readers currently active. */
2052 }
2053 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002054
2055
2056static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2057
2058static int rw_remap_used = 0;
2059static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2060static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2061
sewardj2d8b3f02002-06-01 14:14:19 +00002062
2063static
2064void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2065{
2066 int res = 0;
2067 vg_rwl->initted = 1;
2068 vg_rwl->prefer_w = 1;
2069 vg_rwl->nwait_r = 0;
2070 vg_rwl->nwait_w = 0;
2071 vg_rwl->status = 0;
2072 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2073 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2074 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
2075 assert(res == 0);
2076}
2077
2078
sewardja1ac5cb2002-05-27 13:00:05 +00002079/* Take the address of a LinuxThreads rwlock_t and return the shadow
2080 address of our version. Further, if the LinuxThreads version
2081 appears to have been statically initialised, do the same to the one
2082 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2083 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2084 uninitialised and non-zero meaning initialised.
2085*/
2086static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2087{
2088 int res, i;
2089 vg_rwlock_t* vg_rwl;
2090 res = __pthread_mutex_lock(&rw_remap_mx);
2091 assert(res == 0);
2092
2093 for (i = 0; i < rw_remap_used; i++) {
2094 if (rw_remap_orig[i] == orig)
2095 break;
2096 }
2097 if (i == rw_remap_used) {
2098 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002099 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002100 assert(res == 0);
2101 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2102 }
2103 rw_remap_used++;
2104 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002105 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002106 if (0) printf("allocated rwlock %d\n", i);
2107 }
2108 res = __pthread_mutex_unlock(&rw_remap_mx);
2109 assert(res == 0);
2110 vg_rwl = &rw_remap_new[i];
2111
sewardj2d8b3f02002-06-01 14:14:19 +00002112 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002113 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002114 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002115 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002116 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002117 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002118 }
2119
2120 return vg_rwl;
2121}
2122
2123
sewardja1ac5cb2002-05-27 13:00:05 +00002124int pthread_rwlock_init ( pthread_rwlock_t* orig,
2125 const pthread_rwlockattr_t* attr )
2126{
sewardja1ac5cb2002-05-27 13:00:05 +00002127 vg_rwlock_t* rwl;
2128 if (0) printf ("pthread_rwlock_init\n");
2129 /* Force the remapper to initialise the shadow. */
2130 orig->__rw_readers = 0;
2131 /* Install the lock preference; the remapper needs to know it. */
2132 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2133 if (attr)
2134 orig->__rw_kind = attr->__lockkind;
2135 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002136 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002137}
2138
sewardj2d8b3f02002-06-01 14:14:19 +00002139
2140static
2141void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002142{
sewardj2d8b3f02002-06-01 14:14:19 +00002143 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2144 rwl->nwait_r--;
2145 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002146}
2147
sewardj2d8b3f02002-06-01 14:14:19 +00002148
sewardja1ac5cb2002-05-27 13:00:05 +00002149int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2150{
2151 int res;
2152 vg_rwlock_t* rwl;
2153 if (0) printf ("pthread_rwlock_rdlock\n");
2154 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002155 res = __pthread_mutex_lock(&rwl->mx);
2156 assert(res == 0);
2157 if (!rwl->initted) {
2158 res = __pthread_mutex_unlock(&rwl->mx);
2159 assert(res == 0);
2160 return EINVAL;
2161 }
2162 if (rwl->status < 0) {
2163 assert(rwl->status == -1);
2164 rwl->nwait_r++;
2165 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2166 while (1) {
2167 if (rwl->status == 0) break;
2168 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
2169 assert(res == 0);
2170 }
2171 pthread_cleanup_pop(0);
2172 rwl->nwait_r--;
2173 }
2174 assert(rwl->status >= 0);
2175 rwl->status++;
2176 res = __pthread_mutex_unlock(&rwl->mx);
2177 assert(res == 0);
2178 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002179}
2180
sewardj2d8b3f02002-06-01 14:14:19 +00002181
sewardja1ac5cb2002-05-27 13:00:05 +00002182int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2183{
2184 int res;
2185 vg_rwlock_t* rwl;
2186 if (0) printf ("pthread_rwlock_tryrdlock\n");
2187 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002188 res = __pthread_mutex_lock(&rwl->mx);
2189 assert(res == 0);
2190 if (!rwl->initted) {
2191 res = __pthread_mutex_unlock(&rwl->mx);
2192 assert(res == 0);
2193 return EINVAL;
2194 }
2195 if (rwl->status == -1) {
2196 /* Writer active; we have to give up. */
2197 res = __pthread_mutex_unlock(&rwl->mx);
2198 assert(res == 0);
2199 return EBUSY;
2200 }
2201 /* Success */
2202 assert(rwl->status >= 0);
2203 rwl->status++;
2204 res = __pthread_mutex_unlock(&rwl->mx);
2205 assert(res == 0);
2206 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002207}
2208
sewardj2d8b3f02002-06-01 14:14:19 +00002209
2210static
2211void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2212{
2213 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2214 rwl->nwait_w--;
2215 pthread_mutex_unlock (&rwl->mx);
2216}
2217
2218
sewardja1ac5cb2002-05-27 13:00:05 +00002219int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2220{
2221 int res;
2222 vg_rwlock_t* rwl;
2223 if (0) printf ("pthread_rwlock_wrlock\n");
2224 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002225 res = __pthread_mutex_lock(&rwl->mx);
2226 assert(res == 0);
2227 if (!rwl->initted) {
2228 res = __pthread_mutex_unlock(&rwl->mx);
2229 assert(res == 0);
2230 return EINVAL;
2231 }
2232 if (rwl->status != 0) {
2233 rwl->nwait_w++;
2234 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2235 while (1) {
2236 if (rwl->status == 0) break;
2237 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
2238 assert(res == 0);
2239 }
2240 pthread_cleanup_pop(0);
2241 rwl->nwait_w--;
2242 }
2243 assert(rwl->status == 0);
2244 rwl->status = -1;
2245 res = __pthread_mutex_unlock(&rwl->mx);
2246 assert(res == 0);
2247 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002248}
2249
sewardj2d8b3f02002-06-01 14:14:19 +00002250
sewardja1ac5cb2002-05-27 13:00:05 +00002251int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2252{
2253 int res;
2254 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002255 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002256 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002257 res = __pthread_mutex_lock(&rwl->mx);
2258 assert(res == 0);
2259 if (!rwl->initted) {
2260 res = __pthread_mutex_unlock(&rwl->mx);
2261 assert(res == 0);
2262 return EINVAL;
2263 }
2264 if (rwl->status != 0) {
2265 /* Reader(s) or a writer active; we have to give up. */
2266 res = __pthread_mutex_unlock(&rwl->mx);
2267 assert(res == 0);
2268 return EBUSY;
2269 }
2270 /* Success */
2271 assert(rwl->status == 0);
2272 rwl->status = -1;
2273 res = __pthread_mutex_unlock(&rwl->mx);
2274 assert(res == 0);
2275 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002276}
2277
sewardj2d8b3f02002-06-01 14:14:19 +00002278
sewardja1ac5cb2002-05-27 13:00:05 +00002279int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2280{
2281 int res;
2282 vg_rwlock_t* rwl;
2283 if (0) printf ("pthread_rwlock_unlock\n");
2284 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002285 rwl = rw_remap ( orig );
2286 res = __pthread_mutex_lock(&rwl->mx);
2287 assert(res == 0);
2288 if (!rwl->initted) {
2289 res = __pthread_mutex_unlock(&rwl->mx);
2290 assert(res == 0);
2291 return EINVAL;
2292 }
2293 if (rwl->status == 0) {
2294 res = __pthread_mutex_unlock(&rwl->mx);
2295 assert(res == 0);
2296 return EPERM;
2297 }
2298 assert(rwl->status != 0);
2299 if (rwl->status == -1) {
2300 rwl->status = 0;
2301 } else {
2302 assert(rwl->status > 0);
2303 rwl->status--;
2304 }
2305
2306 assert(rwl->status >= 0);
2307
2308 if (rwl->prefer_w) {
2309
2310 /* Favour waiting writers, if any. */
2311 if (rwl->nwait_w > 0) {
2312 /* Writer(s) are waiting. */
2313 if (rwl->status == 0) {
2314 /* We can let a writer in. */
2315 res = pthread_cond_signal(&rwl->cv_w);
2316 assert(res == 0);
2317 } else {
2318 /* There are still readers active. Do nothing; eventually
2319 they will disappear, at which point a writer will be
2320 admitted. */
2321 }
2322 }
2323 else
2324 /* No waiting writers. */
2325 if (rwl->nwait_r > 0) {
2326 /* Let in a waiting reader. */
2327 res = pthread_cond_signal(&rwl->cv_r);
2328 assert(res == 0);
2329 }
2330
2331 } else {
2332
2333 /* Favour waiting readers, if any. */
2334 if (rwl->nwait_r > 0) {
2335 /* Reader(s) are waiting; let one in. */
2336 res = pthread_cond_signal(&rwl->cv_r);
2337 assert(res == 0);
2338 }
2339 else
2340 /* No waiting readers. */
2341 if (rwl->nwait_w > 0 && rwl->status == 0) {
2342 /* We have waiting writers and no active readers; let a
2343 writer in. */
2344 res = pthread_cond_signal(&rwl->cv_w);
2345 assert(res == 0);
2346 }
2347 }
2348
2349 res = __pthread_mutex_unlock(&rwl->mx);
2350 assert(res == 0);
2351 return 0;
2352}
2353
2354
2355int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2356{
2357 int res;
2358 vg_rwlock_t* rwl;
2359 if (0) printf ("pthread_rwlock_destroy\n");
2360 rwl = rw_remap ( orig );
2361 res = __pthread_mutex_lock(&rwl->mx);
2362 assert(res == 0);
2363 if (!rwl->initted) {
2364 res = __pthread_mutex_unlock(&rwl->mx);
2365 assert(res == 0);
2366 return EINVAL;
2367 }
2368 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2369 res = __pthread_mutex_unlock(&rwl->mx);
2370 assert(res == 0);
2371 return EBUSY;
2372 }
2373 rwl->initted = 0;
2374 res = __pthread_mutex_unlock(&rwl->mx);
2375 assert(res == 0);
2376 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002377}
2378
2379
2380/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002381 B'stard.
2382 ------------------------------------------------------------------ */
2383
2384# define strong_alias(name, aliasname) \
2385 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2386
sewardj5905fae2002-04-26 13:25:00 +00002387# define weak_alias(name, aliasname) \
2388 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002389
sewardj5905fae2002-04-26 13:25:00 +00002390strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2391strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2392strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2393strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2394 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2395strong_alias(__pthread_mutex_init, pthread_mutex_init)
2396strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2397strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2398strong_alias(__pthread_once, pthread_once)
2399strong_alias(__pthread_atfork, pthread_atfork)
2400strong_alias(__pthread_key_create, pthread_key_create)
2401strong_alias(__pthread_getspecific, pthread_getspecific)
2402strong_alias(__pthread_setspecific, pthread_setspecific)
2403
sewardjd529a442002-05-04 19:49:21 +00002404#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002405strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002406#endif
2407
sewardj5905fae2002-04-26 13:25:00 +00002408strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002409strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002410strong_alias(lseek, __lseek)
2411strong_alias(open, __open)
2412strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002413strong_alias(read, __read)
2414strong_alias(wait, __wait)
2415strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002416strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002417strong_alias(send, __send)
2418
sewardj726c4122002-05-16 23:39:10 +00002419weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002420weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002421weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002422
sewardj5905fae2002-04-26 13:25:00 +00002423
sewardj3b13f0e2002-04-25 20:17:29 +00002424
2425/*--------------------------------------------------*/
2426
sewardj5905fae2002-04-26 13:25:00 +00002427weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002428weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002429weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002430
sewardja1ac5cb2002-05-27 13:00:05 +00002431weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2432weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2433weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2434weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2435
sewardj060b04f2002-04-26 21:01:13 +00002436
sewardj3b13f0e2002-04-25 20:17:29 +00002437/* I've no idea what these are, but they get called quite a lot.
2438 Anybody know? */
2439
2440#undef _IO_flockfile
2441void _IO_flockfile ( _IO_FILE * file )
2442{
sewardj853f55d2002-04-26 00:27:53 +00002443 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002444}
sewardj5905fae2002-04-26 13:25:00 +00002445weak_alias(_IO_flockfile, flockfile);
2446
sewardj3b13f0e2002-04-25 20:17:29 +00002447
2448#undef _IO_funlockfile
2449void _IO_funlockfile ( _IO_FILE * file )
2450{
sewardj853f55d2002-04-26 00:27:53 +00002451 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002452}
sewardj5905fae2002-04-26 13:25:00 +00002453weak_alias(_IO_funlockfile, funlockfile);
2454
sewardj3b13f0e2002-04-25 20:17:29 +00002455
sewardjd4f2c712002-04-30 10:20:10 +00002456/* This doesn't seem to be needed to simulate libpthread.so's external
2457 interface, but many people complain about its absence. */
2458
2459strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2460weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002461
2462
2463/*--------------------------------------------------------------------*/
2464/*--- end vg_libpthread.c ---*/
2465/*--------------------------------------------------------------------*/