blob: 6f51b04aae7c99ab38c88d283ce14c601e909ddf [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/* ---------------------------------------------------------------------
sewardja1ac5cb2002-05-27 13:00:05 +00002037 Hacky implementation of reader-writer locks.
2038 ------------------------------------------------------------------ */
2039
2040/*
2041Errata from 7th printing:
2042
2043 Page 259, rwlock.c, line 27, the two "!=" should be ">", for
2044 consistency with other similar tests. (The values should never be
2045 negative; this isn't a fix, but an improvement to clarity and
2046 consistency.)
2047
2048 [27] if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2049
2050 Page 259, rwlock.c, lines 39 and 40, in both lines, "==" should
2051 become "!=":
2052
2053 [39] return (status != 0 ? status
2054 [40] : (status1 != 0 ? status1 : status2));
2055*/
2056
2057/*
2058 * rwlock.h
2059 *
2060 * This header file describes the "reader/writer lock" synchronization
2061 * construct. The type rwlock_t describes the full state of the lock
2062 * including the POSIX 1003.1c synchronization objects necessary.
2063 *
2064 * A reader/writer lock allows a thread to lock shared data either for shared
2065 * read access or exclusive write access.
2066 *
2067 * The rwl_init() and rwl_destroy() functions, respectively, allow you to
2068 * initialize/create and destroy/free the reader/writer lock.
2069 */
2070
sewardja1ac5cb2002-05-27 13:00:05 +00002071/*
2072 * Structure describing a read-write lock.
2073 */
2074typedef struct {
2075 pthread_mutex_t mutex;
2076 pthread_cond_t read; /* wait for read */
2077 pthread_cond_t write; /* wait for write */
2078 int valid; /* set when valid */
2079 int r_active; /* readers active */
2080 int w_active; /* writer active */
2081 int r_wait; /* readers waiting */
2082 int w_wait; /* writers waiting */
2083 int pref_writer; /* != 0 --> prefer writer */
2084} vg_rwlock_t;
2085
2086#define VG_RWLOCK_VALID 0xfacade
2087
2088
2089/*
2090 * Support static initialization of barriers
2091 */
2092#define VG_RWL_INITIALIZER \
2093 {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \
2094 PTHREAD_COND_INITIALIZER, VG_RWLOCK_VALID, 0, 0, 0, 0, 1}
2095
2096
2097static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2098
2099static int rw_remap_used = 0;
2100static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2101static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2102
2103/* Take the address of a LinuxThreads rwlock_t and return the shadow
2104 address of our version. Further, if the LinuxThreads version
2105 appears to have been statically initialised, do the same to the one
2106 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2107 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2108 uninitialised and non-zero meaning initialised.
2109*/
2110static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2111{
2112 int res, i;
2113 vg_rwlock_t* vg_rwl;
2114 res = __pthread_mutex_lock(&rw_remap_mx);
2115 assert(res == 0);
2116
2117 for (i = 0; i < rw_remap_used; i++) {
2118 if (rw_remap_orig[i] == orig)
2119 break;
2120 }
2121 if (i == rw_remap_used) {
2122 if (rw_remap_used == VG_N_RWLOCKS) {
2123 res = pthread_mutex_unlock(&rw_remap_mx);
2124 assert(res == 0);
2125 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2126 }
2127 rw_remap_used++;
2128 rw_remap_orig[i] = orig;
2129 if (0) printf("allocated rwlock %d\n", i);
2130 }
2131 res = __pthread_mutex_unlock(&rw_remap_mx);
2132 assert(res == 0);
2133 vg_rwl = &rw_remap_new[i];
2134
2135 /* Mimic static initialisation of the original. */
2136 if (orig->__rw_readers == 0) {
2137 const vg_rwlock_t default_rwl = VG_RWL_INITIALIZER;
2138 orig->__rw_readers = 1;
2139 *vg_rwl = default_rwl;
2140 vg_rwl->pref_writer = 1;
2141 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
2142 vg_rwl->pref_writer = 0;
2143 }
2144
2145 return vg_rwl;
2146}
2147
2148
2149/*
2150 * rwlock.c
2151 *
2152 * This file implements the "read-write lock" synchronization
2153 * construct.
2154 *
2155 * A read-write lock allows a thread to lock shared data either
2156 * for shared read access or exclusive write access.
2157 *
2158 * The rwl_init() and rwl_destroy() functions, respectively,
2159 * allow you to initialize/create and destroy/free the
2160 * read-write lock.
2161 *
2162 * The rwl_readlock() function locks a read-write lock for
2163 * shared read access, and rwl_readunlock() releases the
2164 * lock. rwl_readtrylock() attempts to lock a read-write lock
2165 * for read access, and returns EBUSY instead of blocking.
2166 *
2167 * The rwl_writelock() function locks a read-write lock for
2168 * exclusive write access, and rwl_writeunlock() releases the
2169 * lock. rwl_writetrylock() attempts to lock a read-write lock
2170 * for write access, and returns EBUSY instead of blocking.
2171 */
2172
2173
2174/*
2175 * Initialize a read-write lock
2176 */
2177static int rwl_init ( vg_rwlock_t *rwl )
2178{
2179 int status;
2180
2181 rwl->r_active = 0;
2182 rwl->r_wait = rwl->w_wait = 0;
2183 rwl->w_active = 0;
2184 status = pthread_mutex_init (&rwl->mutex, NULL);
2185 if (status != 0)
2186 return status;
2187 status = pthread_cond_init (&rwl->read, NULL);
2188 if (status != 0) {
2189 /* if unable to create read CV, destroy mutex */
2190 pthread_mutex_destroy (&rwl->mutex);
2191 return status;
2192 }
2193 status = pthread_cond_init (&rwl->write, NULL);
2194 if (status != 0) {
2195 /* if unable to create write CV, destroy read CV and mutex */
2196 pthread_cond_destroy (&rwl->read);
2197 pthread_mutex_destroy (&rwl->mutex);
2198 return status;
2199 }
2200 rwl->valid = VG_RWLOCK_VALID;
2201 return 0;
2202}
2203
2204/*
2205 * Destroy a read-write lock
2206 */
2207static int rwl_destroy (vg_rwlock_t *rwl)
2208{
2209 int status, status1, status2;
2210
2211 if (rwl->valid != VG_RWLOCK_VALID)
2212 return EINVAL;
2213 status = pthread_mutex_lock (&rwl->mutex);
2214 if (status != 0)
2215 return status;
2216
2217 /*
2218 * Check whether any threads own the lock; report "BUSY" if
2219 * so.
2220 */
2221 if (rwl->r_active > 0 || rwl->w_active) {
2222 pthread_mutex_unlock (&rwl->mutex);
2223 return EBUSY;
2224 }
2225
2226 /*
2227 * Check whether any threads are known to be waiting; report
2228 * EBUSY if so.
2229 */
2230 if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2231 pthread_mutex_unlock (&rwl->mutex);
2232 return EBUSY;
2233 }
2234
2235 rwl->valid = 0;
2236 status = pthread_mutex_unlock (&rwl->mutex);
2237 if (status != 0)
2238 return status;
2239 status = pthread_mutex_destroy (&rwl->mutex);
2240 status1 = pthread_cond_destroy (&rwl->read);
2241 status2 = pthread_cond_destroy (&rwl->write);
2242 return (status != 0 ? status : (status1 != 0 ? status1 : status2));
2243}
2244
2245/*
2246 * Handle cleanup when the read lock condition variable
2247 * wait is cancelled.
2248 *
2249 * Simply record that the thread is no longer waiting,
2250 * and unlock the mutex.
2251 */
2252static void rwl_readcleanup (void *arg)
2253{
2254 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2255
2256 rwl->r_wait--;
2257 pthread_mutex_unlock (&rwl->mutex);
2258}
2259
2260/*
2261 * Lock a read-write lock for read access.
2262 */
2263static int rwl_readlock (vg_rwlock_t *rwl)
2264{
2265 int status;
2266
2267 if (rwl->valid != VG_RWLOCK_VALID)
2268 return EINVAL;
2269 status = pthread_mutex_lock (&rwl->mutex);
2270 if (status != 0)
2271 return status;
2272 if (rwl->w_active) {
2273 rwl->r_wait++;
2274 pthread_cleanup_push (rwl_readcleanup, (void*)rwl);
2275 while (rwl->w_active) {
2276 status = pthread_cond_wait (&rwl->read, &rwl->mutex);
2277 if (status != 0)
2278 break;
2279 }
2280 pthread_cleanup_pop (0);
2281 rwl->r_wait--;
2282 }
2283 if (status == 0)
2284 rwl->r_active++;
2285 pthread_mutex_unlock (&rwl->mutex);
2286 return status;
2287}
2288
2289/*
2290 * Attempt to lock a read-write lock for read access (don't
2291 * block if unavailable).
2292 */
2293static int rwl_readtrylock (vg_rwlock_t *rwl)
2294{
2295 int status, status2;
2296
2297 if (rwl->valid != VG_RWLOCK_VALID)
2298 return EINVAL;
2299 status = pthread_mutex_lock (&rwl->mutex);
2300 if (status != 0)
2301 return status;
2302 if (rwl->w_active)
2303 status = EBUSY;
2304 else
2305 rwl->r_active++;
2306 status2 = pthread_mutex_unlock (&rwl->mutex);
2307 return (status2 != 0 ? status2 : status);
2308}
2309
2310/*
2311 * Handle cleanup when the write lock condition variable
2312 * wait is cancelled.
2313 *
2314 * Simply record that the thread is no longer waiting,
2315 * and unlock the mutex.
2316 */
2317static void rwl_writecleanup (void *arg)
2318{
2319 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2320
2321 rwl->w_wait--;
2322 pthread_mutex_unlock (&rwl->mutex);
2323}
2324
2325/*
2326 * Lock a read-write lock for write access.
2327 */
2328static int rwl_writelock (vg_rwlock_t *rwl)
2329{
2330 int status;
2331
2332 if (rwl->valid != VG_RWLOCK_VALID)
2333 return EINVAL;
2334 status = pthread_mutex_lock (&rwl->mutex);
2335 if (status != 0)
2336 return status;
2337 if (rwl->w_active || rwl->r_active > 0) {
2338 rwl->w_wait++;
2339 pthread_cleanup_push (rwl_writecleanup, (void*)rwl);
2340 while (rwl->w_active || rwl->r_active > 0) {
2341 status = pthread_cond_wait (&rwl->write, &rwl->mutex);
2342 if (status != 0)
2343 break;
2344 }
2345 pthread_cleanup_pop (0);
2346 rwl->w_wait--;
2347 }
2348 if (status == 0)
2349 rwl->w_active = 1;
2350 pthread_mutex_unlock (&rwl->mutex);
2351 return status;
2352}
2353
2354/*
2355 * Attempt to lock a read-write lock for write access. Don't
2356 * block if unavailable.
2357 */
2358static int rwl_writetrylock (vg_rwlock_t *rwl)
2359{
2360 int status, status2;
2361
2362 if (rwl->valid != VG_RWLOCK_VALID)
2363 return EINVAL;
2364 status = pthread_mutex_lock (&rwl->mutex);
2365 if (status != 0)
2366 return status;
2367 if (rwl->w_active || rwl->r_active > 0)
2368 status = EBUSY;
2369 else
2370 rwl->w_active = 1;
2371 status2 = pthread_mutex_unlock (&rwl->mutex);
2372 return (status != 0 ? status : status2);
2373}
2374
2375/*
2376 * Unlock a read-write lock, using the r_active and w_active fields to
2377 * decide whether we're in a read or write lock.
2378 */
2379static int rwl_unlock (vg_rwlock_t *rwl)
2380{
2381 int status, status2;
2382
2383 if (rwl->valid != VG_RWLOCK_VALID)
2384 return EINVAL;
2385 status = pthread_mutex_lock (&rwl->mutex);
2386 if (status != 0)
2387 return status;
2388
2389 if (rwl->r_active > 0) {
2390
2391 /* READ case */
2392 assert(!rwl->w_active);
2393 rwl->r_active--;
2394 if (rwl->r_active == 0 && rwl->w_wait > 0)
2395 status = pthread_cond_signal (&rwl->write);
2396 /* END READ case */
2397
2398 } else {
2399
2400 /* WRITE case */
2401 assert(rwl->w_active);
2402 assert(rwl->r_active == 0);
2403 rwl->w_active = 0;
2404
2405 if (rwl->pref_writer) {
2406 /* Do writer-preference wakeups. */
2407 if (rwl->w_wait > 0) {
2408 status = pthread_cond_signal (&rwl->write);
2409 if (status != 0) {
2410 pthread_mutex_unlock (&rwl->mutex);
2411 return status;
2412 }
2413 } else if (rwl->r_wait > 0) {
2414 status = pthread_cond_broadcast (&rwl->read);
2415 if (status != 0) {
2416 pthread_mutex_unlock (&rwl->mutex);
2417 return status;
2418 }
2419 }
2420 } else {
2421 /* Do reader-preference wakeups. */
2422 if (rwl->r_wait > 0) {
2423 status = pthread_cond_broadcast (&rwl->read);
2424 if (status != 0) {
2425 pthread_mutex_unlock (&rwl->mutex);
2426 return status;
2427 }
2428 } else if (rwl->w_wait > 0) {
2429 status = pthread_cond_signal (&rwl->write);
2430 if (status != 0) {
2431 pthread_mutex_unlock (&rwl->mutex);
2432 return status;
2433 }
2434 }
2435 }
2436 /* END WRITE case */
2437
2438 }
2439
2440 status2 = pthread_mutex_unlock (&rwl->mutex);
2441 return (status2 == 0 ? status : status2);
2442}
2443
2444/* -------------------------------- */
2445
2446int pthread_rwlock_init ( pthread_rwlock_t* orig,
2447 const pthread_rwlockattr_t* attr )
2448{
2449 int res;
2450 vg_rwlock_t* rwl;
2451 if (0) printf ("pthread_rwlock_init\n");
2452 /* Force the remapper to initialise the shadow. */
2453 orig->__rw_readers = 0;
2454 /* Install the lock preference; the remapper needs to know it. */
2455 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2456 if (attr)
2457 orig->__rw_kind = attr->__lockkind;
2458 rwl = rw_remap ( orig );
2459 res = rwl_init ( rwl );
2460 return res;
2461}
2462
2463int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2464{
2465 int res;
2466 vg_rwlock_t* rwl;
2467 if (0) printf ("pthread_rwlock_destroy\n");
2468 rwl = rw_remap ( orig );
2469 res = rwl_destroy ( rwl );
2470 return res;
2471}
2472
2473int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2474{
2475 int res;
2476 vg_rwlock_t* rwl;
2477 if (0) printf ("pthread_rwlock_rdlock\n");
2478 rwl = rw_remap ( orig );
2479 res = rwl_readlock ( rwl );
2480 return res;
2481}
2482
2483int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2484{
2485 int res;
2486 vg_rwlock_t* rwl;
2487 if (0) printf ("pthread_rwlock_tryrdlock\n");
2488 rwl = rw_remap ( orig );
2489 res = rwl_readtrylock ( rwl );
2490 return res;
2491}
2492
2493int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2494{
2495 int res;
2496 vg_rwlock_t* rwl;
2497 if (0) printf ("pthread_rwlock_wrlock\n");
2498 rwl = rw_remap ( orig );
2499 res = rwl_writelock ( rwl );
2500 return res;
2501}
2502
2503int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2504{
2505 int res;
2506 vg_rwlock_t* rwl;
2507 if (0) printf ("pthread_rwlock_trywrlock\n");
2508 rwl = rw_remap ( orig );
2509 res = rwl_writetrylock ( rwl );
2510 return res;
2511}
2512
2513int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2514{
2515 int res;
2516 vg_rwlock_t* rwl;
2517 if (0) printf ("pthread_rwlock_unlock\n");
2518 rwl = rw_remap ( orig );
2519 res = rwl_unlock ( rwl );
2520 return res;
2521}
2522
2523
2524/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002525 B'stard.
2526 ------------------------------------------------------------------ */
2527
2528# define strong_alias(name, aliasname) \
2529 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2530
sewardj5905fae2002-04-26 13:25:00 +00002531# define weak_alias(name, aliasname) \
2532 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002533
sewardj5905fae2002-04-26 13:25:00 +00002534strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2535strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2536strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2537strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2538 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2539strong_alias(__pthread_mutex_init, pthread_mutex_init)
2540strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2541strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2542strong_alias(__pthread_once, pthread_once)
2543strong_alias(__pthread_atfork, pthread_atfork)
2544strong_alias(__pthread_key_create, pthread_key_create)
2545strong_alias(__pthread_getspecific, pthread_getspecific)
2546strong_alias(__pthread_setspecific, pthread_setspecific)
2547
sewardjd529a442002-05-04 19:49:21 +00002548#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002549strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002550#endif
2551
sewardj5905fae2002-04-26 13:25:00 +00002552strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002553strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002554strong_alias(lseek, __lseek)
2555strong_alias(open, __open)
2556strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002557strong_alias(read, __read)
2558strong_alias(wait, __wait)
2559strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002560strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002561strong_alias(send, __send)
2562
sewardj726c4122002-05-16 23:39:10 +00002563weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002564weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002565weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002566
sewardj5905fae2002-04-26 13:25:00 +00002567
sewardj3b13f0e2002-04-25 20:17:29 +00002568
2569/*--------------------------------------------------*/
2570
sewardj5905fae2002-04-26 13:25:00 +00002571weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002572weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002573weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002574
sewardja1ac5cb2002-05-27 13:00:05 +00002575weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2576weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2577weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2578weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2579
sewardj060b04f2002-04-26 21:01:13 +00002580
sewardj3b13f0e2002-04-25 20:17:29 +00002581/* I've no idea what these are, but they get called quite a lot.
2582 Anybody know? */
2583
2584#undef _IO_flockfile
2585void _IO_flockfile ( _IO_FILE * file )
2586{
sewardj853f55d2002-04-26 00:27:53 +00002587 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002588}
sewardj5905fae2002-04-26 13:25:00 +00002589weak_alias(_IO_flockfile, flockfile);
2590
sewardj3b13f0e2002-04-25 20:17:29 +00002591
2592#undef _IO_funlockfile
2593void _IO_funlockfile ( _IO_FILE * file )
2594{
sewardj853f55d2002-04-26 00:27:53 +00002595 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002596}
sewardj5905fae2002-04-26 13:25:00 +00002597weak_alias(_IO_funlockfile, funlockfile);
2598
sewardj3b13f0e2002-04-25 20:17:29 +00002599
sewardjd4f2c712002-04-30 10:20:10 +00002600/* This doesn't seem to be needed to simulate libpthread.so's external
2601 interface, but many people complain about its absence. */
2602
2603strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2604weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002605
2606
2607/*--------------------------------------------------------------------*/
2608/*--- end vg_libpthread.c ---*/
2609/*--------------------------------------------------------------------*/