blob: 994cdb74e0612d4d2f55fd59a147cd6f11d46df6 [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
sewardj1462c8b2002-07-24 09:41:52 +0000550pthread_create (pthread_t *__restrict __thredd,
sewardje663cb92002-04-12 10:26:32 +0000551 __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
sewardj1462c8b2002-07-24 09:41:52 +0000579 if (__thredd)
580 *__thredd = tid_child;
sewardj20917d82002-05-28 01:36:45 +0000581 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
sewardjb0ff1032002-08-06 09:02:53 +00001357
1358#undef _res
1359extern struct __res_state _res;
1360
sewardj3b13f0e2002-04-25 20:17:29 +00001361struct __res_state* __res_state ( void )
1362{
1363 int tid;
1364 /* ensure_valgrind("__res_state"); */
1365 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1366 VG_USERREQ__PTHREAD_GET_THREADID,
1367 0, 0, 0, 0);
1368 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001369 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001370 barf("__res_state: invalid ThreadId");
sewardjb0ff1032002-08-06 09:02:53 +00001371 if (tid == 1)
1372 return & _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001373 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001374}
1375
1376
sewardj5716dbb2002-04-26 03:28:18 +00001377/* ---------------------------------------------------
1378 LIBC-PRIVATE SPECIFIC DATA
1379 ------------------------------------------------ */
1380
1381/* Relies on assumption that initial private data is NULL. This
1382 should be fixed somehow. */
1383
1384/* The allowable keys (indices) (all 2 of them).
1385 From sysdeps/pthread/bits/libc-tsd.h
1386*/
sewardj70adeb22002-04-27 01:35:38 +00001387#define N_LIBC_TSD_EXTRA_KEYS 1
1388
sewardj5716dbb2002-04-26 03:28:18 +00001389enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1390 _LIBC_TSD_KEY_DL_ERROR,
1391 _LIBC_TSD_KEY_N };
1392
1393/* Auto-initialising subsystem. libc_specifics_inited is set
1394 after initialisation. libc_specifics_inited_mx guards it. */
1395static int libc_specifics_inited = 0;
1396static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1397
1398/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001399static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1400 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001401
1402/* Initialise the keys, if they are not already initialise. */
1403static
1404void init_libc_tsd_keys ( void )
1405{
1406 int res, i;
1407 pthread_key_t k;
1408
1409 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1410 if (res != 0) barf("init_libc_tsd_keys: lock");
1411
1412 if (libc_specifics_inited == 0) {
1413 /* printf("INIT libc specifics\n"); */
1414 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001415 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001416 res = pthread_key_create(&k, NULL);
1417 if (res != 0) barf("init_libc_tsd_keys: create");
1418 libc_specifics_keys[i] = k;
1419 }
1420 }
1421
1422 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1423 if (res != 0) barf("init_libc_tsd_keys: unlock");
1424}
1425
1426
1427static int
1428libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1429 const void * pointer )
1430{
sewardj70adeb22002-04-27 01:35:38 +00001431 int res;
1432 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001433 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001434 if (key < _LIBC_TSD_KEY_MALLOC
1435 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001436 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001437 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1438 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001439 "valgrind's libpthread.so: libc_internal_tsd_set: "
1440 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001441 init_libc_tsd_keys();
1442 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1443 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1444 return 0;
1445}
1446
1447static void *
1448libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1449{
sewardj70adeb22002-04-27 01:35:38 +00001450 void* v;
1451 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001452 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001453 if (key < _LIBC_TSD_KEY_MALLOC
1454 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001455 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001456 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1457 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001458 "valgrind's libpthread.so: libc_internal_tsd_get: "
1459 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001460 init_libc_tsd_keys();
1461 v = pthread_getspecific(libc_specifics_keys[key]);
1462 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1463 return v;
1464}
1465
1466
1467
1468
sewardj70adeb22002-04-27 01:35:38 +00001469int (*__libc_internal_tsd_set)
1470 (enum __libc_tsd_key_t key, const void * pointer)
1471 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001472
sewardj70adeb22002-04-27 01:35:38 +00001473void* (*__libc_internal_tsd_get)
1474 (enum __libc_tsd_key_t key)
1475 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001476
1477
sewardje663cb92002-04-12 10:26:32 +00001478/* ---------------------------------------------------------------------
1479 These are here (I think) because they are deemed cancellation
1480 points by POSIX. For the moment we'll simply pass the call along
1481 to the corresponding thread-unaware (?) libc routine.
1482 ------------------------------------------------------------------ */
1483
sewardje663cb92002-04-12 10:26:32 +00001484#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001485#include <sys/types.h>
1486#include <sys/socket.h>
1487
sewardjd529a442002-05-04 19:49:21 +00001488#ifdef GLIBC_2_1
1489extern
1490int __sigaction
1491 (int signum,
1492 const struct sigaction *act,
1493 struct sigaction *oldact);
1494#else
sewardje663cb92002-04-12 10:26:32 +00001495extern
1496int __libc_sigaction
1497 (int signum,
1498 const struct sigaction *act,
1499 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001500#endif
sewardje663cb92002-04-12 10:26:32 +00001501int sigaction(int signum,
1502 const struct sigaction *act,
1503 struct sigaction *oldact)
1504{
sewardjd140e442002-05-29 01:21:19 +00001505 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001506# ifdef GLIBC_2_1
1507 return __sigaction(signum, act, oldact);
1508# else
sewardj45b4b372002-04-16 22:50:32 +00001509 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001510# endif
sewardje663cb92002-04-12 10:26:32 +00001511}
1512
1513
1514extern
1515int __libc_connect(int sockfd,
1516 const struct sockaddr *serv_addr,
1517 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001518__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001519int connect(int sockfd,
1520 const struct sockaddr *serv_addr,
1521 socklen_t addrlen)
1522{
sewardjd140e442002-05-29 01:21:19 +00001523 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001524 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001525}
1526
1527
1528extern
1529int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001530__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001531int fcntl(int fd, int cmd, long arg)
1532{
sewardjd140e442002-05-29 01:21:19 +00001533 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001534 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001535}
1536
1537
1538extern
1539ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001540__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001541ssize_t write(int fd, const void *buf, size_t count)
1542{
sewardjd140e442002-05-29 01:21:19 +00001543 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001544 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001545}
1546
1547
1548extern
1549ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001550__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001551ssize_t read(int fd, void *buf, size_t count)
1552{
sewardjd140e442002-05-29 01:21:19 +00001553 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001554 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001555}
1556
sewardjbe32e452002-04-24 20:29:58 +00001557
1558extern
sewardj853f55d2002-04-26 00:27:53 +00001559int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001560__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001561int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001562{
sewardjd140e442002-05-29 01:21:19 +00001563 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001564 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001565}
1566
sewardje663cb92002-04-12 10:26:32 +00001567
1568extern
sewardj853f55d2002-04-26 00:27:53 +00001569int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001570__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001571int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001572{
sewardjd140e442002-05-29 01:21:19 +00001573 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001574 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001575}
1576
1577
1578extern
1579int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001580__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001581int close(int fd)
1582{
sewardjd140e442002-05-29 01:21:19 +00001583 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001584 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001585}
1586
1587
1588extern
1589int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001590__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001591int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1592{
sewardjd140e442002-05-29 01:21:19 +00001593 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001594 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001595 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001596 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001597}
1598
1599
1600extern
sewardje663cb92002-04-12 10:26:32 +00001601pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001602__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001603pid_t waitpid(pid_t pid, int *status, int options)
1604{
sewardjd140e442002-05-29 01:21:19 +00001605 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001606 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001607}
1608
1609
1610extern
1611int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001612__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001613int nanosleep(const struct timespec *req, struct timespec *rem)
1614{
sewardjd140e442002-05-29 01:21:19 +00001615 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001616 return __libc_nanosleep(req, rem);
1617}
1618
sewardjbe32e452002-04-24 20:29:58 +00001619
sewardje663cb92002-04-12 10:26:32 +00001620extern
1621int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001622__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001623int fsync(int fd)
1624{
sewardjd140e442002-05-29 01:21:19 +00001625 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001626 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001627}
1628
sewardjbe32e452002-04-24 20:29:58 +00001629
sewardj70c75362002-04-13 04:18:32 +00001630extern
1631off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001632__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001633off_t lseek(int fildes, off_t offset, int whence)
1634{
sewardjd140e442002-05-29 01:21:19 +00001635 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001636 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001637}
1638
sewardjbe32e452002-04-24 20:29:58 +00001639
1640extern
1641__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001642__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001643__off64_t lseek64(int fildes, __off64_t offset, int whence)
1644{
sewardjd140e442002-05-29 01:21:19 +00001645 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001646 return __libc_lseek64(fildes, offset, whence);
1647}
1648
1649
sewardj726c4122002-05-16 23:39:10 +00001650extern
1651ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1652 __off64_t __offset);
1653ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1654 __off64_t __offset)
1655{
sewardjd140e442002-05-29 01:21:19 +00001656 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001657 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1658}
1659
1660
sewardja18e2102002-05-18 10:43:22 +00001661extern
1662ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1663 __off64_t __offset);
1664ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1665 __off64_t __offset)
1666{
sewardjd140e442002-05-29 01:21:19 +00001667 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001668 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1669}
1670
sewardj726c4122002-05-16 23:39:10 +00001671
sewardj39b93b12002-05-18 10:56:27 +00001672extern
1673ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1674__attribute__((weak))
1675ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1676{
sewardjd140e442002-05-29 01:21:19 +00001677 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001678 return __libc_pwrite(fd, buf, count, offset);
1679}
1680
1681
1682extern
1683ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1684__attribute__((weak))
1685ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1686{
sewardjd140e442002-05-29 01:21:19 +00001687 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001688 return __libc_pread(fd, buf, count, offset);
1689}
1690
1691
sewardj6af4b5d2002-04-16 04:40:49 +00001692extern
1693void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001694/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001695void longjmp(jmp_buf env, int val)
1696{
1697 __libc_longjmp(env, val);
1698}
1699
sewardjbe32e452002-04-24 20:29:58 +00001700
sewardj436c2db2002-06-18 09:07:54 +00001701extern void __libc_siglongjmp (sigjmp_buf env, int val)
1702 __attribute__ ((noreturn));
1703void siglongjmp(sigjmp_buf env, int val)
1704{
1705 kludged("siglongjmp (cleanup handlers are ignored)");
1706 __libc_siglongjmp(env, val);
1707}
1708
1709
sewardj6af4b5d2002-04-16 04:40:49 +00001710extern
1711int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001712__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001713int send(int s, const void *msg, size_t len, int flags)
1714{
sewardjd140e442002-05-29 01:21:19 +00001715 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001716 return __libc_send(s, msg, len, flags);
1717}
1718
sewardjbe32e452002-04-24 20:29:58 +00001719
sewardj1e8cdc92002-04-18 11:37:52 +00001720extern
1721int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001722__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001723int recv(int s, void *buf, size_t len, int flags)
1724{
sewardjd140e442002-05-29 01:21:19 +00001725 __my_pthread_testcancel();
sewardj1d6b3a22002-06-20 07:58:33 +00001726 wait_for_fd_to_be_readable_or_erring(s);
1727 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001728 return __libc_recv(s, buf, len, flags);
1729}
1730
sewardjbe32e452002-04-24 20:29:58 +00001731
sewardj3665ded2002-05-16 16:57:25 +00001732extern
1733int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1734__attribute__((weak))
1735int sendmsg(int s, const struct msghdr *msg, int flags)
1736{
sewardjd140e442002-05-29 01:21:19 +00001737 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001738 return __libc_sendmsg(s, msg, flags);
1739}
1740
1741
sewardj796d6a22002-04-24 02:28:34 +00001742extern
sewardj59da27a2002-06-06 08:33:54 +00001743int __libc_recvmsg(int s, struct msghdr *msg, int flags);
1744__attribute__((weak))
1745int recvmsg(int s, struct msghdr *msg, int flags)
1746{
1747 __my_pthread_testcancel();
1748 return __libc_recvmsg(s, msg, flags);
1749}
1750
1751
1752extern
sewardj436e0582002-04-26 14:31:40 +00001753int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1754 struct sockaddr *from, socklen_t *fromlen);
1755__attribute__((weak))
1756int recvfrom(int s, void *buf, size_t len, int flags,
1757 struct sockaddr *from, socklen_t *fromlen)
1758{
sewardjd140e442002-05-29 01:21:19 +00001759 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00001760 wait_for_fd_to_be_readable_or_erring(s);
1761 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001762 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1763}
1764
1765
1766extern
sewardj796d6a22002-04-24 02:28:34 +00001767int __libc_sendto(int s, const void *msg, size_t len, int flags,
1768 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001769__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001770int sendto(int s, const void *msg, size_t len, int flags,
1771 const struct sockaddr *to, socklen_t tolen)
1772{
sewardjd140e442002-05-29 01:21:19 +00001773 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001774 return __libc_sendto(s, msg, len, flags, to, tolen);
1775}
1776
sewardjbe32e452002-04-24 20:29:58 +00001777
sewardj369b1702002-04-24 13:28:15 +00001778extern
1779int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001780__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001781int system(const char* str)
1782{
sewardjd140e442002-05-29 01:21:19 +00001783 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001784 return __libc_system(str);
1785}
1786
sewardjbe32e452002-04-24 20:29:58 +00001787
sewardjab0b1c32002-04-24 19:26:47 +00001788extern
1789pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001790__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001791pid_t wait(int *status)
1792{
sewardjd140e442002-05-29 01:21:19 +00001793 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00001794 return __libc_wait(status);
1795}
1796
sewardj45b4b372002-04-16 22:50:32 +00001797
sewardj67f1d582002-05-24 02:11:32 +00001798extern
1799int __libc_msync(const void *start, size_t length, int flags);
1800__attribute__((weak))
1801int msync(const void *start, size_t length, int flags)
1802{
sewardjd140e442002-05-29 01:21:19 +00001803 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00001804 return __libc_msync(start, length, flags);
1805}
1806
sewardj5905fae2002-04-26 13:25:00 +00001807
sewardj2cb00342002-06-28 01:46:26 +00001808/*--- fork and its helper ---*/
1809
1810static
1811void run_fork_handlers ( int what )
1812{
1813 ForkHandlerEntry entry;
1814 int n_h, n_handlers, i, res;
1815
1816 my_assert(what == 0 || what == 1 || what == 2);
1817
1818 /* Fetch old counter */
1819 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
1820 VG_USERREQ__GET_FHSTACK_USED,
1821 0, 0, 0, 0);
1822 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
1823
1824 /* Prepare handlers (what == 0) are called in opposite order of
1825 calls to pthread_atfork. Parent and child handlers are called
1826 in the same order as calls to pthread_atfork. */
1827 if (what == 0)
1828 n_h = n_handlers - 1;
1829 else
1830 n_h = 0;
1831
1832 for (i = 0; i < n_handlers; i++) {
1833 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1834 VG_USERREQ__GET_FHSTACK_ENTRY,
1835 n_h, &entry, 0, 0);
1836 my_assert(res == 0);
1837 switch (what) {
1838 case 0: if (entry.prepare) entry.prepare();
1839 n_h--; break;
1840 case 1: if (entry.parent) entry.parent();
1841 n_h++; break;
1842 case 2: if (entry.child) entry.child();
1843 n_h++; break;
1844 default: barf("run_fork_handlers: invalid what");
1845 }
1846 }
1847
1848 if (what != 0 /* prepare */) {
1849 /* Empty out the stack. */
1850 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1851 VG_USERREQ__SET_FHSTACK_USED,
1852 0, 0, 0, 0);
1853 my_assert(res == 0);
1854 }
1855}
1856
1857extern
1858pid_t __libc_fork(void);
1859pid_t __fork(void)
1860{
1861 pid_t pid;
1862 __my_pthread_testcancel();
1863 __pthread_mutex_lock(&pthread_atfork_lock);
1864
1865 run_fork_handlers(0 /* prepare */);
1866 pid = __libc_fork();
1867 if (pid == 0) {
1868 /* I am the child */
1869 run_fork_handlers(2 /* child */);
1870 __pthread_mutex_init(&pthread_atfork_lock, NULL);
1871 } else {
1872 /* I am the parent */
1873 run_fork_handlers(1 /* parent */);
1874 __pthread_mutex_unlock(&pthread_atfork_lock);
1875 }
1876 return pid;
1877}
1878
1879
1880
1881
sewardj3b13f0e2002-04-25 20:17:29 +00001882/* ---------------------------------------------------------------------
1883 Nonblocking implementations of select() and poll(). This stuff will
1884 surely rot your mind.
1885 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001886
sewardj08a4c3f2002-04-13 03:45:44 +00001887/*--------------------------------------------------*/
1888
1889#include "vg_kerneliface.h"
1890
1891static
1892__inline__
1893int is_kerror ( int res )
1894{
1895 if (res >= -4095 && res <= -1)
1896 return 1;
1897 else
1898 return 0;
1899}
1900
1901
1902static
1903int my_do_syscall1 ( int syscallno, int arg1 )
1904{
1905 int __res;
1906 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1907 : "=a" (__res)
1908 : "0" (syscallno),
1909 "d" (arg1) );
1910 return __res;
1911}
1912
1913static
1914int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001915 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001916{
1917 int __res;
1918 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1919 : "=a" (__res)
1920 : "0" (syscallno),
1921 "d" (arg1),
1922 "c" (arg2) );
1923 return __res;
1924}
1925
1926static
sewardjf854f472002-04-21 12:19:41 +00001927int my_do_syscall3 ( int syscallno,
1928 int arg1, int arg2, int arg3 )
1929{
1930 int __res;
1931 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1932 : "=a" (__res)
1933 : "0" (syscallno),
1934 "S" (arg1),
1935 "c" (arg2),
1936 "d" (arg3) );
1937 return __res;
1938}
1939
1940static
sewardj08a4c3f2002-04-13 03:45:44 +00001941int do_syscall_select( int n,
1942 vki_fd_set* readfds,
1943 vki_fd_set* writefds,
1944 vki_fd_set* exceptfds,
1945 struct vki_timeval * timeout )
1946{
1947 int res;
1948 int args[5];
1949 args[0] = n;
1950 args[1] = (int)readfds;
1951 args[2] = (int)writefds;
1952 args[3] = (int)exceptfds;
1953 args[4] = (int)timeout;
1954 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001955 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001956}
1957
1958
1959/* This is a wrapper round select(), which makes it thread-safe,
1960 meaning that only this thread will block, rather than the entire
1961 process. This wrapper in turn depends on nanosleep() not to block
1962 the entire process, but I think (hope? suspect?) that POSIX
1963 pthreads guarantees that to be the case.
1964
1965 Basic idea is: modify the timeout parameter to select so that it
1966 returns immediately. Poll like this until select returns non-zero,
1967 indicating something interesting happened, or until our time is up.
1968 Space out the polls with nanosleeps of say 20 milliseconds, which
1969 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001970
1971 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00001972 * (checked via my_assert) types fd_set and vki_fd_set are identical.
1973 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00001974 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1975 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001976*/
sewardj08a4c3f2002-04-13 03:45:44 +00001977
sewardj5905fae2002-04-26 13:25:00 +00001978/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001979int select ( int n,
1980 fd_set *rfds,
1981 fd_set *wfds,
1982 fd_set *xfds,
1983 struct timeval *timeout )
1984{
sewardj5f07b662002-04-23 16:52:51 +00001985 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001986 int res;
1987 fd_set rfds_copy;
1988 fd_set wfds_copy;
1989 fd_set xfds_copy;
1990 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001991 struct vki_timeval zero_timeout;
1992 struct vki_timespec nanosleep_interval;
1993
sewardjd140e442002-05-29 01:21:19 +00001994 __my_pthread_testcancel();
1995
sewardj5f07b662002-04-23 16:52:51 +00001996 /* gcc's complains about ms_end being used uninitialised -- classic
1997 case it can't understand, where ms_end is both defined and used
1998 only if timeout != NULL. Hence ... */
1999 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00002000
2001 /* We assume that the kernel and libc data layouts are identical
2002 for the following types. These asserts provide a crude
2003 check. */
2004 if (sizeof(fd_set) != sizeof(vki_fd_set)
2005 || sizeof(struct timeval) != sizeof(struct vki_timeval))
2006 barf("valgrind's hacky non-blocking select(): data sizes error");
2007
sewardj5f07b662002-04-23 16:52:51 +00002008 /* Detect the current time and simultaneously find out if we are
2009 running on Valgrind. */
2010 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2011 VG_USERREQ__READ_MILLISECOND_TIMER,
2012 0, 0, 0, 0);
2013
2014 /* If a zero timeout specified, this call is harmless. Also go
2015 this route if we're not running on Valgrind, for whatever
2016 reason. */
2017 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
2018 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00002019 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00002020 (vki_fd_set*)wfds,
2021 (vki_fd_set*)xfds,
2022 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00002023 if (is_kerror(res)) {
2024 * (__errno_location()) = -res;
2025 return -1;
2026 } else {
2027 return res;
2028 }
2029 }
sewardj08a4c3f2002-04-13 03:45:44 +00002030
sewardj5f07b662002-04-23 16:52:51 +00002031 /* If a timeout was specified, set ms_end to be the end millisecond
2032 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00002033 if (timeout) {
2034 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00002035 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00002036 ms_end = ms_now;
2037 ms_end += (timeout->tv_usec / 1000);
2038 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00002039 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00002040 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00002041 }
2042
2043 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
2044
2045 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00002046 NULL, in which case ms_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002047
sewardj08a4c3f2002-04-13 03:45:44 +00002048 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002049
2050 /* First, do a return-immediately select(). */
sewardj08a4c3f2002-04-13 03:45:44 +00002051
2052 /* These could be trashed each time round the loop, so restore
2053 them each time. */
2054 if (rfds) rfds_copy = *rfds;
2055 if (wfds) wfds_copy = *wfds;
2056 if (xfds) xfds_copy = *xfds;
2057
2058 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
2059
2060 res = do_syscall_select( n,
2061 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
2062 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
2063 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
2064 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00002065 if (is_kerror(res)) {
2066 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00002067 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00002068 * (__errno_location()) = -res;
2069 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00002070 }
2071 if (res > 0) {
2072 /* one or more fds is ready. Copy out resulting sets and
2073 return. */
2074 if (rfds) *rfds = rfds_copy;
2075 if (wfds) *wfds = wfds_copy;
2076 if (xfds) *xfds = xfds_copy;
2077 return res;
2078 }
sewardj05bb2c92002-06-26 00:47:17 +00002079
2080 /* Nothing interesting happened, so we go to sleep for a
2081 while. */
2082
sewardj08a4c3f2002-04-13 03:45:44 +00002083 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
2084 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00002085 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00002086 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00002087 /* It's critical here that valgrind's nanosleep implementation
2088 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00002089 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00002090 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00002091 if (res == -VKI_EINTR) {
2092 /* The nanosleep was interrupted by a signal. So we do the
2093 same. */
2094 * (__errno_location()) = EINTR;
2095 return -1;
2096 }
sewardj05bb2c92002-06-26 00:47:17 +00002097
2098 /* Sleeping finished. If a finite timeout, check to see if it
2099 has expired yet. */
2100 if (timeout) {
2101 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2102 VG_USERREQ__READ_MILLISECOND_TIMER,
2103 0, 0, 0, 0);
2104 my_assert(ms_now != 0xFFFFFFFF);
2105 if (ms_now >= ms_end) {
2106 /* timeout; nothing interesting happened. */
2107 if (rfds) FD_ZERO(rfds);
2108 if (wfds) FD_ZERO(wfds);
2109 if (xfds) FD_ZERO(xfds);
2110 return 0;
2111 }
2112 }
2113
sewardjf854f472002-04-21 12:19:41 +00002114 }
2115}
2116
2117
2118
2119
2120#include <sys/poll.h>
2121
sewardj3e909ce2002-06-03 13:27:15 +00002122#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00002123typedef unsigned long int nfds_t;
2124#endif
2125
sewardj705d3cb2002-05-23 13:13:12 +00002126
sewardj5905fae2002-04-26 13:25:00 +00002127/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00002128int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2129{
sewardj5f07b662002-04-23 16:52:51 +00002130 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00002131 int res, i;
sewardjf854f472002-04-21 12:19:41 +00002132 struct vki_timespec nanosleep_interval;
2133
sewardjd140e442002-05-29 01:21:19 +00002134 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00002135 ensure_valgrind("poll");
2136
sewardj5f07b662002-04-23 16:52:51 +00002137 /* Detect the current time and simultaneously find out if we are
2138 running on Valgrind. */
2139 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2140 VG_USERREQ__READ_MILLISECOND_TIMER,
2141 0, 0, 0, 0);
2142
sewardjf854f472002-04-21 12:19:41 +00002143 if (/* CHECK SIZES FOR struct pollfd */
2144 sizeof(struct timeval) != sizeof(struct vki_timeval))
2145 barf("valgrind's hacky non-blocking poll(): data sizes error");
2146
sewardj5f07b662002-04-23 16:52:51 +00002147 /* dummy initialisation to keep gcc -Wall happy */
2148 ms_end = 0;
2149
2150 /* If a zero timeout specified, this call is harmless. Also do
2151 this if not running on Valgrind. */
2152 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00002153 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
2154 if (is_kerror(res)) {
2155 * (__errno_location()) = -res;
2156 return -1;
2157 } else {
2158 return res;
2159 }
2160 }
2161
sewardj5f07b662002-04-23 16:52:51 +00002162 /* If a timeout was specified, set ms_end to be the end wallclock
2163 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002164 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002165 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002166 }
2167
2168 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2169
2170 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2171 in which case t_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002172
sewardj2d94c112002-06-03 01:25:54 +00002173 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002174
sewardjf854f472002-04-21 12:19:41 +00002175 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002176
2177 /* Do a return-immediately poll. */
2178
2179 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2180 if (is_kerror(res)) {
2181 /* Some kind of error. Set errno and return. */
2182 * (__errno_location()) = -res;
2183 return -1;
2184 }
2185 if (res > 0) {
2186 /* One or more fds is ready. Return now. */
2187 return res;
2188 }
2189
2190 /* Nothing interesting happened, so we go to sleep for a
2191 while. */
2192
2193 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2194 /* nanosleep and go round again */
2195 nanosleep_interval.tv_sec = 0;
2196 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
2197 /* It's critical here that valgrind's nanosleep implementation
2198 is nonblocking. */
2199 (void)my_do_syscall2(__NR_nanosleep,
2200 (int)(&nanosleep_interval), (int)NULL);
2201
2202 /* Sleeping finished. If a finite timeout, check to see if it
2203 has expired yet. */
sewardjf854f472002-04-21 12:19:41 +00002204 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002205 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2206 VG_USERREQ__READ_MILLISECOND_TIMER,
2207 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002208 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002209 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002210 /* timeout; nothing interesting happened. */
2211 for (i = 0; i < __nfds; i++)
2212 __fds[i].revents = 0;
2213 return 0;
2214 }
2215 }
2216
sewardj08a4c3f2002-04-13 03:45:44 +00002217 }
2218}
sewardj3b13f0e2002-04-25 20:17:29 +00002219
2220
sewardj705d3cb2002-05-23 13:13:12 +00002221/* Helper function used to make accept() non-blocking. Idea is to use
2222 the above nonblocking poll() to make this thread ONLY wait for the
2223 specified fd to become ready, and then return. */
sewardjd1c1cf22002-06-26 00:13:36 +00002224
2225/* Sigh -- a hack. We're not supposed to include this file directly;
2226 should do it via /usr/include/fcntl.h, but that introduces a
2227 varargs prototype for fcntl itself, which we can't mimic. */
2228#define _FCNTL_H
2229#include <bits/fcntl.h>
2230
sewardj705d3cb2002-05-23 13:13:12 +00002231static void wait_for_fd_to_be_readable_or_erring ( int fd )
2232{
2233 struct pollfd pfd;
sewardjd1c1cf22002-06-26 00:13:36 +00002234 int res;
2235
sewardj6e6cbaa2002-05-24 02:12:52 +00002236 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardjd1c1cf22002-06-26 00:13:36 +00002237
2238 /* First check to see if the fd is nonblocking, and/or invalid. In
2239 either case return immediately. */
2240 res = __libc_fcntl(fd, F_GETFL, 0);
2241 if (res == -1) return; /* fd is invalid somehow */
2242 if (res & O_NONBLOCK) return; /* fd is nonblocking */
2243
2244 /* Ok, we'd better wait with poll. */
sewardj705d3cb2002-05-23 13:13:12 +00002245 pfd.fd = fd;
2246 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2247 /* ... but not POLLOUT, you may notice. */
2248 pfd.revents = 0;
2249 (void)poll(&pfd, 1, -1 /* forever */);
2250}
2251
2252
sewardj3b13f0e2002-04-25 20:17:29 +00002253/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002254 Hacky implementation of semaphores.
2255 ------------------------------------------------------------------ */
2256
2257#include <semaphore.h>
2258
2259/* This is a terrible way to do the remapping. Plan is to import an
2260 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002261
2262typedef
2263 struct {
2264 pthread_mutex_t se_mx;
2265 pthread_cond_t se_cv;
2266 int count;
2267 }
2268 vg_sem_t;
2269
2270static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2271
2272static int se_remap_used = 0;
2273static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2274static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2275
2276static vg_sem_t* se_remap ( sem_t* orig )
2277{
2278 int res, i;
2279 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002280 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002281
2282 for (i = 0; i < se_remap_used; i++) {
2283 if (se_remap_orig[i] == orig)
2284 break;
2285 }
2286 if (i == se_remap_used) {
2287 if (se_remap_used == VG_N_SEMAPHORES) {
2288 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002289 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002290 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002291 }
2292 se_remap_used++;
2293 se_remap_orig[i] = orig;
2294 /* printf("allocated semaphore %d\n", i); */
2295 }
2296 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002297 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002298 return &se_remap_new[i];
2299}
2300
2301
2302int sem_init(sem_t *sem, int pshared, unsigned int value)
2303{
2304 int res;
2305 vg_sem_t* vg_sem;
2306 ensure_valgrind("sem_init");
2307 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002308 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002309 errno = ENOSYS;
2310 return -1;
2311 }
2312 vg_sem = se_remap(sem);
2313 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002314 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002315 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002316 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002317 vg_sem->count = value;
2318 return 0;
2319}
2320
2321
2322int sem_wait ( sem_t* sem )
2323{
2324 int res;
2325 vg_sem_t* vg_sem;
2326 ensure_valgrind("sem_wait");
2327 vg_sem = se_remap(sem);
2328 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002329 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002330 while (vg_sem->count == 0) {
2331 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002332 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002333 }
2334 vg_sem->count--;
2335 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002336 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002337 return 0;
2338}
2339
2340int sem_post ( sem_t* sem )
2341{
2342 int res;
2343 vg_sem_t* vg_sem;
2344 ensure_valgrind("sem_post");
2345 vg_sem = se_remap(sem);
2346 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002347 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002348 if (vg_sem->count == 0) {
2349 vg_sem->count++;
2350 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002351 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002352 } else {
2353 vg_sem->count++;
2354 }
2355 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002356 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002357 return 0;
2358}
2359
2360
2361int sem_trywait ( sem_t* sem )
2362{
2363 int ret, res;
2364 vg_sem_t* vg_sem;
2365 ensure_valgrind("sem_trywait");
2366 vg_sem = se_remap(sem);
2367 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002368 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002369 if (vg_sem->count > 0) {
2370 vg_sem->count--;
2371 ret = 0;
2372 } else {
2373 ret = -1;
2374 errno = EAGAIN;
2375 }
2376 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002377 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002378 return ret;
2379}
2380
2381
2382int sem_getvalue(sem_t* sem, int * sval)
2383{
2384 vg_sem_t* vg_sem;
2385 ensure_valgrind("sem_trywait");
2386 vg_sem = se_remap(sem);
2387 *sval = vg_sem->count;
2388 return 0;
2389}
2390
2391
2392int sem_destroy(sem_t * sem)
2393{
2394 kludged("sem_destroy");
2395 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2396 return 0;
2397}
2398
2399
2400/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002401 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002402 ------------------------------------------------------------------ */
2403
sewardj2d8b3f02002-06-01 14:14:19 +00002404typedef
2405 struct {
2406 int initted; /* != 0 --> in use; sanity check only */
2407 int prefer_w; /* != 0 --> prefer writer */
2408 int nwait_r; /* # of waiting readers */
2409 int nwait_w; /* # of waiting writers */
2410 pthread_cond_t cv_r; /* for signalling readers */
2411 pthread_cond_t cv_w; /* for signalling writers */
2412 pthread_mutex_t mx;
2413 int status;
2414 /* allowed range for status: >= -1. -1 means 1 writer currently
2415 active, >= 0 means N readers currently active. */
2416 }
2417 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002418
2419
2420static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2421
2422static int rw_remap_used = 0;
2423static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2424static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2425
sewardj2d8b3f02002-06-01 14:14:19 +00002426
2427static
2428void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2429{
2430 int res = 0;
2431 vg_rwl->initted = 1;
2432 vg_rwl->prefer_w = 1;
2433 vg_rwl->nwait_r = 0;
2434 vg_rwl->nwait_w = 0;
2435 vg_rwl->status = 0;
2436 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2437 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2438 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002439 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002440}
2441
2442
sewardja1ac5cb2002-05-27 13:00:05 +00002443/* Take the address of a LinuxThreads rwlock_t and return the shadow
2444 address of our version. Further, if the LinuxThreads version
2445 appears to have been statically initialised, do the same to the one
2446 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2447 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2448 uninitialised and non-zero meaning initialised.
2449*/
2450static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2451{
2452 int res, i;
2453 vg_rwlock_t* vg_rwl;
2454 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002455 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002456
2457 for (i = 0; i < rw_remap_used; i++) {
2458 if (rw_remap_orig[i] == orig)
2459 break;
2460 }
2461 if (i == rw_remap_used) {
2462 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002463 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002464 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002465 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2466 }
2467 rw_remap_used++;
2468 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002469 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002470 if (0) printf("allocated rwlock %d\n", i);
2471 }
2472 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002473 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002474 vg_rwl = &rw_remap_new[i];
2475
sewardj2d8b3f02002-06-01 14:14:19 +00002476 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002477 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002478 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002479 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002480 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002481 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002482 }
2483
2484 return vg_rwl;
2485}
2486
2487
sewardja1ac5cb2002-05-27 13:00:05 +00002488int pthread_rwlock_init ( pthread_rwlock_t* orig,
2489 const pthread_rwlockattr_t* attr )
2490{
sewardja1ac5cb2002-05-27 13:00:05 +00002491 vg_rwlock_t* rwl;
2492 if (0) printf ("pthread_rwlock_init\n");
2493 /* Force the remapper to initialise the shadow. */
2494 orig->__rw_readers = 0;
2495 /* Install the lock preference; the remapper needs to know it. */
2496 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2497 if (attr)
2498 orig->__rw_kind = attr->__lockkind;
2499 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002500 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002501}
2502
sewardj2d8b3f02002-06-01 14:14:19 +00002503
2504static
2505void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002506{
sewardj2d8b3f02002-06-01 14:14:19 +00002507 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2508 rwl->nwait_r--;
2509 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002510}
2511
sewardj2d8b3f02002-06-01 14:14:19 +00002512
sewardja1ac5cb2002-05-27 13:00:05 +00002513int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2514{
2515 int res;
2516 vg_rwlock_t* rwl;
2517 if (0) printf ("pthread_rwlock_rdlock\n");
2518 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002519 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002520 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002521 if (!rwl->initted) {
2522 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002523 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002524 return EINVAL;
2525 }
2526 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002527 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002528 rwl->nwait_r++;
2529 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2530 while (1) {
2531 if (rwl->status == 0) break;
2532 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002533 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002534 }
2535 pthread_cleanup_pop(0);
2536 rwl->nwait_r--;
2537 }
sewardj2d94c112002-06-03 01:25:54 +00002538 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002539 rwl->status++;
2540 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002541 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002542 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002543}
2544
sewardj2d8b3f02002-06-01 14:14:19 +00002545
sewardja1ac5cb2002-05-27 13:00:05 +00002546int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2547{
2548 int res;
2549 vg_rwlock_t* rwl;
2550 if (0) printf ("pthread_rwlock_tryrdlock\n");
2551 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002552 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002553 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002554 if (!rwl->initted) {
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 EINVAL;
2558 }
2559 if (rwl->status == -1) {
2560 /* Writer active; we have to give up. */
2561 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002562 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002563 return EBUSY;
2564 }
2565 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002566 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002567 rwl->status++;
2568 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002569 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002570 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002571}
2572
sewardj2d8b3f02002-06-01 14:14:19 +00002573
2574static
2575void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2576{
2577 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2578 rwl->nwait_w--;
2579 pthread_mutex_unlock (&rwl->mx);
2580}
2581
2582
sewardja1ac5cb2002-05-27 13:00:05 +00002583int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2584{
2585 int res;
2586 vg_rwlock_t* rwl;
2587 if (0) printf ("pthread_rwlock_wrlock\n");
2588 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002589 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002590 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002591 if (!rwl->initted) {
2592 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002593 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002594 return EINVAL;
2595 }
2596 if (rwl->status != 0) {
2597 rwl->nwait_w++;
2598 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2599 while (1) {
2600 if (rwl->status == 0) break;
2601 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002602 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002603 }
2604 pthread_cleanup_pop(0);
2605 rwl->nwait_w--;
2606 }
sewardj2d94c112002-06-03 01:25:54 +00002607 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002608 rwl->status = -1;
2609 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002610 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002611 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002612}
2613
sewardj2d8b3f02002-06-01 14:14:19 +00002614
sewardja1ac5cb2002-05-27 13:00:05 +00002615int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2616{
2617 int res;
2618 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002619 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002620 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002621 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002622 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002623 if (!rwl->initted) {
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 EINVAL;
2627 }
2628 if (rwl->status != 0) {
2629 /* Reader(s) or a writer active; we have to give up. */
2630 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002631 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002632 return EBUSY;
2633 }
2634 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002635 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002636 rwl->status = -1;
2637 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002638 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002639 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002640}
2641
sewardj2d8b3f02002-06-01 14:14:19 +00002642
sewardja1ac5cb2002-05-27 13:00:05 +00002643int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2644{
2645 int res;
2646 vg_rwlock_t* rwl;
2647 if (0) printf ("pthread_rwlock_unlock\n");
2648 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002649 rwl = rw_remap ( orig );
2650 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002651 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002652 if (!rwl->initted) {
2653 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002654 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002655 return EINVAL;
2656 }
2657 if (rwl->status == 0) {
2658 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002659 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002660 return EPERM;
2661 }
sewardj2d94c112002-06-03 01:25:54 +00002662 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002663 if (rwl->status == -1) {
2664 rwl->status = 0;
2665 } else {
sewardj2d94c112002-06-03 01:25:54 +00002666 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002667 rwl->status--;
2668 }
2669
sewardj2d94c112002-06-03 01:25:54 +00002670 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002671
2672 if (rwl->prefer_w) {
2673
2674 /* Favour waiting writers, if any. */
2675 if (rwl->nwait_w > 0) {
2676 /* Writer(s) are waiting. */
2677 if (rwl->status == 0) {
2678 /* We can let a writer in. */
2679 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002680 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002681 } else {
2682 /* There are still readers active. Do nothing; eventually
2683 they will disappear, at which point a writer will be
2684 admitted. */
2685 }
2686 }
2687 else
2688 /* No waiting writers. */
2689 if (rwl->nwait_r > 0) {
2690 /* Let in a waiting reader. */
2691 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002692 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002693 }
2694
2695 } else {
2696
2697 /* Favour waiting readers, if any. */
2698 if (rwl->nwait_r > 0) {
2699 /* Reader(s) are waiting; let one in. */
2700 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002701 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002702 }
2703 else
2704 /* No waiting readers. */
2705 if (rwl->nwait_w > 0 && rwl->status == 0) {
2706 /* We have waiting writers and no active readers; let a
2707 writer in. */
2708 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002709 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002710 }
2711 }
2712
2713 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002714 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002715 return 0;
2716}
2717
2718
2719int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2720{
2721 int res;
2722 vg_rwlock_t* rwl;
2723 if (0) printf ("pthread_rwlock_destroy\n");
2724 rwl = rw_remap ( orig );
2725 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002726 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002727 if (!rwl->initted) {
2728 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002729 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002730 return EINVAL;
2731 }
2732 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2733 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002734 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002735 return EBUSY;
2736 }
2737 rwl->initted = 0;
2738 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002739 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002740 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002741}
2742
2743
sewardj47e4e312002-06-18 09:24:34 +00002744/* Copied directly from LinuxThreads. */
2745int
2746pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
2747{
2748 attr->__lockkind = 0;
2749 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
2750
2751 return 0;
2752}
2753
sewardjfe18eb82002-07-13 12:58:44 +00002754/* Copied directly from LinuxThreads. */
2755int
2756pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
2757{
2758 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
2759 return EINVAL;
2760
2761 /* For now it is not possible to shared a conditional variable. */
2762 if (pshared != PTHREAD_PROCESS_PRIVATE)
2763 return ENOSYS;
2764
2765 attr->__pshared = pshared;
2766
2767 return 0;
2768}
2769
sewardj47e4e312002-06-18 09:24:34 +00002770
sewardja1ac5cb2002-05-27 13:00:05 +00002771/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002772 B'stard.
2773 ------------------------------------------------------------------ */
2774
2775# define strong_alias(name, aliasname) \
2776 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2777
sewardj5905fae2002-04-26 13:25:00 +00002778# define weak_alias(name, aliasname) \
2779 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002780
sewardj5905fae2002-04-26 13:25:00 +00002781strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2782strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2783strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2784strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2785 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2786strong_alias(__pthread_mutex_init, pthread_mutex_init)
2787strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2788strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2789strong_alias(__pthread_once, pthread_once)
2790strong_alias(__pthread_atfork, pthread_atfork)
2791strong_alias(__pthread_key_create, pthread_key_create)
2792strong_alias(__pthread_getspecific, pthread_getspecific)
2793strong_alias(__pthread_setspecific, pthread_setspecific)
2794
sewardjd529a442002-05-04 19:49:21 +00002795#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002796strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002797#endif
2798
sewardj5905fae2002-04-26 13:25:00 +00002799strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002800strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002801strong_alias(lseek, __lseek)
2802strong_alias(open, __open)
2803strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002804strong_alias(read, __read)
2805strong_alias(wait, __wait)
2806strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002807strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002808strong_alias(send, __send)
2809
sewardj726c4122002-05-16 23:39:10 +00002810weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002811weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002812weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002813
sewardjf0b06452002-06-04 08:38:04 +00002814weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00002815
2816/*--------------------------------------------------*/
2817
sewardj5905fae2002-04-26 13:25:00 +00002818weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002819weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002820weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002821
sewardja1ac5cb2002-05-27 13:00:05 +00002822weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2823weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2824weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2825weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2826
sewardj060b04f2002-04-26 21:01:13 +00002827
sewardj3b13f0e2002-04-25 20:17:29 +00002828/* I've no idea what these are, but they get called quite a lot.
2829 Anybody know? */
2830
2831#undef _IO_flockfile
2832void _IO_flockfile ( _IO_FILE * file )
2833{
sewardj853f55d2002-04-26 00:27:53 +00002834 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002835}
sewardj5905fae2002-04-26 13:25:00 +00002836weak_alias(_IO_flockfile, flockfile);
2837
sewardj3b13f0e2002-04-25 20:17:29 +00002838
2839#undef _IO_funlockfile
2840void _IO_funlockfile ( _IO_FILE * file )
2841{
sewardj853f55d2002-04-26 00:27:53 +00002842 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002843}
sewardj5905fae2002-04-26 13:25:00 +00002844weak_alias(_IO_funlockfile, funlockfile);
2845
sewardj3b13f0e2002-04-25 20:17:29 +00002846
sewardjd4f2c712002-04-30 10:20:10 +00002847/* This doesn't seem to be needed to simulate libpthread.so's external
2848 interface, but many people complain about its absence. */
2849
2850strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2851weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002852
2853
2854/*--------------------------------------------------------------------*/
2855/*--- end vg_libpthread.c ---*/
2856/*--------------------------------------------------------------------*/