blob: 2ccf8069e37ae472edc06e75b2d199b2e7065d13 [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
sewardj2d94c112002-06-03 01:25:54 +000069#include <stdio.h>
70
sewardj705d3cb2002-05-23 13:13:12 +000071
72/* ---------------------------------------------------------------------
73 Forwardses.
74 ------------------------------------------------------------------ */
75
76static void wait_for_fd_to_be_readable_or_erring ( int fd );
77
sewardj9a2224b2002-06-19 10:17:40 +000078static
79int my_do_syscall2 ( int syscallno,
80 int arg1, int arg2 );
81
sewardj705d3cb2002-05-23 13:13:12 +000082
sewardje663cb92002-04-12 10:26:32 +000083/* ---------------------------------------------------------------------
84 Helpers. We have to be pretty self-sufficient.
85 ------------------------------------------------------------------ */
86
sewardj436e0582002-04-26 14:31:40 +000087/* Number of times any given error message is printed. */
88#define N_MOANS 3
89
sewardj45b4b372002-04-16 22:50:32 +000090/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
91 Returns 0 (none) if not running on Valgrind. */
92static
93int get_pt_trace_level ( void )
94{
95 int res;
96 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
97 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
98 0, 0, 0, 0);
99 return res;
100}
101
102
sewardje663cb92002-04-12 10:26:32 +0000103static
sewardj2d94c112002-06-03 01:25:54 +0000104void my_exit ( int arg )
sewardje663cb92002-04-12 10:26:32 +0000105{
sewardj45b4b372002-04-16 22:50:32 +0000106 int __res;
sewardje663cb92002-04-12 10:26:32 +0000107 __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
108 : "=a" (__res)
109 : "0" (__NR_exit),
110 "c" (arg) );
sewardj45b4b372002-04-16 22:50:32 +0000111 /* We don't bother to mention the fact that this asm trashes %ebx,
112 since it won't return. If you ever do let it return ... fix
113 this! */
sewardje663cb92002-04-12 10:26:32 +0000114}
115
116
sewardj68b2dd92002-05-10 21:03:56 +0000117/* We need this guy -- it's in valgrind.so. */
118extern void VG_(startup) ( void );
119
120
121/* Just start up Valgrind if it's not already going. VG_(startup)()
122 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000123static __inline__
sewardje663cb92002-04-12 10:26:32 +0000124void ensure_valgrind ( char* caller )
125{
sewardj68b2dd92002-05-10 21:03:56 +0000126 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000127}
128
sewardjbea1caa2002-05-10 23:20:58 +0000129/* While we're at it ... hook our own startup function into this
130 game. */
131__asm__ (
132 ".section .init\n"
133 "\tcall vgPlain_startup"
134);
135
sewardje663cb92002-04-12 10:26:32 +0000136
137static
sewardj3b5d8862002-04-20 13:53:23 +0000138__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +0000139void barf ( char* str )
140{
141 char buf[100];
142 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000143 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000144 strcat(buf, str);
145 strcat(buf, "\n\n");
146 write(2, buf, strlen(buf));
sewardj2d94c112002-06-03 01:25:54 +0000147 my_exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000148 /* We have to persuade gcc into believing this doesn't return. */
149 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000150}
151
152
sewardj2a3d28c2002-04-14 13:27:00 +0000153static void ignored ( char* msg )
154{
sewardj436e0582002-04-26 14:31:40 +0000155 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000156 char* ig = "valgrind's libpthread.so: IGNORED call to: ";
sewardj45b4b372002-04-16 22:50:32 +0000157 write(2, ig, strlen(ig));
158 write(2, msg, strlen(msg));
159 ig = "\n";
160 write(2, ig, strlen(ig));
161 }
sewardj2a3d28c2002-04-14 13:27:00 +0000162}
163
sewardj30671ff2002-04-21 00:13:57 +0000164static void kludged ( char* msg )
165{
sewardj436e0582002-04-26 14:31:40 +0000166 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000167 char* ig = "valgrind's libpthread.so: KLUDGED call to: ";
168 write(2, ig, strlen(ig));
169 write(2, msg, strlen(msg));
170 ig = "\n";
171 write(2, ig, strlen(ig));
172 }
173}
174
175static void not_inside ( char* msg )
176{
sewardj68b2dd92002-05-10 21:03:56 +0000177 VG_(startup)();
sewardj30671ff2002-04-21 00:13:57 +0000178}
179
sewardjccef2e62002-05-29 19:26:32 +0000180__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000181void vgPlain_unimp ( char* what )
182{
sewardj439d45e2002-05-03 20:43:10 +0000183 char* ig = "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ";
sewardj3b13f0e2002-04-25 20:17:29 +0000184 write(2, ig, strlen(ig));
185 write(2, what, strlen(what));
186 ig = "\n";
187 write(2, ig, strlen(ig));
188 barf("Please report this bug to me at: jseward@acm.org");
189}
190
sewardje663cb92002-04-12 10:26:32 +0000191
sewardj457cc472002-06-03 23:13:47 +0000192static
sewardj2d94c112002-06-03 01:25:54 +0000193void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
194{
195 static Bool entered = False;
196 if (entered)
197 my_exit(2);
198 entered = True;
199 fprintf(stderr, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
200 "valgrind", file, line, fn, expr );
201 fprintf(stderr, "Please report this bug to me at: %s\n\n",
202 VG_EMAIL_ADDR);
203 my_exit(1);
204}
205
206#define MY__STRING(__str) #__str
207
208#define my_assert(expr) \
209 ((void) ((expr) ? 0 : \
210 (my_assert_fail (MY__STRING(expr), \
211 __FILE__, __LINE__, \
212 __PRETTY_FUNCTION__), 0)))
213
214
sewardje663cb92002-04-12 10:26:32 +0000215/* ---------------------------------------------------------------------
216 Pass pthread_ calls to Valgrind's request mechanism.
217 ------------------------------------------------------------------ */
218
sewardjf8f819e2002-04-17 23:21:37 +0000219#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000220#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000221
sewardja1ac5cb2002-05-27 13:00:05 +0000222
sewardjf8f819e2002-04-17 23:21:37 +0000223/* ---------------------------------------------------
sewardj4dced352002-06-04 22:54:20 +0000224 Ummm ..
225 ------------------------------------------------ */
226
227static
228void pthread_error ( const char* msg )
229{
230 int res;
231 VALGRIND_MAGIC_SEQUENCE(res, 0,
232 VG_USERREQ__PTHREAD_ERROR,
233 msg, 0, 0, 0);
234}
235
236
237/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000238 THREAD ATTRIBUTES
239 ------------------------------------------------ */
240
sewardj6af4b5d2002-04-16 04:40:49 +0000241int pthread_attr_init(pthread_attr_t *attr)
242{
sewardj7989d0c2002-05-28 11:00:01 +0000243 /* Just initialise the fields which we might look at. */
244 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj6af4b5d2002-04-16 04:40:49 +0000245 return 0;
246}
247
248int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
249{
sewardj7989d0c2002-05-28 11:00:01 +0000250 if (detachstate != PTHREAD_CREATE_JOINABLE
sewardj4dced352002-06-04 22:54:20 +0000251 && detachstate != PTHREAD_CREATE_DETACHED) {
252 pthread_error("pthread_attr_setdetachstate: "
253 "detachstate is invalid");
sewardj7989d0c2002-05-28 11:00:01 +0000254 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000255 }
sewardj7989d0c2002-05-28 11:00:01 +0000256 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000257 return 0;
258}
259
sewardj30671ff2002-04-21 00:13:57 +0000260int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
261{
sewardj436e0582002-04-26 14:31:40 +0000262 static int moans = N_MOANS;
263 if (moans-- > 0)
264 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000265 return 0;
266}
sewardj6af4b5d2002-04-16 04:40:49 +0000267
sewardj0286dd52002-05-16 20:51:15 +0000268__attribute__((weak))
269int pthread_attr_setstacksize (pthread_attr_t *__attr,
270 size_t __stacksize)
271{
sewardja18e2102002-05-18 10:43:22 +0000272 size_t limit;
sewardj3d7c8d62002-06-04 20:59:16 +0000273 char buf[1024];
sewardj0286dd52002-05-16 20:51:15 +0000274 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000275 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
276 - 1000; /* paranoia */
277 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000278 return 0;
sewardj3d7c8d62002-06-04 20:59:16 +0000279 snprintf(buf, sizeof(buf), "pthread_attr_setstacksize: "
280 "requested size %d >= VG_PTHREAD_STACK_SIZE\n "
281 "edit vg_include.h and rebuild.", __stacksize);
282 buf[sizeof(buf)-1] = '\0'; /* Make sure it is zero terminated */
283 barf(buf);
sewardj0286dd52002-05-16 20:51:15 +0000284}
285
286
sewardj30671ff2002-04-21 00:13:57 +0000287/* This is completely bogus. */
288int pthread_attr_getschedparam(const pthread_attr_t *attr,
289 struct sched_param *param)
290{
sewardj436e0582002-04-26 14:31:40 +0000291 static int moans = N_MOANS;
292 if (moans-- > 0)
293 kludged("pthread_attr_getschedparam");
sewardj3e909ce2002-06-03 13:27:15 +0000294# ifdef HAVE_SCHED_PRIORITY
sewardj72d58482002-04-24 02:20:20 +0000295 if (param) param->sched_priority = 0; /* who knows */
296# else
sewardj30671ff2002-04-21 00:13:57 +0000297 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000298# endif
sewardj30671ff2002-04-21 00:13:57 +0000299 return 0;
300}
301
302int pthread_attr_setschedparam(pthread_attr_t *attr,
303 const struct sched_param *param)
304{
sewardj436e0582002-04-26 14:31:40 +0000305 static int moans = N_MOANS;
306 if (moans-- > 0)
307 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000308 return 0;
309}
310
311int pthread_attr_destroy(pthread_attr_t *attr)
312{
sewardj436e0582002-04-26 14:31:40 +0000313 static int moans = N_MOANS;
314 if (moans-- > 0)
315 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000316 return 0;
317}
sewardjf8f819e2002-04-17 23:21:37 +0000318
sewardj0d844232002-06-02 09:29:31 +0000319/* These are no-ops, as with LinuxThreads. */
320int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
321{
322 ensure_valgrind("pthread_attr_setscope");
323 if (scope == PTHREAD_SCOPE_SYSTEM)
324 return 0;
sewardj4dced352002-06-04 22:54:20 +0000325 pthread_error("pthread_attr_setscope: "
326 "invalid or unsupported scope");
sewardj0d844232002-06-02 09:29:31 +0000327 if (scope == PTHREAD_SCOPE_PROCESS)
328 return ENOTSUP;
329 return EINVAL;
330}
331
332int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
333{
334 ensure_valgrind("pthread_attr_setscope");
335 if (scope)
336 *scope = PTHREAD_SCOPE_SYSTEM;
337 return 0;
338}
339
sewardj64039bb2002-06-03 00:58:18 +0000340
341/* Pretty bogus. Avoid if possible. */
342int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
343{
344 int detached;
345 size_t limit;
346 ensure_valgrind("pthread_getattr_np");
347 kludged("pthread_getattr_np");
348 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
349 - 1000; /* paranoia */
350 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
351 attr->__schedpolicy = SCHED_OTHER;
352 attr->__schedparam.sched_priority = 0;
353 attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
354 attr->__scope = PTHREAD_SCOPE_SYSTEM;
355 attr->__guardsize = VKI_BYTES_PER_PAGE;
356 attr->__stackaddr = NULL;
357 attr->__stackaddr_set = 0;
358 attr->__stacksize = limit;
359 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
360 VG_USERREQ__SET_OR_GET_DETACH,
361 2 /* get */, thread, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000362 my_assert(detached == 0 || detached == 1);
sewardj64039bb2002-06-03 00:58:18 +0000363 if (detached)
364 attr->__detachstate = PTHREAD_CREATE_DETACHED;
365 return 0;
366}
367
368
369/* Bogus ... */
370int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
371 void ** stackaddr )
372{
373 ensure_valgrind("pthread_attr_getstackaddr");
374 kludged("pthread_attr_getstackaddr");
375 if (stackaddr)
376 *stackaddr = NULL;
377 return 0;
378}
379
380/* Not bogus (!) */
381int pthread_attr_getstacksize ( const pthread_attr_t * _attr,
382 size_t * __stacksize )
383{
384 size_t limit;
385 ensure_valgrind("pthread_attr_getstacksize");
386 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
387 - 1000; /* paranoia */
388 if (__stacksize)
389 *__stacksize = limit;
390 return 0;
391}
392
sewardja3be12f2002-06-17 12:19:44 +0000393int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
394{
395 if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
396 return EINVAL;
397 attr->__schedpolicy = policy;
398 return 0;
399}
400
401int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
402{
403 *policy = attr->__schedpolicy;
404 return 0;
405}
406
407
sewardj20917d82002-05-28 01:36:45 +0000408/* ---------------------------------------------------
409 Helper functions for running a thread
410 and for clearing up afterwards.
411 ------------------------------------------------ */
412
413/* All exiting threads eventually pass through here, bearing the
414 return value, or PTHREAD_CANCELED, in ret_val. */
415static
416__attribute__((noreturn))
417void thread_exit_wrapper ( void* ret_val )
418{
sewardj870497a2002-05-29 01:06:47 +0000419 int detached, res;
420 CleanupEntry cu;
421 pthread_key_t key;
422
sewardj20917d82002-05-28 01:36:45 +0000423 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000424 while (1) {
425 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
426 VG_USERREQ__CLEANUP_POP,
427 &cu, 0, 0, 0);
428 if (res == -1) break; /* stack empty */
sewardj2d94c112002-06-03 01:25:54 +0000429 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000430 if (0) printf("running exit cleanup handler");
431 cu.fn ( cu.arg );
432 }
433
sewardj870497a2002-05-29 01:06:47 +0000434 /* Run this thread's key finalizers. Really this should be run
435 PTHREAD_DESTRUCTOR_ITERATIONS times. */
436 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
437 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
438 VG_USERREQ__GET_KEY_D_AND_S,
439 key, &cu, 0, 0 );
440 if (res == 0) {
441 /* valid key */
442 if (cu.fn && cu.arg)
443 cu.fn /* destructor for key */
444 ( cu.arg /* specific for key for this thread */ );
445 continue;
446 }
sewardj2d94c112002-06-03 01:25:54 +0000447 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000448 }
sewardj20917d82002-05-28 01:36:45 +0000449
450 /* Decide on my final disposition. */
451 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
452 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000453 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000454 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000455
456 if (detached) {
457 /* Detached; I just quit right now. */
458 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
459 VG_USERREQ__QUIT, 0, 0, 0, 0);
460 } else {
461 /* Not detached; so I wait for a joiner. */
462 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
463 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
464 }
465 /* NOTREACHED */
466 barf("thread_exit_wrapper: still alive?!");
467}
468
469
470/* This function is a wrapper function for running a thread. It runs
471 the root function specified in pthread_create, and then, should the
472 root function return a value, it arranges to run the thread's
473 cleanup handlers and exit correctly. */
474
sewardj728a5272002-06-20 10:25:37 +0000475/* Struct used to convey info from pthread_create to thread_wrapper.
476 Must be careful not to pass to the child thread any pointers to
477 objects which might be on the parent's stack. */
sewardj20917d82002-05-28 01:36:45 +0000478typedef
479 struct {
sewardj728a5272002-06-20 10:25:37 +0000480 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000481 void* (*root_fn) ( void* );
482 void* arg;
483 }
484 NewThreadInfo;
485
486
487/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
488 not return. Note that this runs in the new thread, not the
489 parent. */
490static
491__attribute__((noreturn))
492void thread_wrapper ( NewThreadInfo* info )
493{
sewardj728a5272002-06-20 10:25:37 +0000494 int res;
495 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000496 void* (*root_fn) ( void* );
497 void* arg;
498 void* ret_val;
499
sewardj728a5272002-06-20 10:25:37 +0000500 attr__detachstate = info->attr__detachstate;
501 root_fn = info->root_fn;
502 arg = info->arg;
sewardj20917d82002-05-28 01:36:45 +0000503
sewardj20917d82002-05-28 01:36:45 +0000504 /* Free up the arg block that pthread_create malloced. */
505 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
506 VG_USERREQ__FREE, info, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000507 my_assert(res == 0);
sewardj20917d82002-05-28 01:36:45 +0000508
sewardj7989d0c2002-05-28 11:00:01 +0000509 /* Minimally observe the attributes supplied. */
sewardj728a5272002-06-20 10:25:37 +0000510 if (attr__detachstate != PTHREAD_CREATE_DETACHED
511 && attr__detachstate != PTHREAD_CREATE_JOINABLE)
512 pthread_error("thread_wrapper: invalid attr->__detachstate");
513 if (attr__detachstate == PTHREAD_CREATE_DETACHED)
514 pthread_detach(pthread_self());
sewardj7989d0c2002-05-28 11:00:01 +0000515
sewardj20917d82002-05-28 01:36:45 +0000516 /* The root function might not return. But if it does we simply
517 move along to thread_exit_wrapper. All other ways out for the
518 thread (cancellation, or calling pthread_exit) lead there
519 too. */
520 ret_val = root_fn(arg);
521 thread_exit_wrapper(ret_val);
522 /* NOTREACHED */
523}
524
525
sewardjf8f819e2002-04-17 23:21:37 +0000526/* ---------------------------------------------------
527 THREADs
528 ------------------------------------------------ */
529
sewardjff42d1d2002-05-22 13:17:31 +0000530__attribute__((weak))
531int pthread_yield ( void )
532{
533 int res;
534 ensure_valgrind("pthread_yield");
535 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
536 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
537 return 0;
538}
539
540
sewardj6072c362002-04-19 14:40:57 +0000541int pthread_equal(pthread_t thread1, pthread_t thread2)
542{
543 return thread1 == thread2 ? 1 : 0;
544}
545
546
sewardj20917d82002-05-28 01:36:45 +0000547/* Bundle up the args into a malloc'd block and create a new thread
548 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000549int
550pthread_create (pthread_t *__restrict __thread,
551 __const pthread_attr_t *__restrict __attr,
552 void *(*__start_routine) (void *),
553 void *__restrict __arg)
554{
sewardj20917d82002-05-28 01:36:45 +0000555 int tid_child;
556 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000557
sewardj20917d82002-05-28 01:36:45 +0000558 ensure_valgrind("pthread_create");
559
560 /* Allocate space for the arg block. thread_wrapper will free
561 it. */
562 VALGRIND_MAGIC_SEQUENCE(info, NULL /* default */,
563 VG_USERREQ__MALLOC,
564 sizeof(NewThreadInfo), 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000565 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000566
sewardj728a5272002-06-20 10:25:37 +0000567 if (__attr)
568 info->attr__detachstate = __attr->__detachstate;
569 else
570 info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
571
sewardj20917d82002-05-28 01:36:45 +0000572 info->root_fn = __start_routine;
573 info->arg = __arg;
574 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
575 VG_USERREQ__APPLY_IN_NEW_THREAD,
576 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000577 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000578
579 if (__thread)
580 *__thread = tid_child;
581 return 0; /* success */
582}
sewardje663cb92002-04-12 10:26:32 +0000583
584
585int
586pthread_join (pthread_t __th, void **__thread_return)
587{
588 int res;
589 ensure_valgrind("pthread_join");
590 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
591 VG_USERREQ__PTHREAD_JOIN,
592 __th, __thread_return, 0, 0);
593 return res;
594}
595
596
sewardj3b5d8862002-04-20 13:53:23 +0000597void pthread_exit(void *retval)
598{
sewardj3b5d8862002-04-20 13:53:23 +0000599 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000600 /* Simple! */
601 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000602}
603
sewardje663cb92002-04-12 10:26:32 +0000604
sewardj3b13f0e2002-04-25 20:17:29 +0000605pthread_t pthread_self(void)
sewardje663cb92002-04-12 10:26:32 +0000606{
607 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000608 ensure_valgrind("pthread_self");
sewardj439d45e2002-05-03 20:43:10 +0000609 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardje663cb92002-04-12 10:26:32 +0000610 VG_USERREQ__PTHREAD_GET_THREADID,
611 0, 0, 0, 0);
sewardj439d45e2002-05-03 20:43:10 +0000612 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000613 barf("pthread_self: invalid ThreadId");
614 return tid;
sewardje663cb92002-04-12 10:26:32 +0000615}
616
617
sewardj853f55d2002-04-26 00:27:53 +0000618int pthread_detach(pthread_t th)
619{
sewardj20917d82002-05-28 01:36:45 +0000620 int res;
621 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000622 /* First we enquire as to the current detach state. */
623 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000624 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000625 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000626 if (res == -1) {
627 /* not found */
628 pthread_error("pthread_detach: "
629 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000630 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000631 }
632 if (res == 1) {
633 /* already detached */
634 pthread_error("pthread_detach: "
635 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000636 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000637 }
sewardj7989d0c2002-05-28 11:00:01 +0000638 if (res == 0) {
639 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
640 VG_USERREQ__SET_OR_GET_DETACH,
641 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000642 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000643 return 0;
644 }
645 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000646}
647
648
sewardjf8f819e2002-04-17 23:21:37 +0000649/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000650 CLEANUP STACKS
651 ------------------------------------------------ */
652
653void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
654 void (*__routine) (void *),
655 void *__arg)
656{
657 int res;
658 CleanupEntry cu;
659 ensure_valgrind("_pthread_cleanup_push");
660 cu.fn = __routine;
661 cu.arg = __arg;
662 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
663 VG_USERREQ__CLEANUP_PUSH,
664 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000665 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000666}
667
668
669void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
670 void (*__routine) (void *),
671 void *__arg)
672{
673 /* As _pthread_cleanup_push, but first save the thread's original
674 cancellation type in __buffer and set it to Deferred. */
675 int orig_ctype;
676 ensure_valgrind("_pthread_cleanup_push_defer");
677 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000678 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
679 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
680 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000681 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
682 VG_USERREQ__SET_CANCELTYPE,
683 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000684 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000685 *((int*)(__buffer)) = orig_ctype;
686 /* Now push the cleanup. */
687 _pthread_cleanup_push(NULL, __routine, __arg);
688}
689
690
691void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
692 int __execute)
693{
694 int res;
695 CleanupEntry cu;
696 ensure_valgrind("_pthread_cleanup_push");
697 cu.fn = cu.arg = NULL; /* paranoia */
698 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
699 VG_USERREQ__CLEANUP_POP,
700 &cu, 0, 0, 0);
701 if (res == 0) {
702 /* pop succeeded */
703 if (__execute) {
704 cu.fn ( cu.arg );
705 }
706 return;
707 }
708 if (res == -1) {
709 /* stack underflow */
710 return;
711 }
712 barf("_pthread_cleanup_pop");
713}
714
715
716void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
717 int __execute)
718{
719 int orig_ctype, fake_ctype;
720 /* As _pthread_cleanup_pop, but after popping/running the handler,
721 restore the thread's original cancellation type from the first
722 word of __buffer. */
723 _pthread_cleanup_pop(NULL, __execute);
724 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000725 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000726 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000727 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
728 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
729 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000730 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
731 VG_USERREQ__SET_CANCELTYPE,
732 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000733 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000734}
735
736
737/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000738 MUTEX ATTRIBUTES
739 ------------------------------------------------ */
740
sewardj5905fae2002-04-26 13:25:00 +0000741int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000742{
sewardjf8f819e2002-04-17 23:21:37 +0000743 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000744 return 0;
sewardje663cb92002-04-12 10:26:32 +0000745}
746
sewardj5905fae2002-04-26 13:25:00 +0000747int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000748{
749 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000750# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000751 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000752 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000753# endif
sewardja1679dd2002-05-10 22:31:40 +0000754# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000755 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000756# endif
sewardjf8f819e2002-04-17 23:21:37 +0000757 case PTHREAD_MUTEX_RECURSIVE_NP:
758 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000759 attr->__mutexkind = type;
760 return 0;
761 default:
sewardj4dced352002-06-04 22:54:20 +0000762 pthread_error("pthread_mutexattr_settype: "
763 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000764 return EINVAL;
765 }
766}
767
sewardj5905fae2002-04-26 13:25:00 +0000768int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000769{
770 return 0;
771}
772
773
774/* ---------------------------------------------------
775 MUTEXes
776 ------------------------------------------------ */
777
sewardj5905fae2002-04-26 13:25:00 +0000778int __pthread_mutex_init(pthread_mutex_t *mutex,
779 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000780{
sewardj604ec3c2002-04-18 22:38:41 +0000781 mutex->__m_count = 0;
782 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
783 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
784 if (mutexattr)
785 mutex->__m_kind = mutexattr->__mutexkind;
786 return 0;
sewardje663cb92002-04-12 10:26:32 +0000787}
788
sewardj439d45e2002-05-03 20:43:10 +0000789
sewardj5905fae2002-04-26 13:25:00 +0000790int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000791{
792 int res;
sewardj436e0582002-04-26 14:31:40 +0000793 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000794 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000795 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
796 VG_USERREQ__PTHREAD_MUTEX_LOCK,
797 mutex, 0, 0, 0);
798 return res;
sewardj439d45e2002-05-03 20:43:10 +0000799 } else {
800 if (moans-- > 0)
801 not_inside("pthread_mutex_lock");
802 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000803 }
804}
805
sewardj439d45e2002-05-03 20:43:10 +0000806
sewardj5905fae2002-04-26 13:25:00 +0000807int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000808{
809 int res;
sewardj436e0582002-04-26 14:31:40 +0000810 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000811 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000812 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
813 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
814 mutex, 0, 0, 0);
815 return res;
sewardj439d45e2002-05-03 20:43:10 +0000816 } else {
817 if (moans-- > 0)
818 not_inside("pthread_mutex_trylock");
819 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000820 }
821}
822
sewardj439d45e2002-05-03 20:43:10 +0000823
sewardj5905fae2002-04-26 13:25:00 +0000824int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000825{
826 int res;
sewardj436e0582002-04-26 14:31:40 +0000827 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000828 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000829 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
830 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
831 mutex, 0, 0, 0);
832 return res;
sewardj439d45e2002-05-03 20:43:10 +0000833 } else {
834 if (moans-- > 0)
835 not_inside("pthread_mutex_unlock");
836 return 0;
sewardje663cb92002-04-12 10:26:32 +0000837 }
838}
839
sewardj439d45e2002-05-03 20:43:10 +0000840
sewardj5905fae2002-04-26 13:25:00 +0000841int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000842{
sewardj604ec3c2002-04-18 22:38:41 +0000843 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
844 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +0000845 if (mutex->__m_count > 0) {
846 pthread_error("pthread_mutex_destroy: "
847 "mutex is still in use");
sewardj604ec3c2002-04-18 22:38:41 +0000848 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +0000849 }
850 mutex->__m_count = 0;
851 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
852 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
853 return 0;
sewardje663cb92002-04-12 10:26:32 +0000854}
855
856
sewardjf8f819e2002-04-17 23:21:37 +0000857/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000858 CONDITION VARIABLES
859 ------------------------------------------------ */
860
861/* LinuxThreads supports no attributes for conditions. Hence ... */
862
863int pthread_condattr_init(pthread_condattr_t *attr)
864{
865 return 0;
866}
867
sewardj0738a592002-04-20 13:59:33 +0000868int pthread_condattr_destroy(pthread_condattr_t *attr)
869{
870 return 0;
871}
sewardj6072c362002-04-19 14:40:57 +0000872
873int pthread_cond_init( pthread_cond_t *cond,
874 const pthread_condattr_t *cond_attr)
875{
876 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
877 return 0;
878}
879
sewardjf854f472002-04-21 12:19:41 +0000880int pthread_cond_destroy(pthread_cond_t *cond)
881{
882 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000883 static int moans = N_MOANS;
884 if (moans-- > 0)
885 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000886 return 0;
887}
sewardj6072c362002-04-19 14:40:57 +0000888
889/* ---------------------------------------------------
890 SCHEDULING
891 ------------------------------------------------ */
892
893/* This is completely bogus. */
894int pthread_getschedparam(pthread_t target_thread,
895 int *policy,
896 struct sched_param *param)
897{
sewardj436e0582002-04-26 14:31:40 +0000898 static int moans = N_MOANS;
899 if (moans-- > 0)
900 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000901 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +0000902# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +0000903 if (param) param->sched_priority = 0; /* who knows */
904# else
sewardj6072c362002-04-19 14:40:57 +0000905 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000906# endif
sewardj6072c362002-04-19 14:40:57 +0000907 return 0;
908}
909
910int pthread_setschedparam(pthread_t target_thread,
911 int policy,
912 const struct sched_param *param)
913{
sewardj436e0582002-04-26 14:31:40 +0000914 static int moans = N_MOANS;
915 if (moans-- > 0)
916 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000917 return 0;
918}
919
sewardj3b5d8862002-04-20 13:53:23 +0000920int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
921{
922 int res;
923 ensure_valgrind("pthread_cond_wait");
924 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
925 VG_USERREQ__PTHREAD_COND_WAIT,
926 cond, mutex, 0, 0);
927 return res;
928}
929
sewardj5f07b662002-04-23 16:52:51 +0000930int pthread_cond_timedwait ( pthread_cond_t *cond,
931 pthread_mutex_t *mutex,
932 const struct timespec *abstime )
933{
934 int res;
935 unsigned int ms_now, ms_end;
936 struct timeval timeval_now;
937 unsigned long long int ull_ms_now_after_1970;
938 unsigned long long int ull_ms_end_after_1970;
939
940 ensure_valgrind("pthread_cond_timedwait");
941 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
942 VG_USERREQ__READ_MILLISECOND_TIMER,
943 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000944 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +0000945 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +0000946 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +0000947
948 ull_ms_now_after_1970
949 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
950 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
951 ull_ms_end_after_1970
952 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
953 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +0000954 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
955 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +0000956 ms_end
957 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
958 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
959 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
960 cond, mutex, ms_end, 0);
961 return res;
962}
963
964
sewardj3b5d8862002-04-20 13:53:23 +0000965int pthread_cond_signal(pthread_cond_t *cond)
966{
967 int res;
968 ensure_valgrind("pthread_cond_signal");
969 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
970 VG_USERREQ__PTHREAD_COND_SIGNAL,
971 cond, 0, 0, 0);
972 return res;
973}
974
975int pthread_cond_broadcast(pthread_cond_t *cond)
976{
977 int res;
978 ensure_valgrind("pthread_cond_broadcast");
979 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
980 VG_USERREQ__PTHREAD_COND_BROADCAST,
981 cond, 0, 0, 0);
982 return res;
983}
984
sewardj6072c362002-04-19 14:40:57 +0000985
986/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000987 CANCELLATION
988 ------------------------------------------------ */
989
sewardj853f55d2002-04-26 00:27:53 +0000990int pthread_setcancelstate(int state, int *oldstate)
991{
sewardj20917d82002-05-28 01:36:45 +0000992 int res;
993 ensure_valgrind("pthread_setcancelstate");
994 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +0000995 && state != PTHREAD_CANCEL_DISABLE) {
996 pthread_error("pthread_setcancelstate: "
997 "invalid state");
sewardj20917d82002-05-28 01:36:45 +0000998 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000999 }
sewardj2d94c112002-06-03 01:25:54 +00001000 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1001 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001002 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1003 VG_USERREQ__SET_CANCELSTATE,
1004 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001005 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001006 if (oldstate)
1007 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001008 return 0;
1009}
1010
sewardje663cb92002-04-12 10:26:32 +00001011int pthread_setcanceltype(int type, int *oldtype)
1012{
sewardj20917d82002-05-28 01:36:45 +00001013 int res;
1014 ensure_valgrind("pthread_setcanceltype");
1015 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001016 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1017 pthread_error("pthread_setcanceltype: "
1018 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001019 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001020 }
sewardj2d94c112002-06-03 01:25:54 +00001021 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1022 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001023 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1024 VG_USERREQ__SET_CANCELTYPE,
1025 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001026 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001027 if (oldtype)
1028 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001029 return 0;
1030}
1031
sewardje663cb92002-04-12 10:26:32 +00001032int pthread_cancel(pthread_t thread)
1033{
1034 int res;
1035 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001036 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1037 VG_USERREQ__SET_CANCELPEND,
1038 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001039 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001040 return res;
1041}
1042
sewardjd140e442002-05-29 01:21:19 +00001043static __inline__
1044void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001045{
sewardj20917d82002-05-28 01:36:45 +00001046 int res;
1047 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1048 VG_USERREQ__TESTCANCEL,
1049 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001050 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001051}
1052
sewardjd140e442002-05-29 01:21:19 +00001053void pthread_testcancel ( void )
1054{
1055 __my_pthread_testcancel();
1056}
1057
sewardj20917d82002-05-28 01:36:45 +00001058
sewardjef037c72002-05-30 00:40:03 +00001059/* Not really sure what this is for. I suspect for doing the POSIX
1060 requirements for fork() and exec(). We do this internally anyway
1061 whenever those syscalls are observed, so this could be superfluous,
1062 but hey ...
1063*/
sewardj853f55d2002-04-26 00:27:53 +00001064void __pthread_kill_other_threads_np ( void )
1065{
sewardjef037c72002-05-30 00:40:03 +00001066 int res;
1067 ensure_valgrind("__pthread_kill_other_threads_np");
1068 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1069 VG_USERREQ__NUKE_OTHER_THREADS,
1070 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001071 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001072}
1073
sewardje663cb92002-04-12 10:26:32 +00001074
sewardjf8f819e2002-04-17 23:21:37 +00001075/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001076 SIGNALS
1077 ------------------------------------------------ */
1078
1079#include <signal.h>
1080
1081int pthread_sigmask(int how, const sigset_t *newmask,
1082 sigset_t *oldmask)
1083{
1084 int res;
1085
1086 /* A bit subtle, because the scheduler expects newmask and oldmask
1087 to be vki_sigset_t* rather than sigset_t*, and the two are
1088 different. Fortunately the first 64 bits of a sigset_t are
1089 exactly a vki_sigset_t, so we just pass the pointers through
1090 unmodified. Haaaack!
1091
1092 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001093 constants to VKI_ constants, so that the former do not have to
1094 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001095
1096 ensure_valgrind("pthread_sigmask");
1097
1098 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001099 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1100 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1101 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001102 default: pthread_error("pthread_sigmask: invalid how");
1103 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001104 }
1105
1106 /* Crude check */
1107 if (newmask == NULL)
1108 return EFAULT;
1109
1110 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1111 VG_USERREQ__PTHREAD_SIGMASK,
1112 how, newmask, oldmask, 0);
1113
1114 /* The scheduler tells us of any memory violations. */
1115 return res == 0 ? 0 : EFAULT;
1116}
1117
1118
1119int sigwait ( const sigset_t* set, int* sig )
1120{
1121 int res;
1122 ensure_valgrind("sigwait");
1123 /* As with pthread_sigmask we deliberately confuse sigset_t with
1124 vki_ksigset_t. */
1125 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1126 VG_USERREQ__SIGWAIT,
1127 set, sig, 0, 0);
1128 return res;
1129}
1130
1131
sewardj018f7622002-05-15 21:13:39 +00001132int pthread_kill(pthread_t thread, int signo)
1133{
1134 int res;
1135 ensure_valgrind("pthread_kill");
1136 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1137 VG_USERREQ__PTHREAD_KILL,
1138 thread, signo, 0, 0);
1139 return res;
1140}
1141
1142
sewardj3665ded2002-05-16 16:57:25 +00001143/* Copied verbatim from Linuxthreads */
1144/* Redefine raise() to send signal to calling thread only,
1145 as per POSIX 1003.1c */
1146int raise (int sig)
1147{
1148 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001149 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001150 return 0;
sewardj4dced352002-06-04 22:54:20 +00001151 } else {
sewardj3665ded2002-05-16 16:57:25 +00001152 errno = retcode;
1153 return -1;
1154 }
1155}
1156
1157
sewardj9a2224b2002-06-19 10:17:40 +00001158int pause ( void )
1159{
1160 unsigned int n_orig, n_now;
1161 struct vki_timespec nanosleep_interval;
1162 ensure_valgrind("pause");
1163
1164 /* This is surely a cancellation point. */
1165 __my_pthread_testcancel();
1166
1167 VALGRIND_MAGIC_SEQUENCE(n_orig, 0xFFFFFFFF /* default */,
1168 VG_USERREQ__GET_N_SIGS_RETURNED,
1169 0, 0, 0, 0);
1170 my_assert(n_orig != 0xFFFFFFFF);
1171
1172 while (1) {
1173 VALGRIND_MAGIC_SEQUENCE(n_now, 0xFFFFFFFF /* default */,
1174 VG_USERREQ__GET_N_SIGS_RETURNED,
1175 0, 0, 0, 0);
1176 my_assert(n_now != 0xFFFFFFFF);
1177 my_assert(n_now >= n_orig);
1178 if (n_now != n_orig) break;
1179
1180 nanosleep_interval.tv_sec = 0;
1181 nanosleep_interval.tv_nsec = 52 * 1000 * 1000; /* 52 milliseconds */
1182 /* It's critical here that valgrind's nanosleep implementation
1183 is nonblocking. */
1184 (void)my_do_syscall2(__NR_nanosleep,
1185 (int)(&nanosleep_interval), (int)NULL);
1186 }
1187
1188 * (__errno_location()) = EINTR;
1189 return -1;
1190}
1191
1192
sewardjb48e5002002-05-13 00:16:03 +00001193/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001194 THREAD-SPECIFICs
1195 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001196
sewardj5905fae2002-04-26 13:25:00 +00001197int __pthread_key_create(pthread_key_t *key,
1198 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001199{
sewardj5f07b662002-04-23 16:52:51 +00001200 int res;
1201 ensure_valgrind("pthread_key_create");
1202 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1203 VG_USERREQ__PTHREAD_KEY_CREATE,
1204 key, destr_function, 0, 0);
1205 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001206}
1207
1208int pthread_key_delete(pthread_key_t key)
1209{
sewardj436e0582002-04-26 14:31:40 +00001210 static int moans = N_MOANS;
1211 if (moans-- > 0)
1212 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +00001213 return 0;
1214}
1215
sewardj5905fae2002-04-26 13:25:00 +00001216int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001217{
sewardj5f07b662002-04-23 16:52:51 +00001218 int res;
1219 ensure_valgrind("pthread_setspecific");
1220 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1221 VG_USERREQ__PTHREAD_SETSPECIFIC,
1222 key, pointer, 0, 0);
1223 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001224}
1225
sewardj5905fae2002-04-26 13:25:00 +00001226void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001227{
sewardj5f07b662002-04-23 16:52:51 +00001228 int res;
1229 ensure_valgrind("pthread_getspecific");
1230 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1231 VG_USERREQ__PTHREAD_GETSPECIFIC,
1232 key, 0 , 0, 0);
1233 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001234}
1235
sewardjf8f819e2002-04-17 23:21:37 +00001236
1237/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001238 ONCEry
1239 ------------------------------------------------ */
1240
1241static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1242
1243
sewardj5905fae2002-04-26 13:25:00 +00001244int __pthread_once ( pthread_once_t *once_control,
1245 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001246{
1247 int res;
1248 ensure_valgrind("pthread_once");
1249
sewardj68b2dd92002-05-10 21:03:56 +00001250 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001251
sewardj68b2dd92002-05-10 21:03:56 +00001252 if (res != 0) {
sewardj89d3d852002-04-24 19:21:39 +00001253 barf("pthread_once: Looks like your program's "
1254 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001255 }
sewardj89d3d852002-04-24 19:21:39 +00001256
1257 if (*once_control == 0) {
1258 *once_control = 1;
1259 init_routine();
1260 }
1261
sewardj68b2dd92002-05-10 21:03:56 +00001262 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001263
1264 return 0;
1265}
1266
1267
1268/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001269 MISC
1270 ------------------------------------------------ */
1271
sewardj2cb00342002-06-28 01:46:26 +00001272static pthread_mutex_t pthread_atfork_lock
1273 = PTHREAD_MUTEX_INITIALIZER;
1274
sewardj5905fae2002-04-26 13:25:00 +00001275int __pthread_atfork ( void (*prepare)(void),
1276 void (*parent)(void),
1277 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001278{
sewardj2cb00342002-06-28 01:46:26 +00001279 int n, res;
1280 ForkHandlerEntry entry;
1281
1282 ensure_valgrind("pthread_atfork");
1283 __pthread_mutex_lock(&pthread_atfork_lock);
1284
1285 /* Fetch old counter */
1286 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1287 VG_USERREQ__GET_FHSTACK_USED,
1288 0, 0, 0, 0);
1289 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1290 if (n == VG_N_FORKHANDLERSTACK-1)
1291 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1292 "increase and recompile");
1293
1294 /* Add entry */
1295 entry.prepare = *prepare;
1296 entry.parent = *parent;
1297 entry.child = *child;
1298 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1299 VG_USERREQ__SET_FHSTACK_ENTRY,
1300 n, &entry, 0, 0);
1301 my_assert(res == 0);
1302
1303 /* Bump counter */
1304 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1305 VG_USERREQ__SET_FHSTACK_USED,
1306 n+1, 0, 0, 0);
1307 my_assert(res == 0);
1308
1309 __pthread_mutex_unlock(&pthread_atfork_lock);
1310 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001311}
1312
1313
sewardjbb990782002-05-08 02:01:14 +00001314__attribute__((weak))
1315void __pthread_initialize ( void )
1316{
sewardjbea1caa2002-05-10 23:20:58 +00001317 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001318}
1319
1320
sewardj853f55d2002-04-26 00:27:53 +00001321/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001322 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001323 ------------------------------------------------ */
1324
sewardj3b13f0e2002-04-25 20:17:29 +00001325#include <resolv.h>
1326static int thread_specific_errno[VG_N_THREADS];
1327static int thread_specific_h_errno[VG_N_THREADS];
1328static struct __res_state
1329 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001330
sewardj3b13f0e2002-04-25 20:17:29 +00001331int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001332{
1333 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001334 /* ensure_valgrind("__errno_location"); */
1335 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001336 VG_USERREQ__PTHREAD_GET_THREADID,
1337 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001338 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001339 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001340 barf("__errno_location: invalid ThreadId");
1341 return & thread_specific_errno[tid];
1342}
1343
1344int* __h_errno_location ( void )
1345{
1346 int tid;
1347 /* ensure_valgrind("__h_errno_location"); */
1348 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1349 VG_USERREQ__PTHREAD_GET_THREADID,
1350 0, 0, 0, 0);
1351 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001352 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001353 barf("__h_errno_location: invalid ThreadId");
1354 return & thread_specific_h_errno[tid];
1355}
1356
1357struct __res_state* __res_state ( void )
1358{
1359 int tid;
1360 /* ensure_valgrind("__res_state"); */
1361 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1362 VG_USERREQ__PTHREAD_GET_THREADID,
1363 0, 0, 0, 0);
1364 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001365 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001366 barf("__res_state: invalid ThreadId");
1367 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001368}
1369
1370
sewardj5716dbb2002-04-26 03:28:18 +00001371/* ---------------------------------------------------
1372 LIBC-PRIVATE SPECIFIC DATA
1373 ------------------------------------------------ */
1374
1375/* Relies on assumption that initial private data is NULL. This
1376 should be fixed somehow. */
1377
1378/* The allowable keys (indices) (all 2 of them).
1379 From sysdeps/pthread/bits/libc-tsd.h
1380*/
sewardj70adeb22002-04-27 01:35:38 +00001381#define N_LIBC_TSD_EXTRA_KEYS 1
1382
sewardj5716dbb2002-04-26 03:28:18 +00001383enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1384 _LIBC_TSD_KEY_DL_ERROR,
1385 _LIBC_TSD_KEY_N };
1386
1387/* Auto-initialising subsystem. libc_specifics_inited is set
1388 after initialisation. libc_specifics_inited_mx guards it. */
1389static int libc_specifics_inited = 0;
1390static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1391
1392/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001393static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1394 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001395
1396/* Initialise the keys, if they are not already initialise. */
1397static
1398void init_libc_tsd_keys ( void )
1399{
1400 int res, i;
1401 pthread_key_t k;
1402
1403 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1404 if (res != 0) barf("init_libc_tsd_keys: lock");
1405
1406 if (libc_specifics_inited == 0) {
1407 /* printf("INIT libc specifics\n"); */
1408 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001409 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001410 res = pthread_key_create(&k, NULL);
1411 if (res != 0) barf("init_libc_tsd_keys: create");
1412 libc_specifics_keys[i] = k;
1413 }
1414 }
1415
1416 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1417 if (res != 0) barf("init_libc_tsd_keys: unlock");
1418}
1419
1420
1421static int
1422libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1423 const void * pointer )
1424{
sewardj70adeb22002-04-27 01:35:38 +00001425 int res;
1426 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001427 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001428 if (key < _LIBC_TSD_KEY_MALLOC
1429 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001430 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001431 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1432 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001433 "valgrind's libpthread.so: libc_internal_tsd_set: "
1434 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001435 init_libc_tsd_keys();
1436 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1437 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1438 return 0;
1439}
1440
1441static void *
1442libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1443{
sewardj70adeb22002-04-27 01:35:38 +00001444 void* v;
1445 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001446 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001447 if (key < _LIBC_TSD_KEY_MALLOC
1448 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001449 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001450 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1451 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001452 "valgrind's libpthread.so: libc_internal_tsd_get: "
1453 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001454 init_libc_tsd_keys();
1455 v = pthread_getspecific(libc_specifics_keys[key]);
1456 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1457 return v;
1458}
1459
1460
1461
1462
sewardj70adeb22002-04-27 01:35:38 +00001463int (*__libc_internal_tsd_set)
1464 (enum __libc_tsd_key_t key, const void * pointer)
1465 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001466
sewardj70adeb22002-04-27 01:35:38 +00001467void* (*__libc_internal_tsd_get)
1468 (enum __libc_tsd_key_t key)
1469 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001470
1471
sewardje663cb92002-04-12 10:26:32 +00001472/* ---------------------------------------------------------------------
1473 These are here (I think) because they are deemed cancellation
1474 points by POSIX. For the moment we'll simply pass the call along
1475 to the corresponding thread-unaware (?) libc routine.
1476 ------------------------------------------------------------------ */
1477
sewardje663cb92002-04-12 10:26:32 +00001478#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001479#include <sys/types.h>
1480#include <sys/socket.h>
1481
sewardjd529a442002-05-04 19:49:21 +00001482#ifdef GLIBC_2_1
1483extern
1484int __sigaction
1485 (int signum,
1486 const struct sigaction *act,
1487 struct sigaction *oldact);
1488#else
sewardje663cb92002-04-12 10:26:32 +00001489extern
1490int __libc_sigaction
1491 (int signum,
1492 const struct sigaction *act,
1493 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001494#endif
sewardje663cb92002-04-12 10:26:32 +00001495int sigaction(int signum,
1496 const struct sigaction *act,
1497 struct sigaction *oldact)
1498{
sewardjd140e442002-05-29 01:21:19 +00001499 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001500# ifdef GLIBC_2_1
1501 return __sigaction(signum, act, oldact);
1502# else
sewardj45b4b372002-04-16 22:50:32 +00001503 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001504# endif
sewardje663cb92002-04-12 10:26:32 +00001505}
1506
1507
1508extern
1509int __libc_connect(int sockfd,
1510 const struct sockaddr *serv_addr,
1511 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001512__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001513int connect(int sockfd,
1514 const struct sockaddr *serv_addr,
1515 socklen_t addrlen)
1516{
sewardjd140e442002-05-29 01:21:19 +00001517 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001518 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001519}
1520
1521
1522extern
1523int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001524__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001525int fcntl(int fd, int cmd, long arg)
1526{
sewardjd140e442002-05-29 01:21:19 +00001527 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001528 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001529}
1530
1531
1532extern
1533ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001534__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001535ssize_t write(int fd, const void *buf, size_t count)
1536{
sewardjd140e442002-05-29 01:21:19 +00001537 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001538 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001539}
1540
1541
1542extern
1543ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001544__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001545ssize_t read(int fd, void *buf, size_t count)
1546{
sewardjd140e442002-05-29 01:21:19 +00001547 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001548 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001549}
1550
sewardjbe32e452002-04-24 20:29:58 +00001551
1552extern
sewardj853f55d2002-04-26 00:27:53 +00001553int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001554__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001555int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001556{
sewardjd140e442002-05-29 01:21:19 +00001557 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001558 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001559}
1560
sewardje663cb92002-04-12 10:26:32 +00001561
1562extern
sewardj853f55d2002-04-26 00:27:53 +00001563int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001564__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001565int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001566{
sewardjd140e442002-05-29 01:21:19 +00001567 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001568 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001569}
1570
1571
1572extern
1573int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001574__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001575int close(int fd)
1576{
sewardjd140e442002-05-29 01:21:19 +00001577 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001578 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001579}
1580
1581
1582extern
1583int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001584__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001585int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1586{
sewardjd140e442002-05-29 01:21:19 +00001587 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001588 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001589 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001590 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001591}
1592
1593
1594extern
sewardje663cb92002-04-12 10:26:32 +00001595pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001596__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001597pid_t waitpid(pid_t pid, int *status, int options)
1598{
sewardjd140e442002-05-29 01:21:19 +00001599 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001600 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001601}
1602
1603
1604extern
1605int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001606__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001607int nanosleep(const struct timespec *req, struct timespec *rem)
1608{
sewardjd140e442002-05-29 01:21:19 +00001609 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001610 return __libc_nanosleep(req, rem);
1611}
1612
sewardjbe32e452002-04-24 20:29:58 +00001613
sewardje663cb92002-04-12 10:26:32 +00001614extern
1615int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001616__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001617int fsync(int fd)
1618{
sewardjd140e442002-05-29 01:21:19 +00001619 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001620 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001621}
1622
sewardjbe32e452002-04-24 20:29:58 +00001623
sewardj70c75362002-04-13 04:18:32 +00001624extern
1625off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001626__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001627off_t lseek(int fildes, off_t offset, int whence)
1628{
sewardjd140e442002-05-29 01:21:19 +00001629 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001630 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001631}
1632
sewardjbe32e452002-04-24 20:29:58 +00001633
1634extern
1635__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001636__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001637__off64_t lseek64(int fildes, __off64_t offset, int whence)
1638{
sewardjd140e442002-05-29 01:21:19 +00001639 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001640 return __libc_lseek64(fildes, offset, whence);
1641}
1642
1643
sewardj726c4122002-05-16 23:39:10 +00001644extern
1645ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1646 __off64_t __offset);
1647ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1648 __off64_t __offset)
1649{
sewardjd140e442002-05-29 01:21:19 +00001650 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001651 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1652}
1653
1654
sewardja18e2102002-05-18 10:43:22 +00001655extern
1656ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1657 __off64_t __offset);
1658ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1659 __off64_t __offset)
1660{
sewardjd140e442002-05-29 01:21:19 +00001661 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001662 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1663}
1664
sewardj726c4122002-05-16 23:39:10 +00001665
sewardj39b93b12002-05-18 10:56:27 +00001666extern
1667ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1668__attribute__((weak))
1669ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1670{
sewardjd140e442002-05-29 01:21:19 +00001671 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001672 return __libc_pwrite(fd, buf, count, offset);
1673}
1674
1675
1676extern
1677ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1678__attribute__((weak))
1679ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1680{
sewardjd140e442002-05-29 01:21:19 +00001681 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001682 return __libc_pread(fd, buf, count, offset);
1683}
1684
1685
sewardj6af4b5d2002-04-16 04:40:49 +00001686extern
1687void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001688/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001689void longjmp(jmp_buf env, int val)
1690{
1691 __libc_longjmp(env, val);
1692}
1693
sewardjbe32e452002-04-24 20:29:58 +00001694
sewardj436c2db2002-06-18 09:07:54 +00001695extern void __libc_siglongjmp (sigjmp_buf env, int val)
1696 __attribute__ ((noreturn));
1697void siglongjmp(sigjmp_buf env, int val)
1698{
1699 kludged("siglongjmp (cleanup handlers are ignored)");
1700 __libc_siglongjmp(env, val);
1701}
1702
1703
sewardj6af4b5d2002-04-16 04:40:49 +00001704extern
1705int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001706__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001707int send(int s, const void *msg, size_t len, int flags)
1708{
sewardjd140e442002-05-29 01:21:19 +00001709 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001710 return __libc_send(s, msg, len, flags);
1711}
1712
sewardjbe32e452002-04-24 20:29:58 +00001713
sewardj1e8cdc92002-04-18 11:37:52 +00001714extern
1715int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001716__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001717int recv(int s, void *buf, size_t len, int flags)
1718{
sewardjd140e442002-05-29 01:21:19 +00001719 __my_pthread_testcancel();
sewardj1d6b3a22002-06-20 07:58:33 +00001720 wait_for_fd_to_be_readable_or_erring(s);
1721 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001722 return __libc_recv(s, buf, len, flags);
1723}
1724
sewardjbe32e452002-04-24 20:29:58 +00001725
sewardj3665ded2002-05-16 16:57:25 +00001726extern
1727int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1728__attribute__((weak))
1729int sendmsg(int s, const struct msghdr *msg, int flags)
1730{
sewardjd140e442002-05-29 01:21:19 +00001731 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001732 return __libc_sendmsg(s, msg, flags);
1733}
1734
1735
sewardj796d6a22002-04-24 02:28:34 +00001736extern
sewardj59da27a2002-06-06 08:33:54 +00001737int __libc_recvmsg(int s, struct msghdr *msg, int flags);
1738__attribute__((weak))
1739int recvmsg(int s, struct msghdr *msg, int flags)
1740{
1741 __my_pthread_testcancel();
1742 return __libc_recvmsg(s, msg, flags);
1743}
1744
1745
1746extern
sewardj436e0582002-04-26 14:31:40 +00001747int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1748 struct sockaddr *from, socklen_t *fromlen);
1749__attribute__((weak))
1750int recvfrom(int s, void *buf, size_t len, int flags,
1751 struct sockaddr *from, socklen_t *fromlen)
1752{
sewardjd140e442002-05-29 01:21:19 +00001753 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00001754 wait_for_fd_to_be_readable_or_erring(s);
1755 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001756 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1757}
1758
1759
1760extern
sewardj796d6a22002-04-24 02:28:34 +00001761int __libc_sendto(int s, const void *msg, size_t len, int flags,
1762 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001763__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001764int sendto(int s, const void *msg, size_t len, int flags,
1765 const struct sockaddr *to, socklen_t tolen)
1766{
sewardjd140e442002-05-29 01:21:19 +00001767 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001768 return __libc_sendto(s, msg, len, flags, to, tolen);
1769}
1770
sewardjbe32e452002-04-24 20:29:58 +00001771
sewardj369b1702002-04-24 13:28:15 +00001772extern
1773int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001774__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001775int system(const char* str)
1776{
sewardjd140e442002-05-29 01:21:19 +00001777 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001778 return __libc_system(str);
1779}
1780
sewardjbe32e452002-04-24 20:29:58 +00001781
sewardjab0b1c32002-04-24 19:26:47 +00001782extern
1783pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001784__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001785pid_t wait(int *status)
1786{
sewardjd140e442002-05-29 01:21:19 +00001787 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00001788 return __libc_wait(status);
1789}
1790
sewardj45b4b372002-04-16 22:50:32 +00001791
sewardj67f1d582002-05-24 02:11:32 +00001792extern
1793int __libc_msync(const void *start, size_t length, int flags);
1794__attribute__((weak))
1795int msync(const void *start, size_t length, int flags)
1796{
sewardjd140e442002-05-29 01:21:19 +00001797 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00001798 return __libc_msync(start, length, flags);
1799}
1800
sewardj5905fae2002-04-26 13:25:00 +00001801
sewardj2cb00342002-06-28 01:46:26 +00001802/*--- fork and its helper ---*/
1803
1804static
1805void run_fork_handlers ( int what )
1806{
1807 ForkHandlerEntry entry;
1808 int n_h, n_handlers, i, res;
1809
1810 my_assert(what == 0 || what == 1 || what == 2);
1811
1812 /* Fetch old counter */
1813 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
1814 VG_USERREQ__GET_FHSTACK_USED,
1815 0, 0, 0, 0);
1816 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
1817
1818 /* Prepare handlers (what == 0) are called in opposite order of
1819 calls to pthread_atfork. Parent and child handlers are called
1820 in the same order as calls to pthread_atfork. */
1821 if (what == 0)
1822 n_h = n_handlers - 1;
1823 else
1824 n_h = 0;
1825
1826 for (i = 0; i < n_handlers; i++) {
1827 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1828 VG_USERREQ__GET_FHSTACK_ENTRY,
1829 n_h, &entry, 0, 0);
1830 my_assert(res == 0);
1831 switch (what) {
1832 case 0: if (entry.prepare) entry.prepare();
1833 n_h--; break;
1834 case 1: if (entry.parent) entry.parent();
1835 n_h++; break;
1836 case 2: if (entry.child) entry.child();
1837 n_h++; break;
1838 default: barf("run_fork_handlers: invalid what");
1839 }
1840 }
1841
1842 if (what != 0 /* prepare */) {
1843 /* Empty out the stack. */
1844 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1845 VG_USERREQ__SET_FHSTACK_USED,
1846 0, 0, 0, 0);
1847 my_assert(res == 0);
1848 }
1849}
1850
1851extern
1852pid_t __libc_fork(void);
1853pid_t __fork(void)
1854{
1855 pid_t pid;
1856 __my_pthread_testcancel();
1857 __pthread_mutex_lock(&pthread_atfork_lock);
1858
1859 run_fork_handlers(0 /* prepare */);
1860 pid = __libc_fork();
1861 if (pid == 0) {
1862 /* I am the child */
1863 run_fork_handlers(2 /* child */);
1864 __pthread_mutex_init(&pthread_atfork_lock, NULL);
1865 } else {
1866 /* I am the parent */
1867 run_fork_handlers(1 /* parent */);
1868 __pthread_mutex_unlock(&pthread_atfork_lock);
1869 }
1870 return pid;
1871}
1872
1873
1874
1875
sewardj3b13f0e2002-04-25 20:17:29 +00001876/* ---------------------------------------------------------------------
1877 Nonblocking implementations of select() and poll(). This stuff will
1878 surely rot your mind.
1879 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001880
sewardj08a4c3f2002-04-13 03:45:44 +00001881/*--------------------------------------------------*/
1882
1883#include "vg_kerneliface.h"
1884
1885static
1886__inline__
1887int is_kerror ( int res )
1888{
1889 if (res >= -4095 && res <= -1)
1890 return 1;
1891 else
1892 return 0;
1893}
1894
1895
1896static
1897int my_do_syscall1 ( int syscallno, int arg1 )
1898{
1899 int __res;
1900 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1901 : "=a" (__res)
1902 : "0" (syscallno),
1903 "d" (arg1) );
1904 return __res;
1905}
1906
1907static
1908int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001909 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001910{
1911 int __res;
1912 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1913 : "=a" (__res)
1914 : "0" (syscallno),
1915 "d" (arg1),
1916 "c" (arg2) );
1917 return __res;
1918}
1919
1920static
sewardjf854f472002-04-21 12:19:41 +00001921int my_do_syscall3 ( int syscallno,
1922 int arg1, int arg2, int arg3 )
1923{
1924 int __res;
1925 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1926 : "=a" (__res)
1927 : "0" (syscallno),
1928 "S" (arg1),
1929 "c" (arg2),
1930 "d" (arg3) );
1931 return __res;
1932}
1933
1934static
sewardj08a4c3f2002-04-13 03:45:44 +00001935int do_syscall_select( int n,
1936 vki_fd_set* readfds,
1937 vki_fd_set* writefds,
1938 vki_fd_set* exceptfds,
1939 struct vki_timeval * timeout )
1940{
1941 int res;
1942 int args[5];
1943 args[0] = n;
1944 args[1] = (int)readfds;
1945 args[2] = (int)writefds;
1946 args[3] = (int)exceptfds;
1947 args[4] = (int)timeout;
1948 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001949 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001950}
1951
1952
1953/* This is a wrapper round select(), which makes it thread-safe,
1954 meaning that only this thread will block, rather than the entire
1955 process. This wrapper in turn depends on nanosleep() not to block
1956 the entire process, but I think (hope? suspect?) that POSIX
1957 pthreads guarantees that to be the case.
1958
1959 Basic idea is: modify the timeout parameter to select so that it
1960 returns immediately. Poll like this until select returns non-zero,
1961 indicating something interesting happened, or until our time is up.
1962 Space out the polls with nanosleeps of say 20 milliseconds, which
1963 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001964
1965 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00001966 * (checked via my_assert) types fd_set and vki_fd_set are identical.
1967 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00001968 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1969 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001970*/
sewardj08a4c3f2002-04-13 03:45:44 +00001971
sewardj5905fae2002-04-26 13:25:00 +00001972/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001973int select ( int n,
1974 fd_set *rfds,
1975 fd_set *wfds,
1976 fd_set *xfds,
1977 struct timeval *timeout )
1978{
sewardj5f07b662002-04-23 16:52:51 +00001979 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001980 int res;
1981 fd_set rfds_copy;
1982 fd_set wfds_copy;
1983 fd_set xfds_copy;
1984 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001985 struct vki_timeval zero_timeout;
1986 struct vki_timespec nanosleep_interval;
1987
sewardjd140e442002-05-29 01:21:19 +00001988 __my_pthread_testcancel();
1989
sewardj5f07b662002-04-23 16:52:51 +00001990 /* gcc's complains about ms_end being used uninitialised -- classic
1991 case it can't understand, where ms_end is both defined and used
1992 only if timeout != NULL. Hence ... */
1993 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001994
1995 /* We assume that the kernel and libc data layouts are identical
1996 for the following types. These asserts provide a crude
1997 check. */
1998 if (sizeof(fd_set) != sizeof(vki_fd_set)
1999 || sizeof(struct timeval) != sizeof(struct vki_timeval))
2000 barf("valgrind's hacky non-blocking select(): data sizes error");
2001
sewardj5f07b662002-04-23 16:52:51 +00002002 /* Detect the current time and simultaneously find out if we are
2003 running on Valgrind. */
2004 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2005 VG_USERREQ__READ_MILLISECOND_TIMER,
2006 0, 0, 0, 0);
2007
2008 /* If a zero timeout specified, this call is harmless. Also go
2009 this route if we're not running on Valgrind, for whatever
2010 reason. */
2011 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
2012 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00002013 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00002014 (vki_fd_set*)wfds,
2015 (vki_fd_set*)xfds,
2016 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00002017 if (is_kerror(res)) {
2018 * (__errno_location()) = -res;
2019 return -1;
2020 } else {
2021 return res;
2022 }
2023 }
sewardj08a4c3f2002-04-13 03:45:44 +00002024
sewardj5f07b662002-04-23 16:52:51 +00002025 /* If a timeout was specified, set ms_end to be the end millisecond
2026 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00002027 if (timeout) {
2028 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00002029 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00002030 ms_end = ms_now;
2031 ms_end += (timeout->tv_usec / 1000);
2032 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00002033 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00002034 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00002035 }
2036
2037 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
2038
2039 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00002040 NULL, in which case ms_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002041
sewardj08a4c3f2002-04-13 03:45:44 +00002042 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002043
2044 /* First, do a return-immediately select(). */
sewardj08a4c3f2002-04-13 03:45:44 +00002045
2046 /* These could be trashed each time round the loop, so restore
2047 them each time. */
2048 if (rfds) rfds_copy = *rfds;
2049 if (wfds) wfds_copy = *wfds;
2050 if (xfds) xfds_copy = *xfds;
2051
2052 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
2053
2054 res = do_syscall_select( n,
2055 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
2056 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
2057 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
2058 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00002059 if (is_kerror(res)) {
2060 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00002061 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00002062 * (__errno_location()) = -res;
2063 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00002064 }
2065 if (res > 0) {
2066 /* one or more fds is ready. Copy out resulting sets and
2067 return. */
2068 if (rfds) *rfds = rfds_copy;
2069 if (wfds) *wfds = wfds_copy;
2070 if (xfds) *xfds = xfds_copy;
2071 return res;
2072 }
sewardj05bb2c92002-06-26 00:47:17 +00002073
2074 /* Nothing interesting happened, so we go to sleep for a
2075 while. */
2076
sewardj08a4c3f2002-04-13 03:45:44 +00002077 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
2078 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00002079 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00002080 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00002081 /* It's critical here that valgrind's nanosleep implementation
2082 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00002083 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00002084 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00002085 if (res == -VKI_EINTR) {
2086 /* The nanosleep was interrupted by a signal. So we do the
2087 same. */
2088 * (__errno_location()) = EINTR;
2089 return -1;
2090 }
sewardj05bb2c92002-06-26 00:47:17 +00002091
2092 /* Sleeping finished. If a finite timeout, check to see if it
2093 has expired yet. */
2094 if (timeout) {
2095 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2096 VG_USERREQ__READ_MILLISECOND_TIMER,
2097 0, 0, 0, 0);
2098 my_assert(ms_now != 0xFFFFFFFF);
2099 if (ms_now >= ms_end) {
2100 /* timeout; nothing interesting happened. */
2101 if (rfds) FD_ZERO(rfds);
2102 if (wfds) FD_ZERO(wfds);
2103 if (xfds) FD_ZERO(xfds);
2104 return 0;
2105 }
2106 }
2107
sewardjf854f472002-04-21 12:19:41 +00002108 }
2109}
2110
2111
2112
2113
2114#include <sys/poll.h>
2115
sewardj3e909ce2002-06-03 13:27:15 +00002116#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00002117typedef unsigned long int nfds_t;
2118#endif
2119
sewardj705d3cb2002-05-23 13:13:12 +00002120
sewardj5905fae2002-04-26 13:25:00 +00002121/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00002122int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2123{
sewardj5f07b662002-04-23 16:52:51 +00002124 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00002125 int res, i;
sewardjf854f472002-04-21 12:19:41 +00002126 struct vki_timespec nanosleep_interval;
2127
sewardjd140e442002-05-29 01:21:19 +00002128 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00002129 ensure_valgrind("poll");
2130
sewardj5f07b662002-04-23 16:52:51 +00002131 /* Detect the current time and simultaneously find out if we are
2132 running on Valgrind. */
2133 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2134 VG_USERREQ__READ_MILLISECOND_TIMER,
2135 0, 0, 0, 0);
2136
sewardjf854f472002-04-21 12:19:41 +00002137 if (/* CHECK SIZES FOR struct pollfd */
2138 sizeof(struct timeval) != sizeof(struct vki_timeval))
2139 barf("valgrind's hacky non-blocking poll(): data sizes error");
2140
sewardj5f07b662002-04-23 16:52:51 +00002141 /* dummy initialisation to keep gcc -Wall happy */
2142 ms_end = 0;
2143
2144 /* If a zero timeout specified, this call is harmless. Also do
2145 this if not running on Valgrind. */
2146 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00002147 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
2148 if (is_kerror(res)) {
2149 * (__errno_location()) = -res;
2150 return -1;
2151 } else {
2152 return res;
2153 }
2154 }
2155
sewardj5f07b662002-04-23 16:52:51 +00002156 /* If a timeout was specified, set ms_end to be the end wallclock
2157 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002158 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002159 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002160 }
2161
2162 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2163
2164 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2165 in which case t_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002166
sewardj2d94c112002-06-03 01:25:54 +00002167 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002168
sewardjf854f472002-04-21 12:19:41 +00002169 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002170
2171 /* Do a return-immediately poll. */
2172
2173 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2174 if (is_kerror(res)) {
2175 /* Some kind of error. Set errno and return. */
2176 * (__errno_location()) = -res;
2177 return -1;
2178 }
2179 if (res > 0) {
2180 /* One or more fds is ready. Return now. */
2181 return res;
2182 }
2183
2184 /* Nothing interesting happened, so we go to sleep for a
2185 while. */
2186
2187 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2188 /* nanosleep and go round again */
2189 nanosleep_interval.tv_sec = 0;
2190 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
2191 /* It's critical here that valgrind's nanosleep implementation
2192 is nonblocking. */
2193 (void)my_do_syscall2(__NR_nanosleep,
2194 (int)(&nanosleep_interval), (int)NULL);
2195
2196 /* Sleeping finished. If a finite timeout, check to see if it
2197 has expired yet. */
sewardjf854f472002-04-21 12:19:41 +00002198 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002199 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2200 VG_USERREQ__READ_MILLISECOND_TIMER,
2201 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002202 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002203 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002204 /* timeout; nothing interesting happened. */
2205 for (i = 0; i < __nfds; i++)
2206 __fds[i].revents = 0;
2207 return 0;
2208 }
2209 }
2210
sewardj08a4c3f2002-04-13 03:45:44 +00002211 }
2212}
sewardj3b13f0e2002-04-25 20:17:29 +00002213
2214
sewardj705d3cb2002-05-23 13:13:12 +00002215/* Helper function used to make accept() non-blocking. Idea is to use
2216 the above nonblocking poll() to make this thread ONLY wait for the
2217 specified fd to become ready, and then return. */
sewardjd1c1cf22002-06-26 00:13:36 +00002218
2219/* Sigh -- a hack. We're not supposed to include this file directly;
2220 should do it via /usr/include/fcntl.h, but that introduces a
2221 varargs prototype for fcntl itself, which we can't mimic. */
2222#define _FCNTL_H
2223#include <bits/fcntl.h>
2224
sewardj705d3cb2002-05-23 13:13:12 +00002225static void wait_for_fd_to_be_readable_or_erring ( int fd )
2226{
2227 struct pollfd pfd;
sewardjd1c1cf22002-06-26 00:13:36 +00002228 int res;
2229
sewardj6e6cbaa2002-05-24 02:12:52 +00002230 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardjd1c1cf22002-06-26 00:13:36 +00002231
2232 /* First check to see if the fd is nonblocking, and/or invalid. In
2233 either case return immediately. */
2234 res = __libc_fcntl(fd, F_GETFL, 0);
2235 if (res == -1) return; /* fd is invalid somehow */
2236 if (res & O_NONBLOCK) return; /* fd is nonblocking */
2237
2238 /* Ok, we'd better wait with poll. */
sewardj705d3cb2002-05-23 13:13:12 +00002239 pfd.fd = fd;
2240 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2241 /* ... but not POLLOUT, you may notice. */
2242 pfd.revents = 0;
2243 (void)poll(&pfd, 1, -1 /* forever */);
2244}
2245
2246
sewardj3b13f0e2002-04-25 20:17:29 +00002247/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002248 Hacky implementation of semaphores.
2249 ------------------------------------------------------------------ */
2250
2251#include <semaphore.h>
2252
2253/* This is a terrible way to do the remapping. Plan is to import an
2254 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002255
2256typedef
2257 struct {
2258 pthread_mutex_t se_mx;
2259 pthread_cond_t se_cv;
2260 int count;
2261 }
2262 vg_sem_t;
2263
2264static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2265
2266static int se_remap_used = 0;
2267static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2268static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2269
2270static vg_sem_t* se_remap ( sem_t* orig )
2271{
2272 int res, i;
2273 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002274 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002275
2276 for (i = 0; i < se_remap_used; i++) {
2277 if (se_remap_orig[i] == orig)
2278 break;
2279 }
2280 if (i == se_remap_used) {
2281 if (se_remap_used == VG_N_SEMAPHORES) {
2282 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002283 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002284 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002285 }
2286 se_remap_used++;
2287 se_remap_orig[i] = orig;
2288 /* printf("allocated semaphore %d\n", i); */
2289 }
2290 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002291 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002292 return &se_remap_new[i];
2293}
2294
2295
2296int sem_init(sem_t *sem, int pshared, unsigned int value)
2297{
2298 int res;
2299 vg_sem_t* vg_sem;
2300 ensure_valgrind("sem_init");
2301 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002302 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002303 errno = ENOSYS;
2304 return -1;
2305 }
2306 vg_sem = se_remap(sem);
2307 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002308 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002309 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002310 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002311 vg_sem->count = value;
2312 return 0;
2313}
2314
2315
2316int sem_wait ( sem_t* sem )
2317{
2318 int res;
2319 vg_sem_t* vg_sem;
2320 ensure_valgrind("sem_wait");
2321 vg_sem = se_remap(sem);
2322 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002323 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002324 while (vg_sem->count == 0) {
2325 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002326 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002327 }
2328 vg_sem->count--;
2329 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002330 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002331 return 0;
2332}
2333
2334int sem_post ( sem_t* sem )
2335{
2336 int res;
2337 vg_sem_t* vg_sem;
2338 ensure_valgrind("sem_post");
2339 vg_sem = se_remap(sem);
2340 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002341 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002342 if (vg_sem->count == 0) {
2343 vg_sem->count++;
2344 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002345 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002346 } else {
2347 vg_sem->count++;
2348 }
2349 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002350 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002351 return 0;
2352}
2353
2354
2355int sem_trywait ( sem_t* sem )
2356{
2357 int ret, res;
2358 vg_sem_t* vg_sem;
2359 ensure_valgrind("sem_trywait");
2360 vg_sem = se_remap(sem);
2361 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002362 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002363 if (vg_sem->count > 0) {
2364 vg_sem->count--;
2365 ret = 0;
2366 } else {
2367 ret = -1;
2368 errno = EAGAIN;
2369 }
2370 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002371 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002372 return ret;
2373}
2374
2375
2376int sem_getvalue(sem_t* sem, int * sval)
2377{
2378 vg_sem_t* vg_sem;
2379 ensure_valgrind("sem_trywait");
2380 vg_sem = se_remap(sem);
2381 *sval = vg_sem->count;
2382 return 0;
2383}
2384
2385
2386int sem_destroy(sem_t * sem)
2387{
2388 kludged("sem_destroy");
2389 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2390 return 0;
2391}
2392
2393
2394/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002395 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002396 ------------------------------------------------------------------ */
2397
sewardj2d8b3f02002-06-01 14:14:19 +00002398typedef
2399 struct {
2400 int initted; /* != 0 --> in use; sanity check only */
2401 int prefer_w; /* != 0 --> prefer writer */
2402 int nwait_r; /* # of waiting readers */
2403 int nwait_w; /* # of waiting writers */
2404 pthread_cond_t cv_r; /* for signalling readers */
2405 pthread_cond_t cv_w; /* for signalling writers */
2406 pthread_mutex_t mx;
2407 int status;
2408 /* allowed range for status: >= -1. -1 means 1 writer currently
2409 active, >= 0 means N readers currently active. */
2410 }
2411 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002412
2413
2414static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2415
2416static int rw_remap_used = 0;
2417static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2418static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2419
sewardj2d8b3f02002-06-01 14:14:19 +00002420
2421static
2422void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2423{
2424 int res = 0;
2425 vg_rwl->initted = 1;
2426 vg_rwl->prefer_w = 1;
2427 vg_rwl->nwait_r = 0;
2428 vg_rwl->nwait_w = 0;
2429 vg_rwl->status = 0;
2430 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2431 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2432 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002433 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002434}
2435
2436
sewardja1ac5cb2002-05-27 13:00:05 +00002437/* Take the address of a LinuxThreads rwlock_t and return the shadow
2438 address of our version. Further, if the LinuxThreads version
2439 appears to have been statically initialised, do the same to the one
2440 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2441 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2442 uninitialised and non-zero meaning initialised.
2443*/
2444static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2445{
2446 int res, i;
2447 vg_rwlock_t* vg_rwl;
2448 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002449 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002450
2451 for (i = 0; i < rw_remap_used; i++) {
2452 if (rw_remap_orig[i] == orig)
2453 break;
2454 }
2455 if (i == rw_remap_used) {
2456 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002457 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002458 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002459 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2460 }
2461 rw_remap_used++;
2462 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002463 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002464 if (0) printf("allocated rwlock %d\n", i);
2465 }
2466 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002467 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002468 vg_rwl = &rw_remap_new[i];
2469
sewardj2d8b3f02002-06-01 14:14:19 +00002470 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002471 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002472 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002473 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002474 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002475 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002476 }
2477
2478 return vg_rwl;
2479}
2480
2481
sewardja1ac5cb2002-05-27 13:00:05 +00002482int pthread_rwlock_init ( pthread_rwlock_t* orig,
2483 const pthread_rwlockattr_t* attr )
2484{
sewardja1ac5cb2002-05-27 13:00:05 +00002485 vg_rwlock_t* rwl;
2486 if (0) printf ("pthread_rwlock_init\n");
2487 /* Force the remapper to initialise the shadow. */
2488 orig->__rw_readers = 0;
2489 /* Install the lock preference; the remapper needs to know it. */
2490 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2491 if (attr)
2492 orig->__rw_kind = attr->__lockkind;
2493 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002494 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002495}
2496
sewardj2d8b3f02002-06-01 14:14:19 +00002497
2498static
2499void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002500{
sewardj2d8b3f02002-06-01 14:14:19 +00002501 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2502 rwl->nwait_r--;
2503 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002504}
2505
sewardj2d8b3f02002-06-01 14:14:19 +00002506
sewardja1ac5cb2002-05-27 13:00:05 +00002507int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2508{
2509 int res;
2510 vg_rwlock_t* rwl;
2511 if (0) printf ("pthread_rwlock_rdlock\n");
2512 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002513 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002514 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002515 if (!rwl->initted) {
2516 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002517 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002518 return EINVAL;
2519 }
2520 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002521 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002522 rwl->nwait_r++;
2523 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2524 while (1) {
2525 if (rwl->status == 0) break;
2526 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002527 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002528 }
2529 pthread_cleanup_pop(0);
2530 rwl->nwait_r--;
2531 }
sewardj2d94c112002-06-03 01:25:54 +00002532 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002533 rwl->status++;
2534 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002535 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002536 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002537}
2538
sewardj2d8b3f02002-06-01 14:14:19 +00002539
sewardja1ac5cb2002-05-27 13:00:05 +00002540int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2541{
2542 int res;
2543 vg_rwlock_t* rwl;
2544 if (0) printf ("pthread_rwlock_tryrdlock\n");
2545 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002546 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002547 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002548 if (!rwl->initted) {
2549 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002550 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002551 return EINVAL;
2552 }
2553 if (rwl->status == -1) {
2554 /* Writer active; we have to give up. */
2555 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002556 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002557 return EBUSY;
2558 }
2559 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002560 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002561 rwl->status++;
2562 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002563 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002564 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002565}
2566
sewardj2d8b3f02002-06-01 14:14:19 +00002567
2568static
2569void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2570{
2571 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2572 rwl->nwait_w--;
2573 pthread_mutex_unlock (&rwl->mx);
2574}
2575
2576
sewardja1ac5cb2002-05-27 13:00:05 +00002577int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2578{
2579 int res;
2580 vg_rwlock_t* rwl;
2581 if (0) printf ("pthread_rwlock_wrlock\n");
2582 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002583 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002584 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002585 if (!rwl->initted) {
2586 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002587 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002588 return EINVAL;
2589 }
2590 if (rwl->status != 0) {
2591 rwl->nwait_w++;
2592 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2593 while (1) {
2594 if (rwl->status == 0) break;
2595 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002596 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002597 }
2598 pthread_cleanup_pop(0);
2599 rwl->nwait_w--;
2600 }
sewardj2d94c112002-06-03 01:25:54 +00002601 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002602 rwl->status = -1;
2603 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002604 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002605 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002606}
2607
sewardj2d8b3f02002-06-01 14:14:19 +00002608
sewardja1ac5cb2002-05-27 13:00:05 +00002609int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2610{
2611 int res;
2612 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002613 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002614 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002615 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002616 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002617 if (!rwl->initted) {
2618 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002619 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002620 return EINVAL;
2621 }
2622 if (rwl->status != 0) {
2623 /* Reader(s) or a writer active; we have to give up. */
2624 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002625 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002626 return EBUSY;
2627 }
2628 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002629 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002630 rwl->status = -1;
2631 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002632 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002633 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002634}
2635
sewardj2d8b3f02002-06-01 14:14:19 +00002636
sewardja1ac5cb2002-05-27 13:00:05 +00002637int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2638{
2639 int res;
2640 vg_rwlock_t* rwl;
2641 if (0) printf ("pthread_rwlock_unlock\n");
2642 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002643 rwl = rw_remap ( orig );
2644 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002645 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002646 if (!rwl->initted) {
2647 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002648 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002649 return EINVAL;
2650 }
2651 if (rwl->status == 0) {
2652 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002653 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002654 return EPERM;
2655 }
sewardj2d94c112002-06-03 01:25:54 +00002656 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002657 if (rwl->status == -1) {
2658 rwl->status = 0;
2659 } else {
sewardj2d94c112002-06-03 01:25:54 +00002660 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002661 rwl->status--;
2662 }
2663
sewardj2d94c112002-06-03 01:25:54 +00002664 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002665
2666 if (rwl->prefer_w) {
2667
2668 /* Favour waiting writers, if any. */
2669 if (rwl->nwait_w > 0) {
2670 /* Writer(s) are waiting. */
2671 if (rwl->status == 0) {
2672 /* We can let a writer in. */
2673 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002674 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002675 } else {
2676 /* There are still readers active. Do nothing; eventually
2677 they will disappear, at which point a writer will be
2678 admitted. */
2679 }
2680 }
2681 else
2682 /* No waiting writers. */
2683 if (rwl->nwait_r > 0) {
2684 /* Let in a waiting reader. */
2685 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002686 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002687 }
2688
2689 } else {
2690
2691 /* Favour waiting readers, if any. */
2692 if (rwl->nwait_r > 0) {
2693 /* Reader(s) are waiting; let one in. */
2694 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002695 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002696 }
2697 else
2698 /* No waiting readers. */
2699 if (rwl->nwait_w > 0 && rwl->status == 0) {
2700 /* We have waiting writers and no active readers; let a
2701 writer in. */
2702 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002703 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002704 }
2705 }
2706
2707 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002708 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002709 return 0;
2710}
2711
2712
2713int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2714{
2715 int res;
2716 vg_rwlock_t* rwl;
2717 if (0) printf ("pthread_rwlock_destroy\n");
2718 rwl = rw_remap ( orig );
2719 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002720 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002721 if (!rwl->initted) {
2722 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002723 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002724 return EINVAL;
2725 }
2726 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2727 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002728 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002729 return EBUSY;
2730 }
2731 rwl->initted = 0;
2732 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002733 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002734 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002735}
2736
2737
sewardj47e4e312002-06-18 09:24:34 +00002738/* Copied directly from LinuxThreads. */
2739int
2740pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
2741{
2742 attr->__lockkind = 0;
2743 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
2744
2745 return 0;
2746}
2747
sewardjfe18eb82002-07-13 12:58:44 +00002748/* Copied directly from LinuxThreads. */
2749int
2750pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
2751{
2752 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
2753 return EINVAL;
2754
2755 /* For now it is not possible to shared a conditional variable. */
2756 if (pshared != PTHREAD_PROCESS_PRIVATE)
2757 return ENOSYS;
2758
2759 attr->__pshared = pshared;
2760
2761 return 0;
2762}
2763
sewardj47e4e312002-06-18 09:24:34 +00002764
sewardja1ac5cb2002-05-27 13:00:05 +00002765/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002766 B'stard.
2767 ------------------------------------------------------------------ */
2768
2769# define strong_alias(name, aliasname) \
2770 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2771
sewardj5905fae2002-04-26 13:25:00 +00002772# define weak_alias(name, aliasname) \
2773 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002774
sewardj5905fae2002-04-26 13:25:00 +00002775strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2776strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2777strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2778strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2779 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2780strong_alias(__pthread_mutex_init, pthread_mutex_init)
2781strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2782strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2783strong_alias(__pthread_once, pthread_once)
2784strong_alias(__pthread_atfork, pthread_atfork)
2785strong_alias(__pthread_key_create, pthread_key_create)
2786strong_alias(__pthread_getspecific, pthread_getspecific)
2787strong_alias(__pthread_setspecific, pthread_setspecific)
2788
sewardjd529a442002-05-04 19:49:21 +00002789#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002790strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002791#endif
2792
sewardj5905fae2002-04-26 13:25:00 +00002793strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002794strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002795strong_alias(lseek, __lseek)
2796strong_alias(open, __open)
2797strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002798strong_alias(read, __read)
2799strong_alias(wait, __wait)
2800strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002801strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002802strong_alias(send, __send)
2803
sewardj726c4122002-05-16 23:39:10 +00002804weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002805weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002806weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002807
sewardjf0b06452002-06-04 08:38:04 +00002808weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00002809
2810/*--------------------------------------------------*/
2811
sewardj5905fae2002-04-26 13:25:00 +00002812weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002813weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002814weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002815
sewardja1ac5cb2002-05-27 13:00:05 +00002816weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2817weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2818weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2819weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2820
sewardj060b04f2002-04-26 21:01:13 +00002821
sewardj3b13f0e2002-04-25 20:17:29 +00002822/* I've no idea what these are, but they get called quite a lot.
2823 Anybody know? */
2824
2825#undef _IO_flockfile
2826void _IO_flockfile ( _IO_FILE * file )
2827{
sewardj853f55d2002-04-26 00:27:53 +00002828 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002829}
sewardj5905fae2002-04-26 13:25:00 +00002830weak_alias(_IO_flockfile, flockfile);
2831
sewardj3b13f0e2002-04-25 20:17:29 +00002832
2833#undef _IO_funlockfile
2834void _IO_funlockfile ( _IO_FILE * file )
2835{
sewardj853f55d2002-04-26 00:27:53 +00002836 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002837}
sewardj5905fae2002-04-26 13:25:00 +00002838weak_alias(_IO_funlockfile, funlockfile);
2839
sewardj3b13f0e2002-04-25 20:17:29 +00002840
sewardjd4f2c712002-04-30 10:20:10 +00002841/* This doesn't seem to be needed to simulate libpthread.so's external
2842 interface, but many people complain about its absence. */
2843
2844strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2845weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002846
2847
2848/*--------------------------------------------------------------------*/
2849/*--- end vg_libpthread.c ---*/
2850/*--------------------------------------------------------------------*/