blob: 6cb5dd6622c749f0a73fc68697cac559971e8b91 [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
sewardj0d844232002-06-02 09:29:31 +0000272/* These are no-ops, as with LinuxThreads. */
273int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
274{
275 ensure_valgrind("pthread_attr_setscope");
276 if (scope == PTHREAD_SCOPE_SYSTEM)
277 return 0;
278 if (scope == PTHREAD_SCOPE_PROCESS)
279 return ENOTSUP;
280 return EINVAL;
281}
282
283int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
284{
285 ensure_valgrind("pthread_attr_setscope");
286 if (scope)
287 *scope = PTHREAD_SCOPE_SYSTEM;
288 return 0;
289}
290
sewardj64039bb2002-06-03 00:58:18 +0000291
292/* Pretty bogus. Avoid if possible. */
293int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
294{
295 int detached;
296 size_t limit;
297 ensure_valgrind("pthread_getattr_np");
298 kludged("pthread_getattr_np");
299 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
300 - 1000; /* paranoia */
301 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
302 attr->__schedpolicy = SCHED_OTHER;
303 attr->__schedparam.sched_priority = 0;
304 attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
305 attr->__scope = PTHREAD_SCOPE_SYSTEM;
306 attr->__guardsize = VKI_BYTES_PER_PAGE;
307 attr->__stackaddr = NULL;
308 attr->__stackaddr_set = 0;
309 attr->__stacksize = limit;
310 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
311 VG_USERREQ__SET_OR_GET_DETACH,
312 2 /* get */, thread, 0, 0);
313 assert(detached == 0 || detached == 1);
314 if (detached)
315 attr->__detachstate = PTHREAD_CREATE_DETACHED;
316 return 0;
317}
318
319
320/* Bogus ... */
321int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
322 void ** stackaddr )
323{
324 ensure_valgrind("pthread_attr_getstackaddr");
325 kludged("pthread_attr_getstackaddr");
326 if (stackaddr)
327 *stackaddr = NULL;
328 return 0;
329}
330
331/* Not bogus (!) */
332int pthread_attr_getstacksize ( const pthread_attr_t * _attr,
333 size_t * __stacksize )
334{
335 size_t limit;
336 ensure_valgrind("pthread_attr_getstacksize");
337 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
338 - 1000; /* paranoia */
339 if (__stacksize)
340 *__stacksize = limit;
341 return 0;
342}
343
sewardj20917d82002-05-28 01:36:45 +0000344/* ---------------------------------------------------
345 Helper functions for running a thread
346 and for clearing up afterwards.
347 ------------------------------------------------ */
348
349/* All exiting threads eventually pass through here, bearing the
350 return value, or PTHREAD_CANCELED, in ret_val. */
351static
352__attribute__((noreturn))
353void thread_exit_wrapper ( void* ret_val )
354{
sewardj870497a2002-05-29 01:06:47 +0000355 int detached, res;
356 CleanupEntry cu;
357 pthread_key_t key;
358
sewardj20917d82002-05-28 01:36:45 +0000359 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000360 while (1) {
361 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
362 VG_USERREQ__CLEANUP_POP,
363 &cu, 0, 0, 0);
364 if (res == -1) break; /* stack empty */
365 assert(res == 0);
366 if (0) printf("running exit cleanup handler");
367 cu.fn ( cu.arg );
368 }
369
sewardj870497a2002-05-29 01:06:47 +0000370 /* Run this thread's key finalizers. Really this should be run
371 PTHREAD_DESTRUCTOR_ITERATIONS times. */
372 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
373 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
374 VG_USERREQ__GET_KEY_D_AND_S,
375 key, &cu, 0, 0 );
376 if (res == 0) {
377 /* valid key */
378 if (cu.fn && cu.arg)
379 cu.fn /* destructor for key */
380 ( cu.arg /* specific for key for this thread */ );
381 continue;
382 }
383 assert(res == -1);
384 }
sewardj20917d82002-05-28 01:36:45 +0000385
386 /* Decide on my final disposition. */
387 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
388 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000389 2 /* get */, pthread_self(), 0, 0);
sewardj20917d82002-05-28 01:36:45 +0000390 assert(detached == 0 || detached == 1);
391
392 if (detached) {
393 /* Detached; I just quit right now. */
394 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
395 VG_USERREQ__QUIT, 0, 0, 0, 0);
396 } else {
397 /* Not detached; so I wait for a joiner. */
398 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
399 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
400 }
401 /* NOTREACHED */
402 barf("thread_exit_wrapper: still alive?!");
403}
404
405
406/* This function is a wrapper function for running a thread. It runs
407 the root function specified in pthread_create, and then, should the
408 root function return a value, it arranges to run the thread's
409 cleanup handlers and exit correctly. */
410
411/* Struct used to convey info from pthread_create to
412 thread_wrapper. */
413typedef
414 struct {
415 pthread_attr_t* attr;
416 void* (*root_fn) ( void* );
417 void* arg;
418 }
419 NewThreadInfo;
420
421
422/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
423 not return. Note that this runs in the new thread, not the
424 parent. */
425static
426__attribute__((noreturn))
427void thread_wrapper ( NewThreadInfo* info )
428{
429 int res;
430 pthread_attr_t* attr;
431 void* (*root_fn) ( void* );
432 void* arg;
433 void* ret_val;
434
435 attr = info->attr;
436 root_fn = info->root_fn;
437 arg = info->arg;
438
sewardj20917d82002-05-28 01:36:45 +0000439 /* Free up the arg block that pthread_create malloced. */
440 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
441 VG_USERREQ__FREE, info, 0, 0, 0);
442 assert(res == 0);
443
sewardj7989d0c2002-05-28 11:00:01 +0000444 /* Minimally observe the attributes supplied. */
445 if (attr) {
446 assert(attr->__detachstate == PTHREAD_CREATE_DETACHED
447 || attr->__detachstate == PTHREAD_CREATE_JOINABLE);
448 if (attr->__detachstate == PTHREAD_CREATE_DETACHED)
449 pthread_detach(pthread_self());
450 }
451
sewardj20917d82002-05-28 01:36:45 +0000452 /* The root function might not return. But if it does we simply
453 move along to thread_exit_wrapper. All other ways out for the
454 thread (cancellation, or calling pthread_exit) lead there
455 too. */
456 ret_val = root_fn(arg);
457 thread_exit_wrapper(ret_val);
458 /* NOTREACHED */
459}
460
461
sewardjf8f819e2002-04-17 23:21:37 +0000462/* ---------------------------------------------------
463 THREADs
464 ------------------------------------------------ */
465
sewardjff42d1d2002-05-22 13:17:31 +0000466__attribute__((weak))
467int pthread_yield ( void )
468{
469 int res;
470 ensure_valgrind("pthread_yield");
471 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
472 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
473 return 0;
474}
475
476
sewardj6072c362002-04-19 14:40:57 +0000477int pthread_equal(pthread_t thread1, pthread_t thread2)
478{
479 return thread1 == thread2 ? 1 : 0;
480}
481
482
sewardj20917d82002-05-28 01:36:45 +0000483/* Bundle up the args into a malloc'd block and create a new thread
484 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000485int
486pthread_create (pthread_t *__restrict __thread,
487 __const pthread_attr_t *__restrict __attr,
488 void *(*__start_routine) (void *),
489 void *__restrict __arg)
490{
sewardj20917d82002-05-28 01:36:45 +0000491 int tid_child;
492 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000493
sewardj20917d82002-05-28 01:36:45 +0000494 ensure_valgrind("pthread_create");
495
496 /* Allocate space for the arg block. thread_wrapper will free
497 it. */
498 VALGRIND_MAGIC_SEQUENCE(info, NULL /* default */,
499 VG_USERREQ__MALLOC,
500 sizeof(NewThreadInfo), 0, 0, 0);
501 assert(info != NULL);
502
503 info->attr = (pthread_attr_t*)__attr;
504 info->root_fn = __start_routine;
505 info->arg = __arg;
506 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
507 VG_USERREQ__APPLY_IN_NEW_THREAD,
508 &thread_wrapper, info, 0, 0);
509 assert(tid_child != VG_INVALID_THREADID);
510
511 if (__thread)
512 *__thread = tid_child;
513 return 0; /* success */
514}
sewardje663cb92002-04-12 10:26:32 +0000515
516
517int
518pthread_join (pthread_t __th, void **__thread_return)
519{
520 int res;
521 ensure_valgrind("pthread_join");
522 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
523 VG_USERREQ__PTHREAD_JOIN,
524 __th, __thread_return, 0, 0);
525 return res;
526}
527
528
sewardj3b5d8862002-04-20 13:53:23 +0000529void pthread_exit(void *retval)
530{
sewardj3b5d8862002-04-20 13:53:23 +0000531 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000532 /* Simple! */
533 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000534}
535
sewardje663cb92002-04-12 10:26:32 +0000536
sewardj3b13f0e2002-04-25 20:17:29 +0000537pthread_t pthread_self(void)
sewardje663cb92002-04-12 10:26:32 +0000538{
539 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000540 ensure_valgrind("pthread_self");
sewardj439d45e2002-05-03 20:43:10 +0000541 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardje663cb92002-04-12 10:26:32 +0000542 VG_USERREQ__PTHREAD_GET_THREADID,
543 0, 0, 0, 0);
sewardj439d45e2002-05-03 20:43:10 +0000544 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000545 barf("pthread_self: invalid ThreadId");
546 return tid;
sewardje663cb92002-04-12 10:26:32 +0000547}
548
549
sewardj853f55d2002-04-26 00:27:53 +0000550int pthread_detach(pthread_t th)
551{
sewardj20917d82002-05-28 01:36:45 +0000552 int res;
553 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000554 /* First we enquire as to the current detach state. */
555 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000556 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000557 2 /* get */, th, 0, 0);
558 if (res == -1) /* not found */
559 return ESRCH;
560 if (res == 1) /* already detached */
561 return EINVAL;
562 if (res == 0) {
563 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
564 VG_USERREQ__SET_OR_GET_DETACH,
565 1 /* set */, th, 0, 0);
566 assert(res == 0);
567 return 0;
568 }
569 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000570}
571
572
sewardjf8f819e2002-04-17 23:21:37 +0000573/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000574 CLEANUP STACKS
575 ------------------------------------------------ */
576
577void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
578 void (*__routine) (void *),
579 void *__arg)
580{
581 int res;
582 CleanupEntry cu;
583 ensure_valgrind("_pthread_cleanup_push");
584 cu.fn = __routine;
585 cu.arg = __arg;
586 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
587 VG_USERREQ__CLEANUP_PUSH,
588 &cu, 0, 0, 0);
589 assert(res == 0);
590}
591
592
593void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
594 void (*__routine) (void *),
595 void *__arg)
596{
597 /* As _pthread_cleanup_push, but first save the thread's original
598 cancellation type in __buffer and set it to Deferred. */
599 int orig_ctype;
600 ensure_valgrind("_pthread_cleanup_push_defer");
601 /* Set to Deferred, and put the old cancellation type in res. */
602 assert(-1 != PTHREAD_CANCEL_DEFERRED);
603 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
604 assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
605 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
606 VG_USERREQ__SET_CANCELTYPE,
607 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
608 assert(orig_ctype != -1);
609 *((int*)(__buffer)) = orig_ctype;
610 /* Now push the cleanup. */
611 _pthread_cleanup_push(NULL, __routine, __arg);
612}
613
614
615void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
616 int __execute)
617{
618 int res;
619 CleanupEntry cu;
620 ensure_valgrind("_pthread_cleanup_push");
621 cu.fn = cu.arg = NULL; /* paranoia */
622 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
623 VG_USERREQ__CLEANUP_POP,
624 &cu, 0, 0, 0);
625 if (res == 0) {
626 /* pop succeeded */
627 if (__execute) {
628 cu.fn ( cu.arg );
629 }
630 return;
631 }
632 if (res == -1) {
633 /* stack underflow */
634 return;
635 }
636 barf("_pthread_cleanup_pop");
637}
638
639
640void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
641 int __execute)
642{
643 int orig_ctype, fake_ctype;
644 /* As _pthread_cleanup_pop, but after popping/running the handler,
645 restore the thread's original cancellation type from the first
646 word of __buffer. */
647 _pthread_cleanup_pop(NULL, __execute);
648 orig_ctype = *((int*)(__buffer));
649 assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
650 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
651 assert(-1 != PTHREAD_CANCEL_DEFERRED);
652 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
653 assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
654 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
655 VG_USERREQ__SET_CANCELTYPE,
656 orig_ctype, 0, 0, 0);
657 assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
658}
659
660
661/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000662 MUTEX ATTRIBUTES
663 ------------------------------------------------ */
664
sewardj5905fae2002-04-26 13:25:00 +0000665int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000666{
sewardjf8f819e2002-04-17 23:21:37 +0000667 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000668 return 0;
sewardje663cb92002-04-12 10:26:32 +0000669}
670
sewardj5905fae2002-04-26 13:25:00 +0000671int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000672{
673 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000674# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000675 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000676 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000677# endif
sewardja1679dd2002-05-10 22:31:40 +0000678# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000679 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000680# endif
sewardjf8f819e2002-04-17 23:21:37 +0000681 case PTHREAD_MUTEX_RECURSIVE_NP:
682 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000683 attr->__mutexkind = type;
684 return 0;
685 default:
686 return EINVAL;
687 }
688}
689
sewardj5905fae2002-04-26 13:25:00 +0000690int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000691{
692 return 0;
693}
694
695
696/* ---------------------------------------------------
697 MUTEXes
698 ------------------------------------------------ */
699
sewardj5905fae2002-04-26 13:25:00 +0000700int __pthread_mutex_init(pthread_mutex_t *mutex,
701 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000702{
sewardj604ec3c2002-04-18 22:38:41 +0000703 mutex->__m_count = 0;
704 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
705 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
706 if (mutexattr)
707 mutex->__m_kind = mutexattr->__mutexkind;
708 return 0;
sewardje663cb92002-04-12 10:26:32 +0000709}
710
sewardj439d45e2002-05-03 20:43:10 +0000711
sewardj5905fae2002-04-26 13:25:00 +0000712int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000713{
714 int res;
sewardj436e0582002-04-26 14:31:40 +0000715 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000716 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000717 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
718 VG_USERREQ__PTHREAD_MUTEX_LOCK,
719 mutex, 0, 0, 0);
720 return res;
sewardj439d45e2002-05-03 20:43:10 +0000721 } else {
722 if (moans-- > 0)
723 not_inside("pthread_mutex_lock");
724 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000725 }
726}
727
sewardj439d45e2002-05-03 20:43:10 +0000728
sewardj5905fae2002-04-26 13:25:00 +0000729int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000730{
731 int res;
sewardj436e0582002-04-26 14:31:40 +0000732 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000733 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000734 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
735 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
736 mutex, 0, 0, 0);
737 return res;
sewardj439d45e2002-05-03 20:43:10 +0000738 } else {
739 if (moans-- > 0)
740 not_inside("pthread_mutex_trylock");
741 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000742 }
743}
744
sewardj439d45e2002-05-03 20:43:10 +0000745
sewardj5905fae2002-04-26 13:25:00 +0000746int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000747{
748 int res;
sewardj436e0582002-04-26 14:31:40 +0000749 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000750 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000751 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
752 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
753 mutex, 0, 0, 0);
754 return res;
sewardj439d45e2002-05-03 20:43:10 +0000755 } else {
756 if (moans-- > 0)
757 not_inside("pthread_mutex_unlock");
758 return 0;
sewardje663cb92002-04-12 10:26:32 +0000759 }
760}
761
sewardj439d45e2002-05-03 20:43:10 +0000762
sewardj5905fae2002-04-26 13:25:00 +0000763int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000764{
sewardj604ec3c2002-04-18 22:38:41 +0000765 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
766 need to involve it. */
767 if (mutex->__m_count > 0)
768 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000769 mutex->__m_count = 0;
770 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
771 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000772 return 0;
sewardje663cb92002-04-12 10:26:32 +0000773}
774
775
sewardjf8f819e2002-04-17 23:21:37 +0000776/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000777 CONDITION VARIABLES
778 ------------------------------------------------ */
779
780/* LinuxThreads supports no attributes for conditions. Hence ... */
781
782int pthread_condattr_init(pthread_condattr_t *attr)
783{
784 return 0;
785}
786
sewardj0738a592002-04-20 13:59:33 +0000787int pthread_condattr_destroy(pthread_condattr_t *attr)
788{
789 return 0;
790}
sewardj6072c362002-04-19 14:40:57 +0000791
792int pthread_cond_init( pthread_cond_t *cond,
793 const pthread_condattr_t *cond_attr)
794{
795 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
796 return 0;
797}
798
sewardjf854f472002-04-21 12:19:41 +0000799int pthread_cond_destroy(pthread_cond_t *cond)
800{
801 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000802 static int moans = N_MOANS;
803 if (moans-- > 0)
804 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000805 return 0;
806}
sewardj6072c362002-04-19 14:40:57 +0000807
808/* ---------------------------------------------------
809 SCHEDULING
810 ------------------------------------------------ */
811
812/* This is completely bogus. */
813int pthread_getschedparam(pthread_t target_thread,
814 int *policy,
815 struct sched_param *param)
816{
sewardj436e0582002-04-26 14:31:40 +0000817 static int moans = N_MOANS;
818 if (moans-- > 0)
819 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000820 if (policy) *policy = SCHED_OTHER;
sewardj2a1dcce2002-04-22 12:45:25 +0000821# ifdef GLIBC_2_1
822 if (param) param->sched_priority = 0; /* who knows */
823# else
sewardj6072c362002-04-19 14:40:57 +0000824 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000825# endif
sewardj6072c362002-04-19 14:40:57 +0000826 return 0;
827}
828
829int pthread_setschedparam(pthread_t target_thread,
830 int policy,
831 const struct sched_param *param)
832{
sewardj436e0582002-04-26 14:31:40 +0000833 static int moans = N_MOANS;
834 if (moans-- > 0)
835 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000836 return 0;
837}
838
sewardj3b5d8862002-04-20 13:53:23 +0000839int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
840{
841 int res;
842 ensure_valgrind("pthread_cond_wait");
843 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
844 VG_USERREQ__PTHREAD_COND_WAIT,
845 cond, mutex, 0, 0);
846 return res;
847}
848
sewardj5f07b662002-04-23 16:52:51 +0000849int pthread_cond_timedwait ( pthread_cond_t *cond,
850 pthread_mutex_t *mutex,
851 const struct timespec *abstime )
852{
853 int res;
854 unsigned int ms_now, ms_end;
855 struct timeval timeval_now;
856 unsigned long long int ull_ms_now_after_1970;
857 unsigned long long int ull_ms_end_after_1970;
858
859 ensure_valgrind("pthread_cond_timedwait");
860 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
861 VG_USERREQ__READ_MILLISECOND_TIMER,
862 0, 0, 0, 0);
863 assert(ms_now != 0xFFFFFFFF);
864 res = gettimeofday(&timeval_now, NULL);
865 assert(res == 0);
866
867 ull_ms_now_after_1970
868 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
869 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
870 ull_ms_end_after_1970
871 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
872 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +0000873 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
874 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +0000875 ms_end
876 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
877 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
878 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
879 cond, mutex, ms_end, 0);
880 return res;
881}
882
883
sewardj3b5d8862002-04-20 13:53:23 +0000884int pthread_cond_signal(pthread_cond_t *cond)
885{
886 int res;
887 ensure_valgrind("pthread_cond_signal");
888 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
889 VG_USERREQ__PTHREAD_COND_SIGNAL,
890 cond, 0, 0, 0);
891 return res;
892}
893
894int pthread_cond_broadcast(pthread_cond_t *cond)
895{
896 int res;
897 ensure_valgrind("pthread_cond_broadcast");
898 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
899 VG_USERREQ__PTHREAD_COND_BROADCAST,
900 cond, 0, 0, 0);
901 return res;
902}
903
sewardj6072c362002-04-19 14:40:57 +0000904
905/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000906 CANCELLATION
907 ------------------------------------------------ */
908
sewardj853f55d2002-04-26 00:27:53 +0000909int pthread_setcancelstate(int state, int *oldstate)
910{
sewardj20917d82002-05-28 01:36:45 +0000911 int res;
912 ensure_valgrind("pthread_setcancelstate");
913 if (state != PTHREAD_CANCEL_ENABLE
914 && state != PTHREAD_CANCEL_DISABLE)
915 return EINVAL;
916 assert(-1 != PTHREAD_CANCEL_ENABLE);
917 assert(-1 != PTHREAD_CANCEL_DISABLE);
918 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
919 VG_USERREQ__SET_CANCELSTATE,
920 state, 0, 0, 0);
921 assert(res != -1);
922 if (oldstate)
923 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +0000924 return 0;
925}
926
sewardje663cb92002-04-12 10:26:32 +0000927int pthread_setcanceltype(int type, int *oldtype)
928{
sewardj20917d82002-05-28 01:36:45 +0000929 int res;
930 ensure_valgrind("pthread_setcanceltype");
931 if (type != PTHREAD_CANCEL_DEFERRED
932 && type != PTHREAD_CANCEL_ASYNCHRONOUS)
933 return EINVAL;
934 assert(-1 != PTHREAD_CANCEL_DEFERRED);
935 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
936 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
937 VG_USERREQ__SET_CANCELTYPE,
938 type, 0, 0, 0);
939 assert(res != -1);
940 if (oldtype)
941 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +0000942 return 0;
943}
944
sewardje663cb92002-04-12 10:26:32 +0000945int pthread_cancel(pthread_t thread)
946{
947 int res;
948 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +0000949 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
950 VG_USERREQ__SET_CANCELPEND,
951 thread, &thread_exit_wrapper, 0, 0);
952 assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +0000953 return res;
954}
955
sewardjd140e442002-05-29 01:21:19 +0000956static __inline__
957void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +0000958{
sewardj20917d82002-05-28 01:36:45 +0000959 int res;
960 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
961 VG_USERREQ__TESTCANCEL,
962 0, 0, 0, 0);
963 assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +0000964}
965
sewardjd140e442002-05-29 01:21:19 +0000966void pthread_testcancel ( void )
967{
968 __my_pthread_testcancel();
969}
970
sewardj20917d82002-05-28 01:36:45 +0000971
sewardjef037c72002-05-30 00:40:03 +0000972/* Not really sure what this is for. I suspect for doing the POSIX
973 requirements for fork() and exec(). We do this internally anyway
974 whenever those syscalls are observed, so this could be superfluous,
975 but hey ...
976*/
sewardj853f55d2002-04-26 00:27:53 +0000977void __pthread_kill_other_threads_np ( void )
978{
sewardjef037c72002-05-30 00:40:03 +0000979 int res;
980 ensure_valgrind("__pthread_kill_other_threads_np");
981 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
982 VG_USERREQ__NUKE_OTHER_THREADS,
983 0, 0, 0, 0);
984 assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +0000985}
986
sewardje663cb92002-04-12 10:26:32 +0000987
sewardjf8f819e2002-04-17 23:21:37 +0000988/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +0000989 SIGNALS
990 ------------------------------------------------ */
991
992#include <signal.h>
993
994int pthread_sigmask(int how, const sigset_t *newmask,
995 sigset_t *oldmask)
996{
997 int res;
998
999 /* A bit subtle, because the scheduler expects newmask and oldmask
1000 to be vki_sigset_t* rather than sigset_t*, and the two are
1001 different. Fortunately the first 64 bits of a sigset_t are
1002 exactly a vki_sigset_t, so we just pass the pointers through
1003 unmodified. Haaaack!
1004
1005 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001006 constants to VKI_ constants, so that the former do not have to
1007 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001008
1009 ensure_valgrind("pthread_sigmask");
1010
1011 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001012 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1013 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1014 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardjb48e5002002-05-13 00:16:03 +00001015 default: return EINVAL;
1016 }
1017
1018 /* Crude check */
1019 if (newmask == NULL)
1020 return EFAULT;
1021
1022 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1023 VG_USERREQ__PTHREAD_SIGMASK,
1024 how, newmask, oldmask, 0);
1025
1026 /* The scheduler tells us of any memory violations. */
1027 return res == 0 ? 0 : EFAULT;
1028}
1029
1030
1031int sigwait ( const sigset_t* set, int* sig )
1032{
1033 int res;
1034 ensure_valgrind("sigwait");
1035 /* As with pthread_sigmask we deliberately confuse sigset_t with
1036 vki_ksigset_t. */
1037 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1038 VG_USERREQ__SIGWAIT,
1039 set, sig, 0, 0);
1040 return res;
1041}
1042
1043
sewardj018f7622002-05-15 21:13:39 +00001044int pthread_kill(pthread_t thread, int signo)
1045{
1046 int res;
1047 ensure_valgrind("pthread_kill");
1048 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1049 VG_USERREQ__PTHREAD_KILL,
1050 thread, signo, 0, 0);
1051 return res;
1052}
1053
1054
sewardj3665ded2002-05-16 16:57:25 +00001055/* Copied verbatim from Linuxthreads */
1056/* Redefine raise() to send signal to calling thread only,
1057 as per POSIX 1003.1c */
1058int raise (int sig)
1059{
1060 int retcode = pthread_kill(pthread_self(), sig);
1061 if (retcode == 0)
1062 return 0;
1063 else {
1064 errno = retcode;
1065 return -1;
1066 }
1067}
1068
1069
sewardjb48e5002002-05-13 00:16:03 +00001070/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001071 THREAD-SPECIFICs
1072 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001073
sewardj5905fae2002-04-26 13:25:00 +00001074int __pthread_key_create(pthread_key_t *key,
1075 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001076{
sewardj5f07b662002-04-23 16:52:51 +00001077 int res;
1078 ensure_valgrind("pthread_key_create");
1079 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1080 VG_USERREQ__PTHREAD_KEY_CREATE,
1081 key, destr_function, 0, 0);
1082 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001083}
1084
1085int pthread_key_delete(pthread_key_t key)
1086{
sewardj436e0582002-04-26 14:31:40 +00001087 static int moans = N_MOANS;
1088 if (moans-- > 0)
1089 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +00001090 return 0;
1091}
1092
sewardj5905fae2002-04-26 13:25:00 +00001093int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001094{
sewardj5f07b662002-04-23 16:52:51 +00001095 int res;
1096 ensure_valgrind("pthread_setspecific");
1097 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1098 VG_USERREQ__PTHREAD_SETSPECIFIC,
1099 key, pointer, 0, 0);
1100 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001101}
1102
sewardj5905fae2002-04-26 13:25:00 +00001103void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001104{
sewardj5f07b662002-04-23 16:52:51 +00001105 int res;
1106 ensure_valgrind("pthread_getspecific");
1107 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1108 VG_USERREQ__PTHREAD_GETSPECIFIC,
1109 key, 0 , 0, 0);
1110 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001111}
1112
sewardjf8f819e2002-04-17 23:21:37 +00001113
1114/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001115 ONCEry
1116 ------------------------------------------------ */
1117
1118static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1119
1120
sewardj5905fae2002-04-26 13:25:00 +00001121int __pthread_once ( pthread_once_t *once_control,
1122 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001123{
1124 int res;
1125 ensure_valgrind("pthread_once");
1126
sewardj68b2dd92002-05-10 21:03:56 +00001127 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001128
sewardj68b2dd92002-05-10 21:03:56 +00001129 if (res != 0) {
1130 printf("res = %d\n",res);
sewardj89d3d852002-04-24 19:21:39 +00001131 barf("pthread_once: Looks like your program's "
1132 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001133 }
sewardj89d3d852002-04-24 19:21:39 +00001134
1135 if (*once_control == 0) {
1136 *once_control = 1;
1137 init_routine();
1138 }
1139
sewardj68b2dd92002-05-10 21:03:56 +00001140 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001141
1142 return 0;
1143}
1144
1145
1146/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001147 MISC
1148 ------------------------------------------------ */
1149
sewardj5905fae2002-04-26 13:25:00 +00001150int __pthread_atfork ( void (*prepare)(void),
1151 void (*parent)(void),
1152 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001153{
sewardjccef2e62002-05-29 19:26:32 +00001154 /* We have to do this properly or not at all; faking it isn't an
1155 option. */
1156 vgPlain_unimp("__pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +00001157}
1158
1159
sewardjbb990782002-05-08 02:01:14 +00001160__attribute__((weak))
1161void __pthread_initialize ( void )
1162{
sewardjbea1caa2002-05-10 23:20:58 +00001163 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001164}
1165
1166
sewardj853f55d2002-04-26 00:27:53 +00001167/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001168 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001169 ------------------------------------------------ */
1170
sewardj3b13f0e2002-04-25 20:17:29 +00001171#include <resolv.h>
1172static int thread_specific_errno[VG_N_THREADS];
1173static int thread_specific_h_errno[VG_N_THREADS];
1174static struct __res_state
1175 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001176
sewardj3b13f0e2002-04-25 20:17:29 +00001177int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001178{
1179 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001180 /* ensure_valgrind("__errno_location"); */
1181 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001182 VG_USERREQ__PTHREAD_GET_THREADID,
1183 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001184 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001185 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001186 barf("__errno_location: invalid ThreadId");
1187 return & thread_specific_errno[tid];
1188}
1189
1190int* __h_errno_location ( void )
1191{
1192 int tid;
1193 /* ensure_valgrind("__h_errno_location"); */
1194 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1195 VG_USERREQ__PTHREAD_GET_THREADID,
1196 0, 0, 0, 0);
1197 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001198 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001199 barf("__h_errno_location: invalid ThreadId");
1200 return & thread_specific_h_errno[tid];
1201}
1202
1203struct __res_state* __res_state ( void )
1204{
1205 int tid;
1206 /* ensure_valgrind("__res_state"); */
1207 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1208 VG_USERREQ__PTHREAD_GET_THREADID,
1209 0, 0, 0, 0);
1210 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001211 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001212 barf("__res_state: invalid ThreadId");
1213 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001214}
1215
1216
sewardj5716dbb2002-04-26 03:28:18 +00001217/* ---------------------------------------------------
1218 LIBC-PRIVATE SPECIFIC DATA
1219 ------------------------------------------------ */
1220
1221/* Relies on assumption that initial private data is NULL. This
1222 should be fixed somehow. */
1223
1224/* The allowable keys (indices) (all 2 of them).
1225 From sysdeps/pthread/bits/libc-tsd.h
1226*/
sewardj70adeb22002-04-27 01:35:38 +00001227#define N_LIBC_TSD_EXTRA_KEYS 1
1228
sewardj5716dbb2002-04-26 03:28:18 +00001229enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1230 _LIBC_TSD_KEY_DL_ERROR,
1231 _LIBC_TSD_KEY_N };
1232
1233/* Auto-initialising subsystem. libc_specifics_inited is set
1234 after initialisation. libc_specifics_inited_mx guards it. */
1235static int libc_specifics_inited = 0;
1236static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1237
1238/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001239static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1240 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001241
1242/* Initialise the keys, if they are not already initialise. */
1243static
1244void init_libc_tsd_keys ( void )
1245{
1246 int res, i;
1247 pthread_key_t k;
1248
1249 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1250 if (res != 0) barf("init_libc_tsd_keys: lock");
1251
1252 if (libc_specifics_inited == 0) {
1253 /* printf("INIT libc specifics\n"); */
1254 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001255 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001256 res = pthread_key_create(&k, NULL);
1257 if (res != 0) barf("init_libc_tsd_keys: create");
1258 libc_specifics_keys[i] = k;
1259 }
1260 }
1261
1262 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1263 if (res != 0) barf("init_libc_tsd_keys: unlock");
1264}
1265
1266
1267static int
1268libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1269 const void * pointer )
1270{
sewardj70adeb22002-04-27 01:35:38 +00001271 int res;
1272 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001273 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001274 if (key < _LIBC_TSD_KEY_MALLOC
1275 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001276 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001277 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1278 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001279 "valgrind's libpthread.so: libc_internal_tsd_set: "
1280 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001281 init_libc_tsd_keys();
1282 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1283 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1284 return 0;
1285}
1286
1287static void *
1288libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1289{
sewardj70adeb22002-04-27 01:35:38 +00001290 void* v;
1291 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001292 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001293 if (key < _LIBC_TSD_KEY_MALLOC
1294 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001295 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001296 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1297 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001298 "valgrind's libpthread.so: libc_internal_tsd_get: "
1299 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001300 init_libc_tsd_keys();
1301 v = pthread_getspecific(libc_specifics_keys[key]);
1302 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1303 return v;
1304}
1305
1306
1307
1308
sewardj70adeb22002-04-27 01:35:38 +00001309int (*__libc_internal_tsd_set)
1310 (enum __libc_tsd_key_t key, const void * pointer)
1311 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001312
sewardj70adeb22002-04-27 01:35:38 +00001313void* (*__libc_internal_tsd_get)
1314 (enum __libc_tsd_key_t key)
1315 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001316
1317
sewardje663cb92002-04-12 10:26:32 +00001318/* ---------------------------------------------------------------------
1319 These are here (I think) because they are deemed cancellation
1320 points by POSIX. For the moment we'll simply pass the call along
1321 to the corresponding thread-unaware (?) libc routine.
1322 ------------------------------------------------------------------ */
1323
sewardje663cb92002-04-12 10:26:32 +00001324#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001325#include <sys/types.h>
1326#include <sys/socket.h>
1327
sewardjd529a442002-05-04 19:49:21 +00001328#ifdef GLIBC_2_1
1329extern
1330int __sigaction
1331 (int signum,
1332 const struct sigaction *act,
1333 struct sigaction *oldact);
1334#else
sewardje663cb92002-04-12 10:26:32 +00001335extern
1336int __libc_sigaction
1337 (int signum,
1338 const struct sigaction *act,
1339 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001340#endif
sewardje663cb92002-04-12 10:26:32 +00001341int sigaction(int signum,
1342 const struct sigaction *act,
1343 struct sigaction *oldact)
1344{
sewardjd140e442002-05-29 01:21:19 +00001345 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001346# ifdef GLIBC_2_1
1347 return __sigaction(signum, act, oldact);
1348# else
sewardj45b4b372002-04-16 22:50:32 +00001349 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001350# endif
sewardje663cb92002-04-12 10:26:32 +00001351}
1352
1353
1354extern
1355int __libc_connect(int sockfd,
1356 const struct sockaddr *serv_addr,
1357 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001358__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001359int connect(int sockfd,
1360 const struct sockaddr *serv_addr,
1361 socklen_t addrlen)
1362{
sewardjd140e442002-05-29 01:21:19 +00001363 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001364 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001365}
1366
1367
1368extern
1369int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001370__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001371int fcntl(int fd, int cmd, long arg)
1372{
sewardjd140e442002-05-29 01:21:19 +00001373 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001374 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001375}
1376
1377
1378extern
1379ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001380__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001381ssize_t write(int fd, const void *buf, size_t count)
1382{
sewardjd140e442002-05-29 01:21:19 +00001383 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001384 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001385}
1386
1387
1388extern
1389ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001390__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001391ssize_t read(int fd, void *buf, size_t count)
1392{
sewardjd140e442002-05-29 01:21:19 +00001393 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001394 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001395}
1396
sewardjbe32e452002-04-24 20:29:58 +00001397
1398extern
sewardj853f55d2002-04-26 00:27:53 +00001399int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001400__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001401int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001402{
sewardjd140e442002-05-29 01:21:19 +00001403 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001404 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001405}
1406
sewardje663cb92002-04-12 10:26:32 +00001407
1408extern
sewardj853f55d2002-04-26 00:27:53 +00001409int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001410__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001411int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001412{
sewardjd140e442002-05-29 01:21:19 +00001413 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001414 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001415}
1416
1417
1418extern
1419int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001420__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001421int close(int fd)
1422{
sewardjd140e442002-05-29 01:21:19 +00001423 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001424 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001425}
1426
1427
1428extern
1429int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001430__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001431int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1432{
sewardjd140e442002-05-29 01:21:19 +00001433 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001434 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001435 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001436 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001437}
1438
1439
1440extern
1441pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001442pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001443{
sewardjd140e442002-05-29 01:21:19 +00001444 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001445 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001446}
1447
1448
1449extern
1450pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001451__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001452pid_t waitpid(pid_t pid, int *status, int options)
1453{
sewardjd140e442002-05-29 01:21:19 +00001454 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001455 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001456}
1457
1458
1459extern
1460int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001461__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001462int nanosleep(const struct timespec *req, struct timespec *rem)
1463{
sewardjd140e442002-05-29 01:21:19 +00001464 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001465 return __libc_nanosleep(req, rem);
1466}
1467
sewardjbe32e452002-04-24 20:29:58 +00001468
sewardje663cb92002-04-12 10:26:32 +00001469extern
1470int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001471__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001472int fsync(int fd)
1473{
sewardjd140e442002-05-29 01:21:19 +00001474 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001475 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001476}
1477
sewardjbe32e452002-04-24 20:29:58 +00001478
sewardj70c75362002-04-13 04:18:32 +00001479extern
1480off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001481__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001482off_t lseek(int fildes, off_t offset, int whence)
1483{
sewardjd140e442002-05-29 01:21:19 +00001484 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001485 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001486}
1487
sewardjbe32e452002-04-24 20:29:58 +00001488
1489extern
1490__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001491__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001492__off64_t lseek64(int fildes, __off64_t offset, int whence)
1493{
sewardjd140e442002-05-29 01:21:19 +00001494 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001495 return __libc_lseek64(fildes, offset, whence);
1496}
1497
1498
sewardj726c4122002-05-16 23:39:10 +00001499extern
1500ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1501 __off64_t __offset);
1502ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1503 __off64_t __offset)
1504{
sewardjd140e442002-05-29 01:21:19 +00001505 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001506 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1507}
1508
1509
sewardja18e2102002-05-18 10:43:22 +00001510extern
1511ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1512 __off64_t __offset);
1513ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1514 __off64_t __offset)
1515{
sewardjd140e442002-05-29 01:21:19 +00001516 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001517 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1518}
1519
sewardj726c4122002-05-16 23:39:10 +00001520
sewardj39b93b12002-05-18 10:56:27 +00001521extern
1522ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1523__attribute__((weak))
1524ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1525{
sewardjd140e442002-05-29 01:21:19 +00001526 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001527 return __libc_pwrite(fd, buf, count, offset);
1528}
1529
1530
1531extern
1532ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1533__attribute__((weak))
1534ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1535{
sewardjd140e442002-05-29 01:21:19 +00001536 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001537 return __libc_pread(fd, buf, count, offset);
1538}
1539
1540
sewardj6af4b5d2002-04-16 04:40:49 +00001541extern
1542void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001543/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001544void longjmp(jmp_buf env, int val)
1545{
sewardjd140e442002-05-29 01:21:19 +00001546 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001547 __libc_longjmp(env, val);
1548}
1549
sewardjbe32e452002-04-24 20:29:58 +00001550
sewardj6af4b5d2002-04-16 04:40:49 +00001551extern
1552int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001553__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001554int send(int s, const void *msg, size_t len, int flags)
1555{
sewardjd140e442002-05-29 01:21:19 +00001556 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001557 return __libc_send(s, msg, len, flags);
1558}
1559
sewardjbe32e452002-04-24 20:29:58 +00001560
sewardj1e8cdc92002-04-18 11:37:52 +00001561extern
1562int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001563__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001564int recv(int s, void *buf, size_t len, int flags)
1565{
sewardjd140e442002-05-29 01:21:19 +00001566 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001567 return __libc_recv(s, buf, len, flags);
1568}
1569
sewardjbe32e452002-04-24 20:29:58 +00001570
sewardj3665ded2002-05-16 16:57:25 +00001571extern
1572int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1573__attribute__((weak))
1574int sendmsg(int s, const struct msghdr *msg, int flags)
1575{
sewardjd140e442002-05-29 01:21:19 +00001576 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001577 return __libc_sendmsg(s, msg, flags);
1578}
1579
1580
sewardj796d6a22002-04-24 02:28:34 +00001581extern
sewardj436e0582002-04-26 14:31:40 +00001582int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1583 struct sockaddr *from, socklen_t *fromlen);
1584__attribute__((weak))
1585int recvfrom(int s, void *buf, size_t len, int flags,
1586 struct sockaddr *from, socklen_t *fromlen)
1587{
sewardjd140e442002-05-29 01:21:19 +00001588 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001589 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1590}
1591
1592
1593extern
sewardj796d6a22002-04-24 02:28:34 +00001594int __libc_sendto(int s, const void *msg, size_t len, int flags,
1595 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001596__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001597int sendto(int s, const void *msg, size_t len, int flags,
1598 const struct sockaddr *to, socklen_t tolen)
1599{
sewardjd140e442002-05-29 01:21:19 +00001600 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001601 return __libc_sendto(s, msg, len, flags, to, tolen);
1602}
1603
sewardjbe32e452002-04-24 20:29:58 +00001604
sewardj369b1702002-04-24 13:28:15 +00001605extern
1606int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001607__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001608int system(const char* str)
1609{
sewardjd140e442002-05-29 01:21:19 +00001610 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001611 return __libc_system(str);
1612}
1613
sewardjbe32e452002-04-24 20:29:58 +00001614
sewardjab0b1c32002-04-24 19:26:47 +00001615extern
1616pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001617__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001618pid_t wait(int *status)
1619{
sewardjd140e442002-05-29 01:21:19 +00001620 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00001621 return __libc_wait(status);
1622}
1623
sewardj45b4b372002-04-16 22:50:32 +00001624
sewardj67f1d582002-05-24 02:11:32 +00001625extern
1626int __libc_msync(const void *start, size_t length, int flags);
1627__attribute__((weak))
1628int msync(const void *start, size_t length, int flags)
1629{
sewardjd140e442002-05-29 01:21:19 +00001630 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00001631 return __libc_msync(start, length, flags);
1632}
1633
sewardj5905fae2002-04-26 13:25:00 +00001634
sewardj3b13f0e2002-04-25 20:17:29 +00001635/* ---------------------------------------------------------------------
1636 Nonblocking implementations of select() and poll(). This stuff will
1637 surely rot your mind.
1638 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001639
sewardj08a4c3f2002-04-13 03:45:44 +00001640/*--------------------------------------------------*/
1641
1642#include "vg_kerneliface.h"
1643
1644static
1645__inline__
1646int is_kerror ( int res )
1647{
1648 if (res >= -4095 && res <= -1)
1649 return 1;
1650 else
1651 return 0;
1652}
1653
1654
1655static
1656int my_do_syscall1 ( int syscallno, int arg1 )
1657{
1658 int __res;
1659 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1660 : "=a" (__res)
1661 : "0" (syscallno),
1662 "d" (arg1) );
1663 return __res;
1664}
1665
1666static
1667int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001668 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001669{
1670 int __res;
1671 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1672 : "=a" (__res)
1673 : "0" (syscallno),
1674 "d" (arg1),
1675 "c" (arg2) );
1676 return __res;
1677}
1678
1679static
sewardjf854f472002-04-21 12:19:41 +00001680int my_do_syscall3 ( int syscallno,
1681 int arg1, int arg2, int arg3 )
1682{
1683 int __res;
1684 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1685 : "=a" (__res)
1686 : "0" (syscallno),
1687 "S" (arg1),
1688 "c" (arg2),
1689 "d" (arg3) );
1690 return __res;
1691}
1692
1693static
sewardj08a4c3f2002-04-13 03:45:44 +00001694int do_syscall_select( int n,
1695 vki_fd_set* readfds,
1696 vki_fd_set* writefds,
1697 vki_fd_set* exceptfds,
1698 struct vki_timeval * timeout )
1699{
1700 int res;
1701 int args[5];
1702 args[0] = n;
1703 args[1] = (int)readfds;
1704 args[2] = (int)writefds;
1705 args[3] = (int)exceptfds;
1706 args[4] = (int)timeout;
1707 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001708 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001709}
1710
1711
1712/* This is a wrapper round select(), which makes it thread-safe,
1713 meaning that only this thread will block, rather than the entire
1714 process. This wrapper in turn depends on nanosleep() not to block
1715 the entire process, but I think (hope? suspect?) that POSIX
1716 pthreads guarantees that to be the case.
1717
1718 Basic idea is: modify the timeout parameter to select so that it
1719 returns immediately. Poll like this until select returns non-zero,
1720 indicating something interesting happened, or until our time is up.
1721 Space out the polls with nanosleeps of say 20 milliseconds, which
1722 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001723
1724 Assumes:
1725 * (checked via assert) types fd_set and vki_fd_set are identical.
1726 * (checked via assert) types timeval and vki_timeval are identical.
1727 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1728 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001729*/
sewardj08a4c3f2002-04-13 03:45:44 +00001730
sewardj5905fae2002-04-26 13:25:00 +00001731/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001732int select ( int n,
1733 fd_set *rfds,
1734 fd_set *wfds,
1735 fd_set *xfds,
1736 struct timeval *timeout )
1737{
sewardj5f07b662002-04-23 16:52:51 +00001738 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001739 int res;
1740 fd_set rfds_copy;
1741 fd_set wfds_copy;
1742 fd_set xfds_copy;
1743 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001744 struct vki_timeval zero_timeout;
1745 struct vki_timespec nanosleep_interval;
1746
sewardjd140e442002-05-29 01:21:19 +00001747 __my_pthread_testcancel();
1748
sewardj5f07b662002-04-23 16:52:51 +00001749 /* gcc's complains about ms_end being used uninitialised -- classic
1750 case it can't understand, where ms_end is both defined and used
1751 only if timeout != NULL. Hence ... */
1752 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001753
1754 /* We assume that the kernel and libc data layouts are identical
1755 for the following types. These asserts provide a crude
1756 check. */
1757 if (sizeof(fd_set) != sizeof(vki_fd_set)
1758 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1759 barf("valgrind's hacky non-blocking select(): data sizes error");
1760
sewardj5f07b662002-04-23 16:52:51 +00001761 /* Detect the current time and simultaneously find out if we are
1762 running on Valgrind. */
1763 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1764 VG_USERREQ__READ_MILLISECOND_TIMER,
1765 0, 0, 0, 0);
1766
1767 /* If a zero timeout specified, this call is harmless. Also go
1768 this route if we're not running on Valgrind, for whatever
1769 reason. */
1770 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1771 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001772 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001773 (vki_fd_set*)wfds,
1774 (vki_fd_set*)xfds,
1775 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001776 if (is_kerror(res)) {
1777 * (__errno_location()) = -res;
1778 return -1;
1779 } else {
1780 return res;
1781 }
1782 }
sewardj08a4c3f2002-04-13 03:45:44 +00001783
sewardj5f07b662002-04-23 16:52:51 +00001784 /* If a timeout was specified, set ms_end to be the end millisecond
1785 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001786 if (timeout) {
1787 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
1788 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001789 ms_end = ms_now;
1790 ms_end += (timeout->tv_usec / 1000);
1791 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001792 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +00001793 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001794 }
1795
1796 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1797
1798 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001799 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001800 while (1) {
1801 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +00001802 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1803 VG_USERREQ__READ_MILLISECOND_TIMER,
1804 0, 0, 0, 0);
1805 assert(ms_now != 0xFFFFFFFF);
1806 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +00001807 /* timeout; nothing interesting happened. */
1808 if (rfds) FD_ZERO(rfds);
1809 if (wfds) FD_ZERO(wfds);
1810 if (xfds) FD_ZERO(xfds);
1811 return 0;
1812 }
1813 }
1814
1815 /* These could be trashed each time round the loop, so restore
1816 them each time. */
1817 if (rfds) rfds_copy = *rfds;
1818 if (wfds) wfds_copy = *wfds;
1819 if (xfds) xfds_copy = *xfds;
1820
1821 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1822
1823 res = do_syscall_select( n,
1824 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1825 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1826 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1827 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001828 if (is_kerror(res)) {
1829 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001830 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001831 * (__errno_location()) = -res;
1832 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001833 }
1834 if (res > 0) {
1835 /* one or more fds is ready. Copy out resulting sets and
1836 return. */
1837 if (rfds) *rfds = rfds_copy;
1838 if (wfds) *wfds = wfds_copy;
1839 if (xfds) *xfds = xfds_copy;
1840 return res;
1841 }
1842 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1843 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001844 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001845 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001846 /* It's critical here that valgrind's nanosleep implementation
1847 is nonblocking. */
1848 (void)my_do_syscall2(__NR_nanosleep,
1849 (int)(&nanosleep_interval), (int)NULL);
1850 }
1851}
1852
1853
1854
1855
1856#include <sys/poll.h>
1857
sewardj72d58482002-04-24 02:20:20 +00001858#ifdef GLIBC_2_1
1859typedef unsigned long int nfds_t;
1860#endif
1861
sewardj705d3cb2002-05-23 13:13:12 +00001862
sewardj5905fae2002-04-26 13:25:00 +00001863/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00001864int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1865{
sewardj5f07b662002-04-23 16:52:51 +00001866 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001867 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001868 struct vki_timespec nanosleep_interval;
1869
sewardjd140e442002-05-29 01:21:19 +00001870 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00001871 ensure_valgrind("poll");
1872
sewardj5f07b662002-04-23 16:52:51 +00001873 /* Detect the current time and simultaneously find out if we are
1874 running on Valgrind. */
1875 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1876 VG_USERREQ__READ_MILLISECOND_TIMER,
1877 0, 0, 0, 0);
1878
sewardjf854f472002-04-21 12:19:41 +00001879 if (/* CHECK SIZES FOR struct pollfd */
1880 sizeof(struct timeval) != sizeof(struct vki_timeval))
1881 barf("valgrind's hacky non-blocking poll(): data sizes error");
1882
sewardj5f07b662002-04-23 16:52:51 +00001883 /* dummy initialisation to keep gcc -Wall happy */
1884 ms_end = 0;
1885
1886 /* If a zero timeout specified, this call is harmless. Also do
1887 this if not running on Valgrind. */
1888 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001889 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1890 if (is_kerror(res)) {
1891 * (__errno_location()) = -res;
1892 return -1;
1893 } else {
1894 return res;
1895 }
1896 }
1897
sewardj5f07b662002-04-23 16:52:51 +00001898 /* If a timeout was specified, set ms_end to be the end wallclock
1899 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001900 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00001901 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001902 }
1903
1904 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1905
1906 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1907 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001908 assert(__timeout != 0);
1909
sewardjf854f472002-04-21 12:19:41 +00001910 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001911 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001912 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1913 VG_USERREQ__READ_MILLISECOND_TIMER,
1914 0, 0, 0, 0);
1915 assert(ms_now != 0xFFFFFFFF);
1916 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001917 /* timeout; nothing interesting happened. */
1918 for (i = 0; i < __nfds; i++)
1919 __fds[i].revents = 0;
1920 return 0;
1921 }
1922 }
1923
sewardj5f07b662002-04-23 16:52:51 +00001924 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001925 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1926 if (is_kerror(res)) {
1927 /* Some kind of error. Set errno and return. */
1928 * (__errno_location()) = -res;
1929 return -1;
1930 }
1931 if (res > 0) {
1932 /* One or more fds is ready. Return now. */
1933 return res;
1934 }
1935 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1936 /* nanosleep and go round again */
1937 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001938 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001939 /* It's critical here that valgrind's nanosleep implementation
1940 is nonblocking. */
1941 (void)my_do_syscall2(__NR_nanosleep,
1942 (int)(&nanosleep_interval), (int)NULL);
1943 }
1944}
sewardj3b13f0e2002-04-25 20:17:29 +00001945
1946
sewardj705d3cb2002-05-23 13:13:12 +00001947/* Helper function used to make accept() non-blocking. Idea is to use
1948 the above nonblocking poll() to make this thread ONLY wait for the
1949 specified fd to become ready, and then return. */
1950static void wait_for_fd_to_be_readable_or_erring ( int fd )
1951{
1952 struct pollfd pfd;
sewardj6e6cbaa2002-05-24 02:12:52 +00001953 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardj705d3cb2002-05-23 13:13:12 +00001954 pfd.fd = fd;
1955 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
1956 /* ... but not POLLOUT, you may notice. */
1957 pfd.revents = 0;
1958 (void)poll(&pfd, 1, -1 /* forever */);
1959}
1960
1961
sewardj3b13f0e2002-04-25 20:17:29 +00001962/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00001963 Hacky implementation of semaphores.
1964 ------------------------------------------------------------------ */
1965
1966#include <semaphore.h>
1967
1968/* This is a terrible way to do the remapping. Plan is to import an
1969 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00001970
1971typedef
1972 struct {
1973 pthread_mutex_t se_mx;
1974 pthread_cond_t se_cv;
1975 int count;
1976 }
1977 vg_sem_t;
1978
1979static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
1980
1981static int se_remap_used = 0;
1982static sem_t* se_remap_orig[VG_N_SEMAPHORES];
1983static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
1984
1985static vg_sem_t* se_remap ( sem_t* orig )
1986{
1987 int res, i;
1988 res = __pthread_mutex_lock(&se_remap_mx);
1989 assert(res == 0);
1990
1991 for (i = 0; i < se_remap_used; i++) {
1992 if (se_remap_orig[i] == orig)
1993 break;
1994 }
1995 if (i == se_remap_used) {
1996 if (se_remap_used == VG_N_SEMAPHORES) {
1997 res = pthread_mutex_unlock(&se_remap_mx);
1998 assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00001999 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002000 }
2001 se_remap_used++;
2002 se_remap_orig[i] = orig;
2003 /* printf("allocated semaphore %d\n", i); */
2004 }
2005 res = __pthread_mutex_unlock(&se_remap_mx);
2006 assert(res == 0);
2007 return &se_remap_new[i];
2008}
2009
2010
2011int sem_init(sem_t *sem, int pshared, unsigned int value)
2012{
2013 int res;
2014 vg_sem_t* vg_sem;
2015 ensure_valgrind("sem_init");
2016 if (pshared != 0) {
2017 errno = ENOSYS;
2018 return -1;
2019 }
2020 vg_sem = se_remap(sem);
2021 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
2022 assert(res == 0);
2023 res = pthread_cond_init(&vg_sem->se_cv, NULL);
2024 assert(res == 0);
2025 vg_sem->count = value;
2026 return 0;
2027}
2028
2029
2030int sem_wait ( sem_t* sem )
2031{
2032 int res;
2033 vg_sem_t* vg_sem;
2034 ensure_valgrind("sem_wait");
2035 vg_sem = se_remap(sem);
2036 res = __pthread_mutex_lock(&vg_sem->se_mx);
2037 assert(res == 0);
2038 while (vg_sem->count == 0) {
2039 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
2040 assert(res == 0);
2041 }
2042 vg_sem->count--;
2043 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2044 assert(res == 0);
2045 return 0;
2046}
2047
2048int sem_post ( sem_t* sem )
2049{
2050 int res;
2051 vg_sem_t* vg_sem;
2052 ensure_valgrind("sem_post");
2053 vg_sem = se_remap(sem);
2054 res = __pthread_mutex_lock(&vg_sem->se_mx);
2055 assert(res == 0);
2056 if (vg_sem->count == 0) {
2057 vg_sem->count++;
2058 res = pthread_cond_broadcast(&vg_sem->se_cv);
2059 assert(res == 0);
2060 } else {
2061 vg_sem->count++;
2062 }
2063 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2064 assert(res == 0);
2065 return 0;
2066}
2067
2068
2069int sem_trywait ( sem_t* sem )
2070{
2071 int ret, res;
2072 vg_sem_t* vg_sem;
2073 ensure_valgrind("sem_trywait");
2074 vg_sem = se_remap(sem);
2075 res = __pthread_mutex_lock(&vg_sem->se_mx);
2076 assert(res == 0);
2077 if (vg_sem->count > 0) {
2078 vg_sem->count--;
2079 ret = 0;
2080 } else {
2081 ret = -1;
2082 errno = EAGAIN;
2083 }
2084 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2085 assert(res == 0);
2086 return ret;
2087}
2088
2089
2090int sem_getvalue(sem_t* sem, int * sval)
2091{
2092 vg_sem_t* vg_sem;
2093 ensure_valgrind("sem_trywait");
2094 vg_sem = se_remap(sem);
2095 *sval = vg_sem->count;
2096 return 0;
2097}
2098
2099
2100int sem_destroy(sem_t * sem)
2101{
2102 kludged("sem_destroy");
2103 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2104 return 0;
2105}
2106
2107
2108/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002109 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002110 ------------------------------------------------------------------ */
2111
sewardj2d8b3f02002-06-01 14:14:19 +00002112typedef
2113 struct {
2114 int initted; /* != 0 --> in use; sanity check only */
2115 int prefer_w; /* != 0 --> prefer writer */
2116 int nwait_r; /* # of waiting readers */
2117 int nwait_w; /* # of waiting writers */
2118 pthread_cond_t cv_r; /* for signalling readers */
2119 pthread_cond_t cv_w; /* for signalling writers */
2120 pthread_mutex_t mx;
2121 int status;
2122 /* allowed range for status: >= -1. -1 means 1 writer currently
2123 active, >= 0 means N readers currently active. */
2124 }
2125 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002126
2127
2128static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2129
2130static int rw_remap_used = 0;
2131static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2132static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2133
sewardj2d8b3f02002-06-01 14:14:19 +00002134
2135static
2136void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2137{
2138 int res = 0;
2139 vg_rwl->initted = 1;
2140 vg_rwl->prefer_w = 1;
2141 vg_rwl->nwait_r = 0;
2142 vg_rwl->nwait_w = 0;
2143 vg_rwl->status = 0;
2144 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2145 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2146 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
2147 assert(res == 0);
2148}
2149
2150
sewardja1ac5cb2002-05-27 13:00:05 +00002151/* Take the address of a LinuxThreads rwlock_t and return the shadow
2152 address of our version. Further, if the LinuxThreads version
2153 appears to have been statically initialised, do the same to the one
2154 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2155 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2156 uninitialised and non-zero meaning initialised.
2157*/
2158static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2159{
2160 int res, i;
2161 vg_rwlock_t* vg_rwl;
2162 res = __pthread_mutex_lock(&rw_remap_mx);
2163 assert(res == 0);
2164
2165 for (i = 0; i < rw_remap_used; i++) {
2166 if (rw_remap_orig[i] == orig)
2167 break;
2168 }
2169 if (i == rw_remap_used) {
2170 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002171 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002172 assert(res == 0);
2173 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2174 }
2175 rw_remap_used++;
2176 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002177 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002178 if (0) printf("allocated rwlock %d\n", i);
2179 }
2180 res = __pthread_mutex_unlock(&rw_remap_mx);
2181 assert(res == 0);
2182 vg_rwl = &rw_remap_new[i];
2183
sewardj2d8b3f02002-06-01 14:14:19 +00002184 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002185 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002186 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002187 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002188 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002189 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002190 }
2191
2192 return vg_rwl;
2193}
2194
2195
sewardja1ac5cb2002-05-27 13:00:05 +00002196int pthread_rwlock_init ( pthread_rwlock_t* orig,
2197 const pthread_rwlockattr_t* attr )
2198{
sewardja1ac5cb2002-05-27 13:00:05 +00002199 vg_rwlock_t* rwl;
2200 if (0) printf ("pthread_rwlock_init\n");
2201 /* Force the remapper to initialise the shadow. */
2202 orig->__rw_readers = 0;
2203 /* Install the lock preference; the remapper needs to know it. */
2204 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2205 if (attr)
2206 orig->__rw_kind = attr->__lockkind;
2207 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002208 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002209}
2210
sewardj2d8b3f02002-06-01 14:14:19 +00002211
2212static
2213void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002214{
sewardj2d8b3f02002-06-01 14:14:19 +00002215 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2216 rwl->nwait_r--;
2217 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002218}
2219
sewardj2d8b3f02002-06-01 14:14:19 +00002220
sewardja1ac5cb2002-05-27 13:00:05 +00002221int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2222{
2223 int res;
2224 vg_rwlock_t* rwl;
2225 if (0) printf ("pthread_rwlock_rdlock\n");
2226 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002227 res = __pthread_mutex_lock(&rwl->mx);
2228 assert(res == 0);
2229 if (!rwl->initted) {
2230 res = __pthread_mutex_unlock(&rwl->mx);
2231 assert(res == 0);
2232 return EINVAL;
2233 }
2234 if (rwl->status < 0) {
2235 assert(rwl->status == -1);
2236 rwl->nwait_r++;
2237 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2238 while (1) {
2239 if (rwl->status == 0) break;
2240 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
2241 assert(res == 0);
2242 }
2243 pthread_cleanup_pop(0);
2244 rwl->nwait_r--;
2245 }
2246 assert(rwl->status >= 0);
2247 rwl->status++;
2248 res = __pthread_mutex_unlock(&rwl->mx);
2249 assert(res == 0);
2250 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002251}
2252
sewardj2d8b3f02002-06-01 14:14:19 +00002253
sewardja1ac5cb2002-05-27 13:00:05 +00002254int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2255{
2256 int res;
2257 vg_rwlock_t* rwl;
2258 if (0) printf ("pthread_rwlock_tryrdlock\n");
2259 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002260 res = __pthread_mutex_lock(&rwl->mx);
2261 assert(res == 0);
2262 if (!rwl->initted) {
2263 res = __pthread_mutex_unlock(&rwl->mx);
2264 assert(res == 0);
2265 return EINVAL;
2266 }
2267 if (rwl->status == -1) {
2268 /* Writer active; we have to give up. */
2269 res = __pthread_mutex_unlock(&rwl->mx);
2270 assert(res == 0);
2271 return EBUSY;
2272 }
2273 /* Success */
2274 assert(rwl->status >= 0);
2275 rwl->status++;
2276 res = __pthread_mutex_unlock(&rwl->mx);
2277 assert(res == 0);
2278 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002279}
2280
sewardj2d8b3f02002-06-01 14:14:19 +00002281
2282static
2283void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2284{
2285 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2286 rwl->nwait_w--;
2287 pthread_mutex_unlock (&rwl->mx);
2288}
2289
2290
sewardja1ac5cb2002-05-27 13:00:05 +00002291int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2292{
2293 int res;
2294 vg_rwlock_t* rwl;
2295 if (0) printf ("pthread_rwlock_wrlock\n");
2296 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002297 res = __pthread_mutex_lock(&rwl->mx);
2298 assert(res == 0);
2299 if (!rwl->initted) {
2300 res = __pthread_mutex_unlock(&rwl->mx);
2301 assert(res == 0);
2302 return EINVAL;
2303 }
2304 if (rwl->status != 0) {
2305 rwl->nwait_w++;
2306 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2307 while (1) {
2308 if (rwl->status == 0) break;
2309 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
2310 assert(res == 0);
2311 }
2312 pthread_cleanup_pop(0);
2313 rwl->nwait_w--;
2314 }
2315 assert(rwl->status == 0);
2316 rwl->status = -1;
2317 res = __pthread_mutex_unlock(&rwl->mx);
2318 assert(res == 0);
2319 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002320}
2321
sewardj2d8b3f02002-06-01 14:14:19 +00002322
sewardja1ac5cb2002-05-27 13:00:05 +00002323int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2324{
2325 int res;
2326 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002327 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002328 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002329 res = __pthread_mutex_lock(&rwl->mx);
2330 assert(res == 0);
2331 if (!rwl->initted) {
2332 res = __pthread_mutex_unlock(&rwl->mx);
2333 assert(res == 0);
2334 return EINVAL;
2335 }
2336 if (rwl->status != 0) {
2337 /* Reader(s) or a writer active; we have to give up. */
2338 res = __pthread_mutex_unlock(&rwl->mx);
2339 assert(res == 0);
2340 return EBUSY;
2341 }
2342 /* Success */
2343 assert(rwl->status == 0);
2344 rwl->status = -1;
2345 res = __pthread_mutex_unlock(&rwl->mx);
2346 assert(res == 0);
2347 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002348}
2349
sewardj2d8b3f02002-06-01 14:14:19 +00002350
sewardja1ac5cb2002-05-27 13:00:05 +00002351int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2352{
2353 int res;
2354 vg_rwlock_t* rwl;
2355 if (0) printf ("pthread_rwlock_unlock\n");
2356 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002357 rwl = rw_remap ( orig );
2358 res = __pthread_mutex_lock(&rwl->mx);
2359 assert(res == 0);
2360 if (!rwl->initted) {
2361 res = __pthread_mutex_unlock(&rwl->mx);
2362 assert(res == 0);
2363 return EINVAL;
2364 }
2365 if (rwl->status == 0) {
2366 res = __pthread_mutex_unlock(&rwl->mx);
2367 assert(res == 0);
2368 return EPERM;
2369 }
2370 assert(rwl->status != 0);
2371 if (rwl->status == -1) {
2372 rwl->status = 0;
2373 } else {
2374 assert(rwl->status > 0);
2375 rwl->status--;
2376 }
2377
2378 assert(rwl->status >= 0);
2379
2380 if (rwl->prefer_w) {
2381
2382 /* Favour waiting writers, if any. */
2383 if (rwl->nwait_w > 0) {
2384 /* Writer(s) are waiting. */
2385 if (rwl->status == 0) {
2386 /* We can let a writer in. */
2387 res = pthread_cond_signal(&rwl->cv_w);
2388 assert(res == 0);
2389 } else {
2390 /* There are still readers active. Do nothing; eventually
2391 they will disappear, at which point a writer will be
2392 admitted. */
2393 }
2394 }
2395 else
2396 /* No waiting writers. */
2397 if (rwl->nwait_r > 0) {
2398 /* Let in a waiting reader. */
2399 res = pthread_cond_signal(&rwl->cv_r);
2400 assert(res == 0);
2401 }
2402
2403 } else {
2404
2405 /* Favour waiting readers, if any. */
2406 if (rwl->nwait_r > 0) {
2407 /* Reader(s) are waiting; let one in. */
2408 res = pthread_cond_signal(&rwl->cv_r);
2409 assert(res == 0);
2410 }
2411 else
2412 /* No waiting readers. */
2413 if (rwl->nwait_w > 0 && rwl->status == 0) {
2414 /* We have waiting writers and no active readers; let a
2415 writer in. */
2416 res = pthread_cond_signal(&rwl->cv_w);
2417 assert(res == 0);
2418 }
2419 }
2420
2421 res = __pthread_mutex_unlock(&rwl->mx);
2422 assert(res == 0);
2423 return 0;
2424}
2425
2426
2427int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2428{
2429 int res;
2430 vg_rwlock_t* rwl;
2431 if (0) printf ("pthread_rwlock_destroy\n");
2432 rwl = rw_remap ( orig );
2433 res = __pthread_mutex_lock(&rwl->mx);
2434 assert(res == 0);
2435 if (!rwl->initted) {
2436 res = __pthread_mutex_unlock(&rwl->mx);
2437 assert(res == 0);
2438 return EINVAL;
2439 }
2440 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2441 res = __pthread_mutex_unlock(&rwl->mx);
2442 assert(res == 0);
2443 return EBUSY;
2444 }
2445 rwl->initted = 0;
2446 res = __pthread_mutex_unlock(&rwl->mx);
2447 assert(res == 0);
2448 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002449}
2450
2451
2452/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002453 B'stard.
2454 ------------------------------------------------------------------ */
2455
2456# define strong_alias(name, aliasname) \
2457 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2458
sewardj5905fae2002-04-26 13:25:00 +00002459# define weak_alias(name, aliasname) \
2460 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002461
sewardj5905fae2002-04-26 13:25:00 +00002462strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2463strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2464strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2465strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2466 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2467strong_alias(__pthread_mutex_init, pthread_mutex_init)
2468strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2469strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2470strong_alias(__pthread_once, pthread_once)
2471strong_alias(__pthread_atfork, pthread_atfork)
2472strong_alias(__pthread_key_create, pthread_key_create)
2473strong_alias(__pthread_getspecific, pthread_getspecific)
2474strong_alias(__pthread_setspecific, pthread_setspecific)
2475
sewardjd529a442002-05-04 19:49:21 +00002476#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002477strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002478#endif
2479
sewardj5905fae2002-04-26 13:25:00 +00002480strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002481strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002482strong_alias(lseek, __lseek)
2483strong_alias(open, __open)
2484strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002485strong_alias(read, __read)
2486strong_alias(wait, __wait)
2487strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002488strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002489strong_alias(send, __send)
2490
sewardj726c4122002-05-16 23:39:10 +00002491weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002492weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002493weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002494
sewardj5905fae2002-04-26 13:25:00 +00002495
sewardj3b13f0e2002-04-25 20:17:29 +00002496
2497/*--------------------------------------------------*/
2498
sewardj5905fae2002-04-26 13:25:00 +00002499weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002500weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002501weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002502
sewardja1ac5cb2002-05-27 13:00:05 +00002503weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2504weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2505weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2506weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2507
sewardj060b04f2002-04-26 21:01:13 +00002508
sewardj3b13f0e2002-04-25 20:17:29 +00002509/* I've no idea what these are, but they get called quite a lot.
2510 Anybody know? */
2511
2512#undef _IO_flockfile
2513void _IO_flockfile ( _IO_FILE * file )
2514{
sewardj853f55d2002-04-26 00:27:53 +00002515 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002516}
sewardj5905fae2002-04-26 13:25:00 +00002517weak_alias(_IO_flockfile, flockfile);
2518
sewardj3b13f0e2002-04-25 20:17:29 +00002519
2520#undef _IO_funlockfile
2521void _IO_funlockfile ( _IO_FILE * file )
2522{
sewardj853f55d2002-04-26 00:27:53 +00002523 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002524}
sewardj5905fae2002-04-26 13:25:00 +00002525weak_alias(_IO_funlockfile, funlockfile);
2526
sewardj3b13f0e2002-04-25 20:17:29 +00002527
sewardjd4f2c712002-04-30 10:20:10 +00002528/* This doesn't seem to be needed to simulate libpthread.so's external
2529 interface, but many people complain about its absence. */
2530
2531strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2532weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002533
2534
2535/*--------------------------------------------------------------------*/
2536/*--- end vg_libpthread.c ---*/
2537/*--------------------------------------------------------------------*/