blob: 600d19842f539e90d2afad24c2a2cf52d496e0c4 [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/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardj439d45e2002-05-03 20:43:10 +000010
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
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardj439d45e2002-05-03 20:43:10 +000030*/
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
sewardjf912dfc2002-11-13 21:51:10 +000068#include <sys/stat.h>
69#include <sys/poll.h>
sewardj2d94c112002-06-03 01:25:54 +000070#include <stdio.h>
71
sewardj705d3cb2002-05-23 13:13:12 +000072
73/* ---------------------------------------------------------------------
74 Forwardses.
75 ------------------------------------------------------------------ */
76
77static void wait_for_fd_to_be_readable_or_erring ( int fd );
78
sewardj9a2224b2002-06-19 10:17:40 +000079static
sewardj08c7f012002-10-07 23:56:55 +000080int my_do_syscall1 ( int syscallno, int arg1 );
81
82static
sewardj9a2224b2002-06-19 10:17:40 +000083int my_do_syscall2 ( int syscallno,
84 int arg1, int arg2 );
85
sewardj08c7f012002-10-07 23:56:55 +000086static
87int my_do_syscall3 ( int syscallno,
88 int arg1, int arg2, int arg3 );
89
90
91#ifdef GLIBC_2_3
92 /* kludge by JRS (not from glibc) ... */
93 typedef void* __locale_t;
94
95 /* Copied from locale/locale.h in glibc-2.2.93 sources */
96 /* This value can be passed to `uselocale' and may be returned by
97 it. Passing this value to any other function has undefined
98 behavior. */
99# define LC_GLOBAL_LOCALE ((__locale_t) -1L)
100 extern __locale_t __uselocale ( __locale_t );
101#endif
102
sewardj00a66b12002-10-12 16:42:35 +0000103static
104void init_libc_tsd_keys ( void );
105
sewardj705d3cb2002-05-23 13:13:12 +0000106
sewardje663cb92002-04-12 10:26:32 +0000107/* ---------------------------------------------------------------------
108 Helpers. We have to be pretty self-sufficient.
109 ------------------------------------------------------------------ */
110
sewardj436e0582002-04-26 14:31:40 +0000111/* Number of times any given error message is printed. */
112#define N_MOANS 3
113
sewardj45b4b372002-04-16 22:50:32 +0000114/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
115 Returns 0 (none) if not running on Valgrind. */
116static
117int get_pt_trace_level ( void )
118{
119 int res;
120 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
121 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
122 0, 0, 0, 0);
123 return res;
124}
125
sewardje663cb92002-04-12 10:26:32 +0000126static
sewardj2d94c112002-06-03 01:25:54 +0000127void my_exit ( int arg )
sewardje663cb92002-04-12 10:26:32 +0000128{
sewardj08c7f012002-10-07 23:56:55 +0000129 my_do_syscall1(__NR_exit, arg);
130 /*NOTREACHED*/
sewardje663cb92002-04-12 10:26:32 +0000131}
132
sewardj08c7f012002-10-07 23:56:55 +0000133static
134void my_write ( int fd, const void *buf, int count )
135{
136 my_do_syscall3(__NR_write, fd, (int)buf, count );
137}
sewardje663cb92002-04-12 10:26:32 +0000138
sewardj68b2dd92002-05-10 21:03:56 +0000139/* We need this guy -- it's in valgrind.so. */
140extern void VG_(startup) ( void );
141
142
143/* Just start up Valgrind if it's not already going. VG_(startup)()
144 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000145static __inline__
sewardje663cb92002-04-12 10:26:32 +0000146void ensure_valgrind ( char* caller )
147{
sewardj68b2dd92002-05-10 21:03:56 +0000148 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000149}
150
sewardjbea1caa2002-05-10 23:20:58 +0000151/* While we're at it ... hook our own startup function into this
152 game. */
153__asm__ (
154 ".section .init\n"
155 "\tcall vgPlain_startup"
156);
157
sewardje663cb92002-04-12 10:26:32 +0000158
159static
sewardj3b5d8862002-04-20 13:53:23 +0000160__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +0000161void barf ( char* str )
162{
sewardj69a72a52002-11-03 13:41:41 +0000163 int res;
164 char buf[1000];
sewardje663cb92002-04-12 10:26:32 +0000165 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000166 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000167 strcat(buf, str);
168 strcat(buf, "\n\n");
sewardj69a72a52002-11-03 13:41:41 +0000169 VALGRIND_MAGIC_SEQUENCE(res, 0, /* irrelevant default */
170 VG_USERREQ__LOGMESSAGE, buf, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000171 my_exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000172 /* We have to persuade gcc into believing this doesn't return. */
173 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000174}
175
176
sewardj69a72a52002-11-03 13:41:41 +0000177static void cat_n_send ( char* pre, char* msg )
sewardj2a3d28c2002-04-14 13:27:00 +0000178{
sewardj69a72a52002-11-03 13:41:41 +0000179 char buf[1000];
180 int res;
sewardj436e0582002-04-26 14:31:40 +0000181 if (get_pt_trace_level() >= 0) {
sewardj69a72a52002-11-03 13:41:41 +0000182 snprintf(buf, sizeof(buf), "%s%s", pre, msg );
183 buf[sizeof(buf)-1] = '\0';
184 VALGRIND_MAGIC_SEQUENCE(res, 0, /* irrelevant default */
185 VG_USERREQ__LOGMESSAGE, buf, 0, 0, 0);
sewardj45b4b372002-04-16 22:50:32 +0000186 }
sewardj2a3d28c2002-04-14 13:27:00 +0000187}
188
sewardj69a72a52002-11-03 13:41:41 +0000189static void ignored ( char* msg )
190{
191 cat_n_send ( "valgrind's libpthread.so: IGNORED call to: ", msg );
192}
193
194
sewardj30671ff2002-04-21 00:13:57 +0000195static void kludged ( char* msg )
196{
sewardj69a72a52002-11-03 13:41:41 +0000197 cat_n_send ( "valgrind's libpthread.so: KLUDGED call to: ", msg );
sewardj439d45e2002-05-03 20:43:10 +0000198}
199
sewardj69a72a52002-11-03 13:41:41 +0000200
sewardjccef2e62002-05-29 19:26:32 +0000201__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000202void vgPlain_unimp ( char* what )
203{
sewardj69a72a52002-11-03 13:41:41 +0000204 cat_n_send (
205 "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ", what );
sewardj3b13f0e2002-04-25 20:17:29 +0000206 barf("Please report this bug to me at: jseward@acm.org");
207}
208
sewardje663cb92002-04-12 10:26:32 +0000209
sewardj457cc472002-06-03 23:13:47 +0000210static
sewardj2d94c112002-06-03 01:25:54 +0000211void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
212{
sewardj69a72a52002-11-03 13:41:41 +0000213 char buf[1000];
sewardj2d94c112002-06-03 01:25:54 +0000214 static Bool entered = False;
215 if (entered)
216 my_exit(2);
217 entered = True;
sewardj69a72a52002-11-03 13:41:41 +0000218 sprintf(buf, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
219 "valgrind", file, line, fn, expr );
220 cat_n_send ( "", buf );
221 sprintf(buf, "Please report this bug to me at: %s\n\n",
222 VG_EMAIL_ADDR);
223 cat_n_send ( "", buf );
sewardj2d94c112002-06-03 01:25:54 +0000224 my_exit(1);
225}
226
227#define MY__STRING(__str) #__str
228
229#define my_assert(expr) \
230 ((void) ((expr) ? 0 : \
231 (my_assert_fail (MY__STRING(expr), \
232 __FILE__, __LINE__, \
233 __PRETTY_FUNCTION__), 0)))
234
sewardj00a66b12002-10-12 16:42:35 +0000235static
236void my_free ( void* ptr )
237{
238 int res;
239 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
240 VG_USERREQ__FREE, ptr, 0, 0, 0);
241 my_assert(res == 0);
242}
243
244
245static
246void* my_malloc ( int nbytes )
247{
248 void* res;
249 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
250 VG_USERREQ__MALLOC, nbytes, 0, 0, 0);
251 my_assert(res != (void*)0);
252 return res;
253}
254
255
sewardj2d94c112002-06-03 01:25:54 +0000256
sewardje663cb92002-04-12 10:26:32 +0000257/* ---------------------------------------------------------------------
258 Pass pthread_ calls to Valgrind's request mechanism.
259 ------------------------------------------------------------------ */
260
sewardjf8f819e2002-04-17 23:21:37 +0000261#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000262#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000263
sewardja1ac5cb2002-05-27 13:00:05 +0000264
sewardjf8f819e2002-04-17 23:21:37 +0000265/* ---------------------------------------------------
sewardj4dced352002-06-04 22:54:20 +0000266 Ummm ..
267 ------------------------------------------------ */
268
269static
270void pthread_error ( const char* msg )
271{
272 int res;
273 VALGRIND_MAGIC_SEQUENCE(res, 0,
274 VG_USERREQ__PTHREAD_ERROR,
275 msg, 0, 0, 0);
276}
277
278
279/* ---------------------------------------------------
sewardj00a66b12002-10-12 16:42:35 +0000280 Here so it can be inlined without complaint.
281 ------------------------------------------------ */
282
283__inline__
284pthread_t pthread_self(void)
285{
286 int tid;
287 ensure_valgrind("pthread_self");
288 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
289 VG_USERREQ__PTHREAD_GET_THREADID,
290 0, 0, 0, 0);
291 if (tid < 1 || tid >= VG_N_THREADS)
292 barf("pthread_self: invalid ThreadId");
293 return tid;
294}
295
296
297/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000298 THREAD ATTRIBUTES
299 ------------------------------------------------ */
300
sewardj6af4b5d2002-04-16 04:40:49 +0000301int pthread_attr_init(pthread_attr_t *attr)
302{
sewardj7989d0c2002-05-28 11:00:01 +0000303 /* Just initialise the fields which we might look at. */
304 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj111b14c2002-10-20 16:22:57 +0000305 /* Linuxthreads sets this field to the value __getpagesize(), so I
306 guess the following is OK. */
307 attr->__guardsize = VKI_BYTES_PER_PAGE; return 0;
sewardj6af4b5d2002-04-16 04:40:49 +0000308}
309
310int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
311{
sewardj7989d0c2002-05-28 11:00:01 +0000312 if (detachstate != PTHREAD_CREATE_JOINABLE
sewardj4dced352002-06-04 22:54:20 +0000313 && detachstate != PTHREAD_CREATE_DETACHED) {
314 pthread_error("pthread_attr_setdetachstate: "
315 "detachstate is invalid");
sewardj7989d0c2002-05-28 11:00:01 +0000316 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000317 }
sewardj7989d0c2002-05-28 11:00:01 +0000318 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000319 return 0;
320}
321
njn25e49d8e72002-09-23 09:36:25 +0000322int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
323{
324 *detachstate = attr->__detachstate;
325 return 0;
326}
327
sewardj30671ff2002-04-21 00:13:57 +0000328int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
329{
sewardj436e0582002-04-26 14:31:40 +0000330 static int moans = N_MOANS;
331 if (moans-- > 0)
332 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000333 return 0;
334}
sewardj6af4b5d2002-04-16 04:40:49 +0000335
sewardj0286dd52002-05-16 20:51:15 +0000336__attribute__((weak))
337int pthread_attr_setstacksize (pthread_attr_t *__attr,
338 size_t __stacksize)
339{
sewardja18e2102002-05-18 10:43:22 +0000340 size_t limit;
sewardj3d7c8d62002-06-04 20:59:16 +0000341 char buf[1024];
sewardj0286dd52002-05-16 20:51:15 +0000342 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000343 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
344 - 1000; /* paranoia */
345 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000346 return 0;
sewardj3d7c8d62002-06-04 20:59:16 +0000347 snprintf(buf, sizeof(buf), "pthread_attr_setstacksize: "
348 "requested size %d >= VG_PTHREAD_STACK_SIZE\n "
349 "edit vg_include.h and rebuild.", __stacksize);
350 buf[sizeof(buf)-1] = '\0'; /* Make sure it is zero terminated */
351 barf(buf);
sewardj0286dd52002-05-16 20:51:15 +0000352}
353
354
sewardj30671ff2002-04-21 00:13:57 +0000355/* This is completely bogus. */
356int pthread_attr_getschedparam(const pthread_attr_t *attr,
357 struct sched_param *param)
358{
sewardj436e0582002-04-26 14:31:40 +0000359 static int moans = N_MOANS;
360 if (moans-- > 0)
361 kludged("pthread_attr_getschedparam");
sewardj3e909ce2002-06-03 13:27:15 +0000362# ifdef HAVE_SCHED_PRIORITY
sewardj72d58482002-04-24 02:20:20 +0000363 if (param) param->sched_priority = 0; /* who knows */
364# else
sewardj30671ff2002-04-21 00:13:57 +0000365 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000366# endif
sewardj30671ff2002-04-21 00:13:57 +0000367 return 0;
368}
369
370int pthread_attr_setschedparam(pthread_attr_t *attr,
371 const struct sched_param *param)
372{
sewardj436e0582002-04-26 14:31:40 +0000373 static int moans = N_MOANS;
374 if (moans-- > 0)
375 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000376 return 0;
377}
378
379int pthread_attr_destroy(pthread_attr_t *attr)
380{
sewardj436e0582002-04-26 14:31:40 +0000381 static int moans = N_MOANS;
382 if (moans-- > 0)
383 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000384 return 0;
385}
sewardjf8f819e2002-04-17 23:21:37 +0000386
sewardj0d844232002-06-02 09:29:31 +0000387/* These are no-ops, as with LinuxThreads. */
388int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
389{
390 ensure_valgrind("pthread_attr_setscope");
391 if (scope == PTHREAD_SCOPE_SYSTEM)
392 return 0;
sewardj4dced352002-06-04 22:54:20 +0000393 pthread_error("pthread_attr_setscope: "
394 "invalid or unsupported scope");
sewardj0d844232002-06-02 09:29:31 +0000395 if (scope == PTHREAD_SCOPE_PROCESS)
396 return ENOTSUP;
397 return EINVAL;
398}
399
400int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
401{
402 ensure_valgrind("pthread_attr_setscope");
403 if (scope)
404 *scope = PTHREAD_SCOPE_SYSTEM;
405 return 0;
406}
407
sewardj64039bb2002-06-03 00:58:18 +0000408
409/* Pretty bogus. Avoid if possible. */
410int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
411{
412 int detached;
413 size_t limit;
414 ensure_valgrind("pthread_getattr_np");
415 kludged("pthread_getattr_np");
416 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
417 - 1000; /* paranoia */
418 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
419 attr->__schedpolicy = SCHED_OTHER;
420 attr->__schedparam.sched_priority = 0;
421 attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
422 attr->__scope = PTHREAD_SCOPE_SYSTEM;
423 attr->__guardsize = VKI_BYTES_PER_PAGE;
424 attr->__stackaddr = NULL;
425 attr->__stackaddr_set = 0;
426 attr->__stacksize = limit;
427 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
428 VG_USERREQ__SET_OR_GET_DETACH,
429 2 /* get */, thread, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000430 my_assert(detached == 0 || detached == 1);
sewardj64039bb2002-06-03 00:58:18 +0000431 if (detached)
432 attr->__detachstate = PTHREAD_CREATE_DETACHED;
433 return 0;
434}
435
436
437/* Bogus ... */
sewardj111b14c2002-10-20 16:22:57 +0000438__attribute__((weak))
sewardj64039bb2002-06-03 00:58:18 +0000439int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
440 void ** stackaddr )
441{
442 ensure_valgrind("pthread_attr_getstackaddr");
443 kludged("pthread_attr_getstackaddr");
444 if (stackaddr)
445 *stackaddr = NULL;
446 return 0;
447}
448
449/* Not bogus (!) */
sewardj111b14c2002-10-20 16:22:57 +0000450__attribute__((weak))
sewardj64039bb2002-06-03 00:58:18 +0000451int pthread_attr_getstacksize ( const pthread_attr_t * _attr,
452 size_t * __stacksize )
453{
454 size_t limit;
455 ensure_valgrind("pthread_attr_getstacksize");
456 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
457 - 1000; /* paranoia */
458 if (__stacksize)
459 *__stacksize = limit;
460 return 0;
461}
462
sewardja3be12f2002-06-17 12:19:44 +0000463int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
464{
465 if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
466 return EINVAL;
467 attr->__schedpolicy = policy;
468 return 0;
469}
470
471int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
472{
473 *policy = attr->__schedpolicy;
474 return 0;
475}
476
477
sewardj111b14c2002-10-20 16:22:57 +0000478/* This is completely bogus. We reject all attempts to change it from
479 VKI_BYTES_PER_PAGE. I don't have a clue what it's for so it seems
480 safest to be paranoid. */
481__attribute__((weak))
482int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
483{
484 static int moans = N_MOANS;
485
486 if (guardsize == VKI_BYTES_PER_PAGE)
487 return 0;
488
489 if (moans-- > 0)
490 ignored("pthread_attr_setguardsize: ignoring guardsize != 4096");
491
492 return 0;
493}
494
495/* A straight copy of the LinuxThreads code. */
496__attribute__((weak))
497int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
498{
499 *guardsize = attr->__guardsize;
500 return 0;
501}
502
503
sewardj20917d82002-05-28 01:36:45 +0000504/* ---------------------------------------------------
505 Helper functions for running a thread
506 and for clearing up afterwards.
507 ------------------------------------------------ */
508
509/* All exiting threads eventually pass through here, bearing the
510 return value, or PTHREAD_CANCELED, in ret_val. */
511static
512__attribute__((noreturn))
513void thread_exit_wrapper ( void* ret_val )
514{
sewardj870497a2002-05-29 01:06:47 +0000515 int detached, res;
516 CleanupEntry cu;
517 pthread_key_t key;
sewardj00a66b12002-10-12 16:42:35 +0000518 void** specifics_ptr;
sewardj870497a2002-05-29 01:06:47 +0000519
sewardj20917d82002-05-28 01:36:45 +0000520 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000521 while (1) {
522 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
523 VG_USERREQ__CLEANUP_POP,
524 &cu, 0, 0, 0);
525 if (res == -1) break; /* stack empty */
sewardj2d94c112002-06-03 01:25:54 +0000526 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000527 if (0) printf("running exit cleanup handler");
528 cu.fn ( cu.arg );
529 }
530
sewardj870497a2002-05-29 01:06:47 +0000531 /* Run this thread's key finalizers. Really this should be run
532 PTHREAD_DESTRUCTOR_ITERATIONS times. */
533 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
534 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
535 VG_USERREQ__GET_KEY_D_AND_S,
536 key, &cu, 0, 0 );
537 if (res == 0) {
538 /* valid key */
539 if (cu.fn && cu.arg)
540 cu.fn /* destructor for key */
541 ( cu.arg /* specific for key for this thread */ );
542 continue;
543 }
sewardj2d94c112002-06-03 01:25:54 +0000544 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000545 }
sewardj20917d82002-05-28 01:36:45 +0000546
sewardj00a66b12002-10-12 16:42:35 +0000547 /* Free up my specifics space, if any. */
548 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
549 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
550 pthread_self(), 0, 0, 0);
551 my_assert(specifics_ptr != (void**)3);
552 my_assert(specifics_ptr != (void**)1); /* 1 means invalid thread */
553 if (specifics_ptr != NULL)
554 my_free(specifics_ptr);
555
sewardj20917d82002-05-28 01:36:45 +0000556 /* Decide on my final disposition. */
557 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
558 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000559 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000560 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000561
562 if (detached) {
563 /* Detached; I just quit right now. */
564 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
565 VG_USERREQ__QUIT, 0, 0, 0, 0);
566 } else {
567 /* Not detached; so I wait for a joiner. */
568 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
569 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
570 }
571 /* NOTREACHED */
572 barf("thread_exit_wrapper: still alive?!");
573}
574
575
576/* This function is a wrapper function for running a thread. It runs
577 the root function specified in pthread_create, and then, should the
578 root function return a value, it arranges to run the thread's
579 cleanup handlers and exit correctly. */
580
sewardj728a5272002-06-20 10:25:37 +0000581/* Struct used to convey info from pthread_create to thread_wrapper.
582 Must be careful not to pass to the child thread any pointers to
583 objects which might be on the parent's stack. */
sewardj20917d82002-05-28 01:36:45 +0000584typedef
585 struct {
sewardj728a5272002-06-20 10:25:37 +0000586 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000587 void* (*root_fn) ( void* );
588 void* arg;
589 }
590 NewThreadInfo;
591
592
593/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
594 not return. Note that this runs in the new thread, not the
595 parent. */
596static
597__attribute__((noreturn))
598void thread_wrapper ( NewThreadInfo* info )
599{
sewardj728a5272002-06-20 10:25:37 +0000600 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000601 void* (*root_fn) ( void* );
602 void* arg;
603 void* ret_val;
604
sewardj728a5272002-06-20 10:25:37 +0000605 attr__detachstate = info->attr__detachstate;
606 root_fn = info->root_fn;
607 arg = info->arg;
sewardj20917d82002-05-28 01:36:45 +0000608
sewardj20917d82002-05-28 01:36:45 +0000609 /* Free up the arg block that pthread_create malloced. */
sewardj00a66b12002-10-12 16:42:35 +0000610 my_free(info);
sewardj20917d82002-05-28 01:36:45 +0000611
sewardj7989d0c2002-05-28 11:00:01 +0000612 /* Minimally observe the attributes supplied. */
sewardj728a5272002-06-20 10:25:37 +0000613 if (attr__detachstate != PTHREAD_CREATE_DETACHED
614 && attr__detachstate != PTHREAD_CREATE_JOINABLE)
615 pthread_error("thread_wrapper: invalid attr->__detachstate");
616 if (attr__detachstate == PTHREAD_CREATE_DETACHED)
617 pthread_detach(pthread_self());
sewardj7989d0c2002-05-28 11:00:01 +0000618
sewardj00a66b12002-10-12 16:42:35 +0000619# ifdef GLIBC_2_3
620 /* Set this thread's locale to the global (default) locale. A hack
621 in support of glibc-2.3. This does the biz for the all new
622 threads; the root thread is done with a horrible hack in
623 init_libc_tsd_keys() below.
624 */
625 __uselocale(LC_GLOBAL_LOCALE);
626# endif
627
sewardj20917d82002-05-28 01:36:45 +0000628 /* The root function might not return. But if it does we simply
629 move along to thread_exit_wrapper. All other ways out for the
630 thread (cancellation, or calling pthread_exit) lead there
631 too. */
632 ret_val = root_fn(arg);
633 thread_exit_wrapper(ret_val);
634 /* NOTREACHED */
635}
636
637
sewardjf8f819e2002-04-17 23:21:37 +0000638/* ---------------------------------------------------
639 THREADs
640 ------------------------------------------------ */
641
sewardjff42d1d2002-05-22 13:17:31 +0000642__attribute__((weak))
643int pthread_yield ( void )
644{
645 int res;
646 ensure_valgrind("pthread_yield");
647 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
648 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
649 return 0;
650}
651
652
sewardj6072c362002-04-19 14:40:57 +0000653int pthread_equal(pthread_t thread1, pthread_t thread2)
654{
655 return thread1 == thread2 ? 1 : 0;
656}
657
658
sewardj20917d82002-05-28 01:36:45 +0000659/* Bundle up the args into a malloc'd block and create a new thread
660 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000661int
sewardj1462c8b2002-07-24 09:41:52 +0000662pthread_create (pthread_t *__restrict __thredd,
sewardje663cb92002-04-12 10:26:32 +0000663 __const pthread_attr_t *__restrict __attr,
664 void *(*__start_routine) (void *),
665 void *__restrict __arg)
666{
sewardj20917d82002-05-28 01:36:45 +0000667 int tid_child;
668 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000669
sewardj20917d82002-05-28 01:36:45 +0000670 ensure_valgrind("pthread_create");
671
sewardj00a66b12002-10-12 16:42:35 +0000672 /* make sure the tsd keys, and hence locale info, are initialised
673 before we get into complications making new threads. */
674 init_libc_tsd_keys();
675
sewardj20917d82002-05-28 01:36:45 +0000676 /* Allocate space for the arg block. thread_wrapper will free
677 it. */
sewardj00a66b12002-10-12 16:42:35 +0000678 info = my_malloc(sizeof(NewThreadInfo));
sewardj2d94c112002-06-03 01:25:54 +0000679 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000680
sewardj728a5272002-06-20 10:25:37 +0000681 if (__attr)
682 info->attr__detachstate = __attr->__detachstate;
683 else
684 info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
685
sewardj20917d82002-05-28 01:36:45 +0000686 info->root_fn = __start_routine;
687 info->arg = __arg;
688 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
689 VG_USERREQ__APPLY_IN_NEW_THREAD,
690 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000691 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000692
sewardj1462c8b2002-07-24 09:41:52 +0000693 if (__thredd)
694 *__thredd = tid_child;
sewardj20917d82002-05-28 01:36:45 +0000695 return 0; /* success */
696}
sewardje663cb92002-04-12 10:26:32 +0000697
698
699int
700pthread_join (pthread_t __th, void **__thread_return)
701{
702 int res;
703 ensure_valgrind("pthread_join");
704 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
705 VG_USERREQ__PTHREAD_JOIN,
706 __th, __thread_return, 0, 0);
707 return res;
708}
709
710
sewardj3b5d8862002-04-20 13:53:23 +0000711void pthread_exit(void *retval)
712{
sewardj3b5d8862002-04-20 13:53:23 +0000713 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000714 /* Simple! */
715 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000716}
717
sewardje663cb92002-04-12 10:26:32 +0000718
sewardj853f55d2002-04-26 00:27:53 +0000719int pthread_detach(pthread_t th)
720{
sewardj20917d82002-05-28 01:36:45 +0000721 int res;
722 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000723 /* First we enquire as to the current detach state. */
724 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000725 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000726 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000727 if (res == -1) {
728 /* not found */
729 pthread_error("pthread_detach: "
730 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000731 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000732 }
733 if (res == 1) {
734 /* already detached */
735 pthread_error("pthread_detach: "
736 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000737 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000738 }
sewardj7989d0c2002-05-28 11:00:01 +0000739 if (res == 0) {
740 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
741 VG_USERREQ__SET_OR_GET_DETACH,
742 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000743 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000744 return 0;
745 }
746 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000747}
748
749
sewardjf8f819e2002-04-17 23:21:37 +0000750/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000751 CLEANUP STACKS
752 ------------------------------------------------ */
753
754void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
755 void (*__routine) (void *),
756 void *__arg)
757{
758 int res;
759 CleanupEntry cu;
760 ensure_valgrind("_pthread_cleanup_push");
761 cu.fn = __routine;
762 cu.arg = __arg;
763 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
764 VG_USERREQ__CLEANUP_PUSH,
765 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000766 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000767}
768
769
770void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
771 void (*__routine) (void *),
772 void *__arg)
773{
774 /* As _pthread_cleanup_push, but first save the thread's original
775 cancellation type in __buffer and set it to Deferred. */
776 int orig_ctype;
777 ensure_valgrind("_pthread_cleanup_push_defer");
778 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000779 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
780 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
781 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000782 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
783 VG_USERREQ__SET_CANCELTYPE,
784 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000785 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000786 *((int*)(__buffer)) = orig_ctype;
787 /* Now push the cleanup. */
788 _pthread_cleanup_push(NULL, __routine, __arg);
789}
790
791
792void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
793 int __execute)
794{
795 int res;
796 CleanupEntry cu;
797 ensure_valgrind("_pthread_cleanup_push");
798 cu.fn = cu.arg = NULL; /* paranoia */
799 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
800 VG_USERREQ__CLEANUP_POP,
801 &cu, 0, 0, 0);
802 if (res == 0) {
803 /* pop succeeded */
804 if (__execute) {
805 cu.fn ( cu.arg );
806 }
807 return;
808 }
809 if (res == -1) {
810 /* stack underflow */
811 return;
812 }
813 barf("_pthread_cleanup_pop");
814}
815
816
817void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
818 int __execute)
819{
820 int orig_ctype, fake_ctype;
821 /* As _pthread_cleanup_pop, but after popping/running the handler,
822 restore the thread's original cancellation type from the first
823 word of __buffer. */
824 _pthread_cleanup_pop(NULL, __execute);
825 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000826 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000827 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000828 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
829 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
830 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000831 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
832 VG_USERREQ__SET_CANCELTYPE,
833 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000834 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000835}
836
837
838/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000839 MUTEX ATTRIBUTES
840 ------------------------------------------------ */
841
sewardj5905fae2002-04-26 13:25:00 +0000842int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000843{
sewardjf8f819e2002-04-17 23:21:37 +0000844 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000845 return 0;
sewardje663cb92002-04-12 10:26:32 +0000846}
847
sewardj5905fae2002-04-26 13:25:00 +0000848int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000849{
850 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000851# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000852 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000853 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000854# endif
sewardja1679dd2002-05-10 22:31:40 +0000855# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000856 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000857# endif
sewardjf8f819e2002-04-17 23:21:37 +0000858 case PTHREAD_MUTEX_RECURSIVE_NP:
859 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000860 attr->__mutexkind = type;
861 return 0;
862 default:
sewardj4dced352002-06-04 22:54:20 +0000863 pthread_error("pthread_mutexattr_settype: "
864 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000865 return EINVAL;
866 }
867}
868
sewardj5905fae2002-04-26 13:25:00 +0000869int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000870{
871 return 0;
872}
873
874
875/* ---------------------------------------------------
876 MUTEXes
877 ------------------------------------------------ */
878
sewardj5905fae2002-04-26 13:25:00 +0000879int __pthread_mutex_init(pthread_mutex_t *mutex,
880 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000881{
sewardj604ec3c2002-04-18 22:38:41 +0000882 mutex->__m_count = 0;
883 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
884 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
885 if (mutexattr)
886 mutex->__m_kind = mutexattr->__mutexkind;
887 return 0;
sewardje663cb92002-04-12 10:26:32 +0000888}
889
sewardj439d45e2002-05-03 20:43:10 +0000890
sewardj5905fae2002-04-26 13:25:00 +0000891int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000892{
893 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000894
sewardj439d45e2002-05-03 20:43:10 +0000895 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000896 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
897 VG_USERREQ__PTHREAD_MUTEX_LOCK,
898 mutex, 0, 0, 0);
899 return res;
sewardj439d45e2002-05-03 20:43:10 +0000900 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000901 /* Play at locking */
902 if (0)
903 kludged("prehistoric lock");
904 mutex->__m_owner = (_pthread_descr)1;
905 mutex->__m_count = 1;
906 mutex->__m_kind |= VG_PTHREAD_PREHISTORY;
sewardj439d45e2002-05-03 20:43:10 +0000907 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000908 }
909}
910
sewardj439d45e2002-05-03 20:43:10 +0000911
sewardj5905fae2002-04-26 13:25:00 +0000912int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000913{
914 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000915
sewardj439d45e2002-05-03 20:43:10 +0000916 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000917 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
918 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
919 mutex, 0, 0, 0);
920 return res;
sewardj439d45e2002-05-03 20:43:10 +0000921 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000922 /* Play at locking */
923 if (0)
924 kludged("prehistoric trylock");
925 mutex->__m_owner = (_pthread_descr)1;
926 mutex->__m_count = 1;
927 mutex->__m_kind |= VG_PTHREAD_PREHISTORY;
928 return 0; /* success */
sewardj30671ff2002-04-21 00:13:57 +0000929 }
930}
931
sewardj439d45e2002-05-03 20:43:10 +0000932
sewardj5905fae2002-04-26 13:25:00 +0000933int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000934{
935 int res;
sewardjd8acdf22002-11-13 21:57:52 +0000936
sewardj439d45e2002-05-03 20:43:10 +0000937 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000938 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
939 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
940 mutex, 0, 0, 0);
941 return res;
sewardj439d45e2002-05-03 20:43:10 +0000942 } else {
sewardjd8acdf22002-11-13 21:57:52 +0000943 /* Play at locking */
944 if (0)
945 kludged("prehistoric unlock");
946 mutex->__m_owner = 0;
947 mutex->__m_count = 0;
948 mutex->__m_kind &= ~VG_PTHREAD_PREHISTORY;
949 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000950 }
951}
952
sewardj439d45e2002-05-03 20:43:10 +0000953
sewardj5905fae2002-04-26 13:25:00 +0000954int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000955{
sewardj604ec3c2002-04-18 22:38:41 +0000956 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
957 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +0000958 if (mutex->__m_count > 0) {
sewardjd8acdf22002-11-13 21:57:52 +0000959 /* Oh, the horror. glibc's internal use of pthreads "knows"
960 that destroying a lock does an implicit unlock. Make it
961 explicit. */
962 __pthread_mutex_unlock(mutex);
963 pthread_error("pthread_mutex_destroy: "
964 "mutex is still in use");
965 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +0000966 }
967 mutex->__m_count = 0;
968 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
969 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
970 return 0;
sewardje663cb92002-04-12 10:26:32 +0000971}
972
973
sewardjf8f819e2002-04-17 23:21:37 +0000974/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000975 CONDITION VARIABLES
976 ------------------------------------------------ */
977
978/* LinuxThreads supports no attributes for conditions. Hence ... */
979
980int pthread_condattr_init(pthread_condattr_t *attr)
981{
982 return 0;
983}
984
sewardj0738a592002-04-20 13:59:33 +0000985int pthread_condattr_destroy(pthread_condattr_t *attr)
986{
987 return 0;
988}
sewardj6072c362002-04-19 14:40:57 +0000989
990int pthread_cond_init( pthread_cond_t *cond,
991 const pthread_condattr_t *cond_attr)
992{
993 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
994 return 0;
995}
996
sewardjf854f472002-04-21 12:19:41 +0000997int pthread_cond_destroy(pthread_cond_t *cond)
998{
999 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +00001000 static int moans = N_MOANS;
1001 if (moans-- > 0)
1002 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +00001003 return 0;
1004}
sewardj6072c362002-04-19 14:40:57 +00001005
1006/* ---------------------------------------------------
1007 SCHEDULING
1008 ------------------------------------------------ */
1009
1010/* This is completely bogus. */
1011int pthread_getschedparam(pthread_t target_thread,
1012 int *policy,
1013 struct sched_param *param)
1014{
sewardj436e0582002-04-26 14:31:40 +00001015 static int moans = N_MOANS;
1016 if (moans-- > 0)
1017 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +00001018 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +00001019# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +00001020 if (param) param->sched_priority = 0; /* who knows */
1021# else
sewardj6072c362002-04-19 14:40:57 +00001022 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +00001023# endif
sewardj6072c362002-04-19 14:40:57 +00001024 return 0;
1025}
1026
1027int pthread_setschedparam(pthread_t target_thread,
1028 int policy,
1029 const struct sched_param *param)
1030{
sewardj436e0582002-04-26 14:31:40 +00001031 static int moans = N_MOANS;
1032 if (moans-- > 0)
1033 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +00001034 return 0;
1035}
1036
sewardj3b5d8862002-04-20 13:53:23 +00001037int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
1038{
1039 int res;
1040 ensure_valgrind("pthread_cond_wait");
1041 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1042 VG_USERREQ__PTHREAD_COND_WAIT,
1043 cond, mutex, 0, 0);
1044 return res;
1045}
1046
sewardj5f07b662002-04-23 16:52:51 +00001047int pthread_cond_timedwait ( pthread_cond_t *cond,
1048 pthread_mutex_t *mutex,
1049 const struct timespec *abstime )
1050{
1051 int res;
1052 unsigned int ms_now, ms_end;
1053 struct timeval timeval_now;
1054 unsigned long long int ull_ms_now_after_1970;
1055 unsigned long long int ull_ms_end_after_1970;
1056
1057 ensure_valgrind("pthread_cond_timedwait");
1058 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1059 VG_USERREQ__READ_MILLISECOND_TIMER,
1060 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001061 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001062 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +00001063 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001064
1065 ull_ms_now_after_1970
1066 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
1067 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
1068 ull_ms_end_after_1970
1069 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
1070 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +00001071 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
1072 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +00001073 ms_end
1074 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
1075 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1076 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
1077 cond, mutex, ms_end, 0);
1078 return res;
1079}
1080
1081
sewardj3b5d8862002-04-20 13:53:23 +00001082int pthread_cond_signal(pthread_cond_t *cond)
1083{
1084 int res;
1085 ensure_valgrind("pthread_cond_signal");
1086 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1087 VG_USERREQ__PTHREAD_COND_SIGNAL,
1088 cond, 0, 0, 0);
1089 return res;
1090}
1091
1092int pthread_cond_broadcast(pthread_cond_t *cond)
1093{
1094 int res;
1095 ensure_valgrind("pthread_cond_broadcast");
1096 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1097 VG_USERREQ__PTHREAD_COND_BROADCAST,
1098 cond, 0, 0, 0);
1099 return res;
1100}
1101
sewardj6072c362002-04-19 14:40:57 +00001102
1103/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001104 CANCELLATION
1105 ------------------------------------------------ */
1106
sewardj853f55d2002-04-26 00:27:53 +00001107int pthread_setcancelstate(int state, int *oldstate)
1108{
sewardj20917d82002-05-28 01:36:45 +00001109 int res;
1110 ensure_valgrind("pthread_setcancelstate");
1111 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +00001112 && state != PTHREAD_CANCEL_DISABLE) {
1113 pthread_error("pthread_setcancelstate: "
1114 "invalid state");
sewardj20917d82002-05-28 01:36:45 +00001115 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001116 }
sewardj2d94c112002-06-03 01:25:54 +00001117 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1118 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001119 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1120 VG_USERREQ__SET_CANCELSTATE,
1121 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001122 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001123 if (oldstate)
1124 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001125 return 0;
1126}
1127
sewardje663cb92002-04-12 10:26:32 +00001128int pthread_setcanceltype(int type, int *oldtype)
1129{
sewardj20917d82002-05-28 01:36:45 +00001130 int res;
1131 ensure_valgrind("pthread_setcanceltype");
1132 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001133 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1134 pthread_error("pthread_setcanceltype: "
1135 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001136 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001137 }
sewardj2d94c112002-06-03 01:25:54 +00001138 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1139 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001140 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1141 VG_USERREQ__SET_CANCELTYPE,
1142 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001143 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001144 if (oldtype)
1145 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001146 return 0;
1147}
1148
sewardje663cb92002-04-12 10:26:32 +00001149int pthread_cancel(pthread_t thread)
1150{
1151 int res;
1152 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001153 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1154 VG_USERREQ__SET_CANCELPEND,
1155 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001156 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001157 return res;
1158}
1159
sewardjd140e442002-05-29 01:21:19 +00001160static __inline__
1161void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001162{
sewardj20917d82002-05-28 01:36:45 +00001163 int res;
njn25e49d8e72002-09-23 09:36:25 +00001164 ensure_valgrind("__my_pthread_testcancel");
sewardj20917d82002-05-28 01:36:45 +00001165 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1166 VG_USERREQ__TESTCANCEL,
1167 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001168 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001169}
1170
sewardjd140e442002-05-29 01:21:19 +00001171void pthread_testcancel ( void )
1172{
1173 __my_pthread_testcancel();
1174}
1175
sewardj20917d82002-05-28 01:36:45 +00001176
sewardjef037c72002-05-30 00:40:03 +00001177/* Not really sure what this is for. I suspect for doing the POSIX
1178 requirements for fork() and exec(). We do this internally anyway
1179 whenever those syscalls are observed, so this could be superfluous,
1180 but hey ...
1181*/
sewardj853f55d2002-04-26 00:27:53 +00001182void __pthread_kill_other_threads_np ( void )
1183{
sewardjef037c72002-05-30 00:40:03 +00001184 int res;
1185 ensure_valgrind("__pthread_kill_other_threads_np");
1186 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1187 VG_USERREQ__NUKE_OTHER_THREADS,
1188 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001189 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001190}
1191
sewardje663cb92002-04-12 10:26:32 +00001192
sewardjf8f819e2002-04-17 23:21:37 +00001193/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001194 SIGNALS
1195 ------------------------------------------------ */
1196
1197#include <signal.h>
1198
1199int pthread_sigmask(int how, const sigset_t *newmask,
1200 sigset_t *oldmask)
1201{
1202 int res;
1203
1204 /* A bit subtle, because the scheduler expects newmask and oldmask
1205 to be vki_sigset_t* rather than sigset_t*, and the two are
1206 different. Fortunately the first 64 bits of a sigset_t are
1207 exactly a vki_sigset_t, so we just pass the pointers through
1208 unmodified. Haaaack!
1209
1210 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001211 constants to VKI_ constants, so that the former do not have to
1212 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001213
1214 ensure_valgrind("pthread_sigmask");
1215
1216 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001217 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1218 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1219 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001220 default: pthread_error("pthread_sigmask: invalid how");
1221 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001222 }
1223
1224 /* Crude check */
1225 if (newmask == NULL)
1226 return EFAULT;
1227
1228 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1229 VG_USERREQ__PTHREAD_SIGMASK,
1230 how, newmask, oldmask, 0);
1231
1232 /* The scheduler tells us of any memory violations. */
1233 return res == 0 ? 0 : EFAULT;
1234}
1235
1236
1237int sigwait ( const sigset_t* set, int* sig )
1238{
1239 int res;
1240 ensure_valgrind("sigwait");
1241 /* As with pthread_sigmask we deliberately confuse sigset_t with
1242 vki_ksigset_t. */
1243 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1244 VG_USERREQ__SIGWAIT,
1245 set, sig, 0, 0);
1246 return res;
1247}
1248
1249
sewardj018f7622002-05-15 21:13:39 +00001250int pthread_kill(pthread_t thread, int signo)
1251{
1252 int res;
1253 ensure_valgrind("pthread_kill");
1254 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1255 VG_USERREQ__PTHREAD_KILL,
1256 thread, signo, 0, 0);
1257 return res;
1258}
1259
1260
sewardj3665ded2002-05-16 16:57:25 +00001261/* Copied verbatim from Linuxthreads */
1262/* Redefine raise() to send signal to calling thread only,
1263 as per POSIX 1003.1c */
1264int raise (int sig)
1265{
1266 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001267 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001268 return 0;
sewardj4dced352002-06-04 22:54:20 +00001269 } else {
sewardj3665ded2002-05-16 16:57:25 +00001270 errno = retcode;
1271 return -1;
1272 }
1273}
1274
1275
sewardj9a2224b2002-06-19 10:17:40 +00001276int pause ( void )
1277{
1278 unsigned int n_orig, n_now;
1279 struct vki_timespec nanosleep_interval;
1280 ensure_valgrind("pause");
1281
1282 /* This is surely a cancellation point. */
1283 __my_pthread_testcancel();
1284
1285 VALGRIND_MAGIC_SEQUENCE(n_orig, 0xFFFFFFFF /* default */,
1286 VG_USERREQ__GET_N_SIGS_RETURNED,
1287 0, 0, 0, 0);
1288 my_assert(n_orig != 0xFFFFFFFF);
1289
1290 while (1) {
1291 VALGRIND_MAGIC_SEQUENCE(n_now, 0xFFFFFFFF /* default */,
1292 VG_USERREQ__GET_N_SIGS_RETURNED,
1293 0, 0, 0, 0);
1294 my_assert(n_now != 0xFFFFFFFF);
1295 my_assert(n_now >= n_orig);
1296 if (n_now != n_orig) break;
1297
1298 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001299 nanosleep_interval.tv_nsec = 12 * 1000 * 1000; /* 12 milliseconds */
sewardj9a2224b2002-06-19 10:17:40 +00001300 /* It's critical here that valgrind's nanosleep implementation
1301 is nonblocking. */
1302 (void)my_do_syscall2(__NR_nanosleep,
1303 (int)(&nanosleep_interval), (int)NULL);
1304 }
1305
1306 * (__errno_location()) = EINTR;
1307 return -1;
1308}
1309
1310
sewardjb48e5002002-05-13 00:16:03 +00001311/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001312 THREAD-SPECIFICs
1313 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001314
sewardj00a66b12002-10-12 16:42:35 +00001315static
1316int key_is_valid (pthread_key_t key)
1317{
1318 int res;
1319 VALGRIND_MAGIC_SEQUENCE(res, 2 /* default */,
1320 VG_USERREQ__PTHREAD_KEY_VALIDATE,
1321 key, 0, 0, 0);
1322 my_assert(res != 2);
1323 return res;
1324}
1325
1326
1327/* Returns NULL if thread is invalid. Otherwise, if the thread
1328 already has a specifics area, return that. Otherwise allocate it
1329 one. */
1330static
1331void** get_or_allocate_specifics_ptr ( pthread_t thread )
1332{
1333 int res, i;
1334 void** specifics_ptr;
1335 ensure_valgrind("get_or_allocate_specifics_ptr");
1336
1337 /* Returns zero if the thread has no specific_ptr. One if thread
1338 is invalid. Otherwise, the specific_ptr value. This is
1339 allocated with my_malloc and so is aligned and cannot be
1340 confused with 1 or 3. */
1341 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
1342 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
1343 thread, 0, 0, 0);
1344 my_assert(specifics_ptr != (void**)3);
1345
1346 if (specifics_ptr == (void**)1)
1347 return NULL; /* invalid thread */
1348
1349 if (specifics_ptr != NULL)
1350 return specifics_ptr; /* already has a specifics ptr. */
1351
1352 /* None yet ... allocate a new one. Should never fail. */
1353 specifics_ptr = my_malloc( VG_N_THREAD_KEYS * sizeof(void*) );
1354 my_assert(specifics_ptr != NULL);
1355
1356 VALGRIND_MAGIC_SEQUENCE(res, -1 /* default */,
1357 VG_USERREQ__PTHREAD_SETSPECIFIC_PTR,
1358 specifics_ptr, 0, 0, 0);
1359 my_assert(res == 0);
1360
1361 /* POSIX sez: "Upon thread creation, the value NULL shall be
1362 associated with all defined keys in the new thread." This
1363 allocation is in effect a delayed allocation of the specific
1364 data for a thread, at its first-use. Hence we initialise it
1365 here. */
1366 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
1367 specifics_ptr[i] = NULL;
1368 }
1369
1370 return specifics_ptr;
1371}
1372
1373
sewardj5905fae2002-04-26 13:25:00 +00001374int __pthread_key_create(pthread_key_t *key,
1375 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001376{
sewardj00a66b12002-10-12 16:42:35 +00001377 void** specifics_ptr;
1378 int res, i;
sewardj5f07b662002-04-23 16:52:51 +00001379 ensure_valgrind("pthread_key_create");
sewardj00a66b12002-10-12 16:42:35 +00001380
1381 /* This writes *key if successful. It should never fail. */
1382 VALGRIND_MAGIC_SEQUENCE(res, 1 /* default */,
sewardj5f07b662002-04-23 16:52:51 +00001383 VG_USERREQ__PTHREAD_KEY_CREATE,
1384 key, destr_function, 0, 0);
sewardj00a66b12002-10-12 16:42:35 +00001385 my_assert(res == 0);
1386
1387 /* POSIX sez: "Upon key creation, the value NULL shall be
1388 associated with the new key in all active threads." */
1389 for (i = 0; i < VG_N_THREADS; i++) {
1390 specifics_ptr = get_or_allocate_specifics_ptr(i);
1391 /* we get NULL if i is an invalid thread. */
1392 if (specifics_ptr != NULL)
1393 specifics_ptr[*key] = NULL;
1394 }
1395
sewardj5f07b662002-04-23 16:52:51 +00001396 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001397}
1398
1399int pthread_key_delete(pthread_key_t key)
1400{
sewardj00a66b12002-10-12 16:42:35 +00001401 int res;
1402 ensure_valgrind("pthread_key_create");
1403 if (!key_is_valid(key))
1404 return EINVAL;
1405 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1406 VG_USERREQ__PTHREAD_KEY_DELETE,
1407 key, 0, 0, 0);
1408 my_assert(res == 0);
sewardj5e5fa512002-04-14 13:13:05 +00001409 return 0;
1410}
1411
sewardj5905fae2002-04-26 13:25:00 +00001412int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001413{
sewardj00a66b12002-10-12 16:42:35 +00001414 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001415 ensure_valgrind("pthread_setspecific");
sewardj00a66b12002-10-12 16:42:35 +00001416
1417 if (!key_is_valid(key))
1418 return EINVAL;
1419
1420 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1421 specifics_ptr[key] = (void*)pointer;
1422 return 0;
sewardj5e5fa512002-04-14 13:13:05 +00001423}
1424
sewardj5905fae2002-04-26 13:25:00 +00001425void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001426{
sewardj00a66b12002-10-12 16:42:35 +00001427 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001428 ensure_valgrind("pthread_getspecific");
sewardj00a66b12002-10-12 16:42:35 +00001429
1430 if (!key_is_valid(key))
1431 return NULL;
1432
1433 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1434 return specifics_ptr[key];
1435}
1436
1437
sewardj9aa918d2002-10-20 16:25:55 +00001438#ifdef GLIBC_2_3
sewardj00a66b12002-10-12 16:42:35 +00001439static
1440void ** __pthread_getspecific_addr(pthread_key_t key)
1441{
1442 void** specifics_ptr;
1443 ensure_valgrind("pthread_getspecific_addr");
1444
1445 if (!key_is_valid(key))
1446 return NULL;
1447
1448 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1449 return &(specifics_ptr[key]);
sewardj5e5fa512002-04-14 13:13:05 +00001450}
sewardj9aa918d2002-10-20 16:25:55 +00001451#endif
sewardjf8f819e2002-04-17 23:21:37 +00001452
1453/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001454 ONCEry
1455 ------------------------------------------------ */
1456
1457static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1458
1459
sewardj5905fae2002-04-26 13:25:00 +00001460int __pthread_once ( pthread_once_t *once_control,
1461 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001462{
1463 int res;
1464 ensure_valgrind("pthread_once");
1465
sewardj68b2dd92002-05-10 21:03:56 +00001466 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001467
sewardj68b2dd92002-05-10 21:03:56 +00001468 if (res != 0) {
sewardj89d3d852002-04-24 19:21:39 +00001469 barf("pthread_once: Looks like your program's "
1470 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001471 }
sewardj89d3d852002-04-24 19:21:39 +00001472
1473 if (*once_control == 0) {
1474 *once_control = 1;
1475 init_routine();
1476 }
1477
sewardj68b2dd92002-05-10 21:03:56 +00001478 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001479
1480 return 0;
1481}
1482
1483
1484/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001485 MISC
1486 ------------------------------------------------ */
1487
sewardj2cb00342002-06-28 01:46:26 +00001488static pthread_mutex_t pthread_atfork_lock
1489 = PTHREAD_MUTEX_INITIALIZER;
1490
sewardj5905fae2002-04-26 13:25:00 +00001491int __pthread_atfork ( void (*prepare)(void),
1492 void (*parent)(void),
1493 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001494{
sewardj2cb00342002-06-28 01:46:26 +00001495 int n, res;
1496 ForkHandlerEntry entry;
1497
1498 ensure_valgrind("pthread_atfork");
1499 __pthread_mutex_lock(&pthread_atfork_lock);
1500
1501 /* Fetch old counter */
1502 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1503 VG_USERREQ__GET_FHSTACK_USED,
1504 0, 0, 0, 0);
1505 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1506 if (n == VG_N_FORKHANDLERSTACK-1)
1507 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1508 "increase and recompile");
1509
1510 /* Add entry */
1511 entry.prepare = *prepare;
1512 entry.parent = *parent;
1513 entry.child = *child;
1514 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1515 VG_USERREQ__SET_FHSTACK_ENTRY,
1516 n, &entry, 0, 0);
1517 my_assert(res == 0);
1518
1519 /* Bump counter */
1520 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1521 VG_USERREQ__SET_FHSTACK_USED,
1522 n+1, 0, 0, 0);
1523 my_assert(res == 0);
1524
1525 __pthread_mutex_unlock(&pthread_atfork_lock);
1526 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001527}
1528
1529
sewardjbb990782002-05-08 02:01:14 +00001530__attribute__((weak))
1531void __pthread_initialize ( void )
1532{
sewardjbea1caa2002-05-10 23:20:58 +00001533 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001534}
1535
1536
sewardj853f55d2002-04-26 00:27:53 +00001537/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001538 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001539 ------------------------------------------------ */
1540
sewardj3b13f0e2002-04-25 20:17:29 +00001541#include <resolv.h>
1542static int thread_specific_errno[VG_N_THREADS];
1543static int thread_specific_h_errno[VG_N_THREADS];
1544static struct __res_state
1545 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001546
sewardj3b13f0e2002-04-25 20:17:29 +00001547int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001548{
1549 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001550 /* ensure_valgrind("__errno_location"); */
1551 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001552 VG_USERREQ__PTHREAD_GET_THREADID,
1553 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001554 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001555 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001556 barf("__errno_location: invalid ThreadId");
1557 return & thread_specific_errno[tid];
1558}
1559
1560int* __h_errno_location ( void )
1561{
1562 int tid;
1563 /* ensure_valgrind("__h_errno_location"); */
1564 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1565 VG_USERREQ__PTHREAD_GET_THREADID,
1566 0, 0, 0, 0);
1567 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001568 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001569 barf("__h_errno_location: invalid ThreadId");
1570 return & thread_specific_h_errno[tid];
1571}
1572
sewardjb0ff1032002-08-06 09:02:53 +00001573
1574#undef _res
1575extern struct __res_state _res;
1576
sewardj3b13f0e2002-04-25 20:17:29 +00001577struct __res_state* __res_state ( void )
1578{
1579 int tid;
1580 /* ensure_valgrind("__res_state"); */
1581 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1582 VG_USERREQ__PTHREAD_GET_THREADID,
1583 0, 0, 0, 0);
1584 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001585 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001586 barf("__res_state: invalid ThreadId");
sewardjb0ff1032002-08-06 09:02:53 +00001587 if (tid == 1)
1588 return & _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001589 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001590}
1591
1592
sewardj5716dbb2002-04-26 03:28:18 +00001593/* ---------------------------------------------------
1594 LIBC-PRIVATE SPECIFIC DATA
1595 ------------------------------------------------ */
1596
1597/* Relies on assumption that initial private data is NULL. This
1598 should be fixed somehow. */
1599
njn25e49d8e72002-09-23 09:36:25 +00001600/* The allowable keys (indices) (all 3 of them).
sewardj5716dbb2002-04-26 03:28:18 +00001601 From sysdeps/pthread/bits/libc-tsd.h
1602*/
sewardjcb7f08a2002-10-02 09:41:49 +00001603/* as per glibc anoncvs HEAD of 20021001. */
sewardj5716dbb2002-04-26 03:28:18 +00001604enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1605 _LIBC_TSD_KEY_DL_ERROR,
njn25e49d8e72002-09-23 09:36:25 +00001606 _LIBC_TSD_KEY_RPC_VARS,
sewardjcb7f08a2002-10-02 09:41:49 +00001607 _LIBC_TSD_KEY_LOCALE,
1608 _LIBC_TSD_KEY_CTYPE_B,
1609 _LIBC_TSD_KEY_CTYPE_TOLOWER,
1610 _LIBC_TSD_KEY_CTYPE_TOUPPER,
sewardj5716dbb2002-04-26 03:28:18 +00001611 _LIBC_TSD_KEY_N };
1612
1613/* Auto-initialising subsystem. libc_specifics_inited is set
1614 after initialisation. libc_specifics_inited_mx guards it. */
1615static int libc_specifics_inited = 0;
1616static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1617
sewardj00a66b12002-10-12 16:42:35 +00001618
sewardj5716dbb2002-04-26 03:28:18 +00001619/* These are the keys we must initialise the first time. */
sewardjcb7f08a2002-10-02 09:41:49 +00001620static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N];
sewardj5716dbb2002-04-26 03:28:18 +00001621
sewardj00a66b12002-10-12 16:42:35 +00001622
sewardjcb7f08a2002-10-02 09:41:49 +00001623/* Initialise the keys, if they are not already initialised. */
sewardj5716dbb2002-04-26 03:28:18 +00001624static
1625void init_libc_tsd_keys ( void )
1626{
1627 int res, i;
1628 pthread_key_t k;
1629
sewardj08c7f012002-10-07 23:56:55 +00001630 /* Don't fall into deadlock if we get called again whilst we still
1631 hold the lock, via the __uselocale() call herein. */
1632 if (libc_specifics_inited != 0)
1633 return;
1634
1635 /* Take the lock. */
sewardj00a66b12002-10-12 16:42:35 +00001636 res = __pthread_mutex_lock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001637 if (res != 0) barf("init_libc_tsd_keys: lock");
1638
sewardj08c7f012002-10-07 23:56:55 +00001639 /* Now test again, to be sure there is no mistake. */
1640 if (libc_specifics_inited != 0) {
sewardj00a66b12002-10-12 16:42:35 +00001641 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj08c7f012002-10-07 23:56:55 +00001642 if (res != 0) barf("init_libc_tsd_keys: unlock(1)");
1643 return;
sewardj5716dbb2002-04-26 03:28:18 +00001644 }
1645
sewardj08c7f012002-10-07 23:56:55 +00001646 /* Actually do the initialisation. */
1647 /* printf("INIT libc specifics\n"); */
1648 for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
sewardj00a66b12002-10-12 16:42:35 +00001649 res = __pthread_key_create(&k, NULL);
sewardj08c7f012002-10-07 23:56:55 +00001650 if (res != 0) barf("init_libc_tsd_keys: create");
1651 libc_specifics_keys[i] = k;
1652 }
1653
1654 /* Signify init done. */
1655 libc_specifics_inited = 1;
1656
1657# ifdef GLIBC_2_3
1658 /* Set the initialising thread's locale to the global (default)
sewardj00a66b12002-10-12 16:42:35 +00001659 locale. A hack in support of glibc-2.3. This does the biz for
1660 the root thread. For all other threads we run this in
1661 thread_wrapper(), which does the real work of
1662 pthread_create(). */
1663 /* assert that we are the root thread. I don't know if this is
1664 really a valid assertion to make; if it breaks I'll reconsider
1665 it. */
1666 my_assert(pthread_self() == 1);
sewardj08c7f012002-10-07 23:56:55 +00001667 __uselocale(LC_GLOBAL_LOCALE);
1668# endif
1669
1670 /* Unlock and return. */
sewardj00a66b12002-10-12 16:42:35 +00001671 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001672 if (res != 0) barf("init_libc_tsd_keys: unlock");
1673}
1674
1675
1676static int
1677libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1678 const void * pointer )
1679{
sewardjcb7f08a2002-10-02 09:41:49 +00001680 int res;
sewardj5716dbb2002-04-26 03:28:18 +00001681 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardjcb7f08a2002-10-02 09:41:49 +00001682 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001683 barf("libc_internal_tsd_set: invalid key");
1684 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001685 res = __pthread_setspecific(libc_specifics_keys[key], pointer);
sewardj5716dbb2002-04-26 03:28:18 +00001686 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1687 return 0;
1688}
1689
1690static void *
1691libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1692{
sewardjcb7f08a2002-10-02 09:41:49 +00001693 void* v;
sewardj5716dbb2002-04-26 03:28:18 +00001694 /* printf("GET GET GET key %d\n", key); */
sewardjcb7f08a2002-10-02 09:41:49 +00001695 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001696 barf("libc_internal_tsd_get: invalid key");
1697 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001698 v = __pthread_getspecific(libc_specifics_keys[key]);
sewardj5716dbb2002-04-26 03:28:18 +00001699 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1700 return v;
1701}
1702
1703
sewardj70adeb22002-04-27 01:35:38 +00001704int (*__libc_internal_tsd_set)
1705 (enum __libc_tsd_key_t key, const void * pointer)
1706 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001707
sewardj70adeb22002-04-27 01:35:38 +00001708void* (*__libc_internal_tsd_get)
1709 (enum __libc_tsd_key_t key)
1710 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001711
1712
sewardj00a66b12002-10-12 16:42:35 +00001713#ifdef GLIBC_2_3
1714/* This one was first spotted be me in the glibc-2.2.93 sources. */
1715static void**
1716libc_internal_tsd_address ( enum __libc_tsd_key_t key )
1717{
1718 void** v;
1719 /* printf("ADDR ADDR ADDR key %d\n", key); */
1720 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
1721 barf("libc_internal_tsd_address: invalid key");
1722 init_libc_tsd_keys();
1723 v = __pthread_getspecific_addr(libc_specifics_keys[key]);
1724 return v;
1725}
1726
1727void ** (*__libc_internal_tsd_address)
1728 (enum __libc_tsd_key_t key)
1729 = libc_internal_tsd_address;
1730#endif
1731
1732
sewardje663cb92002-04-12 10:26:32 +00001733/* ---------------------------------------------------------------------
1734 These are here (I think) because they are deemed cancellation
1735 points by POSIX. For the moment we'll simply pass the call along
1736 to the corresponding thread-unaware (?) libc routine.
1737 ------------------------------------------------------------------ */
1738
sewardje663cb92002-04-12 10:26:32 +00001739#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001740#include <sys/types.h>
1741#include <sys/socket.h>
1742
sewardjd529a442002-05-04 19:49:21 +00001743#ifdef GLIBC_2_1
1744extern
1745int __sigaction
1746 (int signum,
1747 const struct sigaction *act,
1748 struct sigaction *oldact);
1749#else
sewardje663cb92002-04-12 10:26:32 +00001750extern
1751int __libc_sigaction
1752 (int signum,
1753 const struct sigaction *act,
1754 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001755#endif
sewardje663cb92002-04-12 10:26:32 +00001756int sigaction(int signum,
1757 const struct sigaction *act,
1758 struct sigaction *oldact)
1759{
sewardjd140e442002-05-29 01:21:19 +00001760 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001761# ifdef GLIBC_2_1
1762 return __sigaction(signum, act, oldact);
1763# else
sewardj45b4b372002-04-16 22:50:32 +00001764 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001765# endif
sewardje663cb92002-04-12 10:26:32 +00001766}
1767
1768
1769extern
1770int __libc_connect(int sockfd,
1771 const struct sockaddr *serv_addr,
1772 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001773__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001774int connect(int sockfd,
1775 const struct sockaddr *serv_addr,
1776 socklen_t addrlen)
1777{
sewardjd140e442002-05-29 01:21:19 +00001778 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001779 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001780}
1781
1782
1783extern
1784int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001785__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001786int fcntl(int fd, int cmd, long arg)
1787{
sewardjd140e442002-05-29 01:21:19 +00001788 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001789 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001790}
1791
1792
1793extern
1794ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001795__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001796ssize_t write(int fd, const void *buf, size_t count)
1797{
sewardjd140e442002-05-29 01:21:19 +00001798 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001799 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001800}
1801
1802
1803extern
1804ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001805__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001806ssize_t read(int fd, void *buf, size_t count)
1807{
sewardjd140e442002-05-29 01:21:19 +00001808 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001809 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001810}
1811
sewardjf912dfc2002-11-13 21:51:10 +00001812/*
1813 * Ugh, this is horrible but here goes:
1814 *
1815 * Open of a named pipe (fifo file) can block. In a threaded program,
1816 * this means that the whole thing can block. We therefore need to
1817 * make the open appear to block to the caller, but still keep polling
1818 * for everyone else.
1819 *
1820 * There are four cases:
1821 *
1822 * - the caller asked for O_NONBLOCK. The easy one: we just do it.
1823 *
1824 * - the caller asked for a blocking O_RDONLY open. We open it with
1825 * O_NONBLOCK and then use poll to wait for it to become ready.
1826 *
1827 * - the caller asked for a blocking O_WRONLY open. Unfortunately, this
1828 * will fail with ENXIO when we make it non-blocking. Doubly
1829 * unfortunate is that we can only rely on these semantics if it is
1830 * actually a fifo file; the hack is that if we see that it is a
1831 * O_WRONLY open and we get ENXIO, then stat the path and see if it
1832 * actually is a fifo. This is racy, but it is the best we can do.
1833 * If it is a fifo, then keep trying the open until it works; if not
1834 * just return the error.
1835 *
1836 * - the caller asked for a blocking O_RDWR open. Well, under Linux,
1837 * this never blocks, so we just clear the non-blocking flag and
1838 * return.
1839 *
1840 * This code assumes that for whatever we open, O_NONBLOCK followed by
1841 * a fcntl clearing O_NONBLOCK is the same as opening without
1842 * O_NONBLOCK. Also assumes that stat and fstat have no side-effects.
1843 *
1844 * XXX Should probably put in special cases for some devices as well,
1845 * like serial ports. Unfortunately they don't work like fifos, so
1846 * this logic will become even more tortured. Wait until we really
1847 * need it.
1848 */
1849static inline int _open(const char *pathname, int flags, mode_t mode,
1850 int (*openp)(const char *, int, mode_t))
sewardjbe32e452002-04-24 20:29:58 +00001851{
sewardjf912dfc2002-11-13 21:51:10 +00001852 int fd;
1853 struct stat st;
1854 struct vki_timespec nanosleep_interval;
1855 int saved_errno;
1856
sewardjd140e442002-05-29 01:21:19 +00001857 __my_pthread_testcancel();
sewardjf912dfc2002-11-13 21:51:10 +00001858
1859 /* Assume we can only get O_RDONLY, O_WRONLY or O_RDWR */
1860 my_assert((flags & VKI_O_ACCMODE) != VKI_O_ACCMODE);
1861
1862 for(;;) {
1863 fd = (*openp)(pathname, flags | VKI_O_NONBLOCK, mode);
1864
1865 /* return immediately if caller wanted nonblocking anyway */
1866 if (flags & VKI_O_NONBLOCK)
1867 return fd;
1868
1869 saved_errno = errno;
1870
1871 if (fd != -1)
1872 break; /* open worked */
1873
1874 /* If we got ENXIO and we're opening WRONLY, and it turns out
1875 to really be a FIFO, then poll waiting for open to succeed */
1876 if (errno == ENXIO &&
1877 (flags & VKI_O_ACCMODE) == VKI_O_WRONLY &&
1878 (stat(pathname, &st) == 0 && S_ISFIFO(st.st_mode))) {
1879
1880 /* OK, we're opening a FIFO for writing; sleep and spin */
1881 nanosleep_interval.tv_sec = 0;
1882 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
1883 /* It's critical here that valgrind's nanosleep implementation
1884 is nonblocking. */
1885 (void)my_do_syscall2(__NR_nanosleep,
1886 (int)(&nanosleep_interval), (int)NULL);
1887 } else {
1888 /* it was just an error */
1889 errno = saved_errno;
1890 return -1;
1891 }
1892 }
1893
1894 /* OK, we've got a nonblocking FD for a caller who wants blocking;
1895 reset the flags to what they asked for */
1896 fcntl(fd, VKI_F_SETFL, flags);
1897
1898 /* Return now if one of:
1899 - we were opening O_RDWR (never blocks)
1900 - we opened with O_WRONLY (polling already done)
1901 - the thing we opened wasn't a FIFO after all (or fstat failed)
1902 */
1903 if ((flags & VKI_O_ACCMODE) != VKI_O_RDONLY ||
1904 (fstat(fd, &st) == -1 || !S_ISFIFO(st.st_mode))) {
1905 errno = saved_errno;
1906 return fd;
1907 }
1908
1909 /* OK, drop into the poll loop looking for something to read on the fd */
1910 my_assert((flags & VKI_O_ACCMODE) == VKI_O_RDONLY);
1911 for(;;) {
1912 struct pollfd pollfd;
1913 int res;
1914
1915 pollfd.fd = fd;
1916 pollfd.events = POLLIN;
1917 pollfd.revents = 0;
1918
1919 res = my_do_syscall3(__NR_poll, (int)&pollfd, 1, 0);
1920
1921 my_assert(res == 0 || res == 1);
1922
1923 if (res == 1) {
1924 /* OK, got it.
1925
1926 XXX This is wrong: we're waiting for either something to
1927 read or a HUP on the file descriptor, but the semantics of
1928 fifo open are that we should unblock as soon as someone
1929 simply opens the other end, not that they write something.
1930 With luck this won't matter in practice.
1931 */
1932 my_assert(pollfd.revents & (POLLIN|POLLHUP));
1933 break;
1934 }
1935
1936 /* Still nobody home; sleep and spin */
1937 nanosleep_interval.tv_sec = 0;
1938 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
1939 /* It's critical here that valgrind's nanosleep implementation
1940 is nonblocking. */
1941 (void)my_do_syscall2(__NR_nanosleep,
1942 (int)(&nanosleep_interval), (int)NULL);
1943 }
1944
1945 errno = saved_errno;
1946 return fd;
sewardjbe32e452002-04-24 20:29:58 +00001947}
1948
sewardjf912dfc2002-11-13 21:51:10 +00001949extern
1950int __libc_open64(const char *pathname, int flags, mode_t mode);
1951/* __attribute__((weak)) */
1952int open64(const char *pathname, int flags, mode_t mode)
1953{
1954 return _open(pathname, flags, mode, __libc_open64);
1955}
sewardje663cb92002-04-12 10:26:32 +00001956
1957extern
sewardj853f55d2002-04-26 00:27:53 +00001958int __libc_open(const char *pathname, int flags, mode_t mode);
sewardjf912dfc2002-11-13 21:51:10 +00001959/* __attribute__((weak)) */
sewardj853f55d2002-04-26 00:27:53 +00001960int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001961{
sewardjf912dfc2002-11-13 21:51:10 +00001962 return _open(pathname, flags, mode, __libc_open);
sewardje663cb92002-04-12 10:26:32 +00001963}
1964
sewardje663cb92002-04-12 10:26:32 +00001965extern
1966int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001967__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001968int close(int fd)
1969{
sewardjd140e442002-05-29 01:21:19 +00001970 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001971 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001972}
1973
1974
1975extern
1976int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardjf220ccc2002-10-23 21:53:49 +00001977
1978int VGL_(accept)(int s, struct sockaddr *addr, socklen_t *addrlen)
sewardje663cb92002-04-12 10:26:32 +00001979{
sewardjd140e442002-05-29 01:21:19 +00001980 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001981 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001982 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001983 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001984}
1985
sewardj0c573af92002-10-23 21:55:01 +00001986extern
1987int __libc_recv(int s, void *buf, size_t len, int flags);
1988
1989int VGL_(recv)(int s, void *buf, size_t len, int flags)
1990{
1991 __my_pthread_testcancel();
1992 wait_for_fd_to_be_readable_or_erring(s);
1993 __my_pthread_testcancel();
1994 return __libc_recv(s, buf, len, flags);
1995}
1996
sewardje663cb92002-04-12 10:26:32 +00001997
1998extern
sewardje663cb92002-04-12 10:26:32 +00001999pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00002000__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00002001pid_t waitpid(pid_t pid, int *status, int options)
2002{
sewardjd140e442002-05-29 01:21:19 +00002003 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002004 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00002005}
2006
2007
2008extern
2009int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00002010__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00002011int nanosleep(const struct timespec *req, struct timespec *rem)
2012{
sewardjd140e442002-05-29 01:21:19 +00002013 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00002014 return __libc_nanosleep(req, rem);
2015}
2016
sewardjbe32e452002-04-24 20:29:58 +00002017
sewardje663cb92002-04-12 10:26:32 +00002018extern
2019int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00002020__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00002021int fsync(int fd)
2022{
sewardjd140e442002-05-29 01:21:19 +00002023 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002024 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00002025}
2026
sewardjbe32e452002-04-24 20:29:58 +00002027
sewardj70c75362002-04-13 04:18:32 +00002028extern
2029off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00002030__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00002031off_t lseek(int fildes, off_t offset, int whence)
2032{
sewardjd140e442002-05-29 01:21:19 +00002033 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00002034 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00002035}
2036
sewardjbe32e452002-04-24 20:29:58 +00002037
2038extern
2039__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00002040__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00002041__off64_t lseek64(int fildes, __off64_t offset, int whence)
2042{
sewardjd140e442002-05-29 01:21:19 +00002043 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00002044 return __libc_lseek64(fildes, offset, whence);
2045}
2046
2047
sewardj726c4122002-05-16 23:39:10 +00002048extern
2049ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
2050 __off64_t __offset);
2051ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
2052 __off64_t __offset)
2053{
sewardjd140e442002-05-29 01:21:19 +00002054 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00002055 return __libc_pread64(__fd, __buf, __nbytes, __offset);
2056}
2057
2058
sewardja18e2102002-05-18 10:43:22 +00002059extern
2060ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
2061 __off64_t __offset);
2062ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
2063 __off64_t __offset)
2064{
sewardjd140e442002-05-29 01:21:19 +00002065 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00002066 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
2067}
2068
sewardj726c4122002-05-16 23:39:10 +00002069
sewardj39b93b12002-05-18 10:56:27 +00002070extern
2071ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
2072__attribute__((weak))
2073ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
2074{
sewardjd140e442002-05-29 01:21:19 +00002075 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00002076 return __libc_pwrite(fd, buf, count, offset);
2077}
2078
2079
2080extern
2081ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
2082__attribute__((weak))
2083ssize_t pread(int fd, void *buf, size_t count, off_t offset)
2084{
sewardjd140e442002-05-29 01:21:19 +00002085 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00002086 return __libc_pread(fd, buf, count, offset);
2087}
2088
2089
sewardj6af4b5d2002-04-16 04:40:49 +00002090extern
2091void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00002092/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00002093void longjmp(jmp_buf env, int val)
2094{
2095 __libc_longjmp(env, val);
2096}
2097
sewardjbe32e452002-04-24 20:29:58 +00002098
sewardj436c2db2002-06-18 09:07:54 +00002099extern void __libc_siglongjmp (sigjmp_buf env, int val)
2100 __attribute__ ((noreturn));
2101void siglongjmp(sigjmp_buf env, int val)
2102{
2103 kludged("siglongjmp (cleanup handlers are ignored)");
2104 __libc_siglongjmp(env, val);
2105}
2106
2107
sewardj6af4b5d2002-04-16 04:40:49 +00002108extern
2109int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00002110__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00002111int send(int s, const void *msg, size_t len, int flags)
2112{
sewardjd140e442002-05-29 01:21:19 +00002113 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00002114 return __libc_send(s, msg, len, flags);
2115}
2116
sewardjbe32e452002-04-24 20:29:58 +00002117
sewardj1e8cdc92002-04-18 11:37:52 +00002118extern
2119int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00002120__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00002121int recv(int s, void *buf, size_t len, int flags)
2122{
sewardjd140e442002-05-29 01:21:19 +00002123 __my_pthread_testcancel();
sewardj1d6b3a22002-06-20 07:58:33 +00002124 wait_for_fd_to_be_readable_or_erring(s);
2125 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00002126 return __libc_recv(s, buf, len, flags);
2127}
2128
sewardjbe32e452002-04-24 20:29:58 +00002129
sewardj3665ded2002-05-16 16:57:25 +00002130extern
2131int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
2132__attribute__((weak))
2133int sendmsg(int s, const struct msghdr *msg, int flags)
2134{
sewardjd140e442002-05-29 01:21:19 +00002135 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00002136 return __libc_sendmsg(s, msg, flags);
2137}
2138
2139
sewardj796d6a22002-04-24 02:28:34 +00002140extern
sewardj59da27a2002-06-06 08:33:54 +00002141int __libc_recvmsg(int s, struct msghdr *msg, int flags);
2142__attribute__((weak))
2143int recvmsg(int s, struct msghdr *msg, int flags)
2144{
2145 __my_pthread_testcancel();
2146 return __libc_recvmsg(s, msg, flags);
2147}
2148
2149
2150extern
sewardj436e0582002-04-26 14:31:40 +00002151int __libc_recvfrom(int s, void *buf, size_t len, int flags,
2152 struct sockaddr *from, socklen_t *fromlen);
2153__attribute__((weak))
2154int recvfrom(int s, void *buf, size_t len, int flags,
2155 struct sockaddr *from, socklen_t *fromlen)
2156{
sewardjd140e442002-05-29 01:21:19 +00002157 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00002158 wait_for_fd_to_be_readable_or_erring(s);
2159 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00002160 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
2161}
2162
2163
2164extern
sewardj796d6a22002-04-24 02:28:34 +00002165int __libc_sendto(int s, const void *msg, size_t len, int flags,
2166 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00002167__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00002168int sendto(int s, const void *msg, size_t len, int flags,
2169 const struct sockaddr *to, socklen_t tolen)
2170{
sewardjd140e442002-05-29 01:21:19 +00002171 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00002172 return __libc_sendto(s, msg, len, flags, to, tolen);
2173}
2174
sewardjbe32e452002-04-24 20:29:58 +00002175
sewardj369b1702002-04-24 13:28:15 +00002176extern
2177int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00002178__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00002179int system(const char* str)
2180{
sewardjd140e442002-05-29 01:21:19 +00002181 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00002182 return __libc_system(str);
2183}
2184
sewardjbe32e452002-04-24 20:29:58 +00002185
sewardjab0b1c32002-04-24 19:26:47 +00002186extern
2187pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00002188__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00002189pid_t wait(int *status)
2190{
sewardjd140e442002-05-29 01:21:19 +00002191 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00002192 return __libc_wait(status);
2193}
2194
sewardj45b4b372002-04-16 22:50:32 +00002195
sewardj67f1d582002-05-24 02:11:32 +00002196extern
2197int __libc_msync(const void *start, size_t length, int flags);
2198__attribute__((weak))
2199int msync(const void *start, size_t length, int flags)
2200{
sewardjd140e442002-05-29 01:21:19 +00002201 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00002202 return __libc_msync(start, length, flags);
2203}
2204
sewardj5905fae2002-04-26 13:25:00 +00002205
sewardj2cb00342002-06-28 01:46:26 +00002206/*--- fork and its helper ---*/
2207
2208static
2209void run_fork_handlers ( int what )
2210{
2211 ForkHandlerEntry entry;
2212 int n_h, n_handlers, i, res;
2213
2214 my_assert(what == 0 || what == 1 || what == 2);
2215
2216 /* Fetch old counter */
2217 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2218 VG_USERREQ__GET_FHSTACK_USED,
2219 0, 0, 0, 0);
2220 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2221
2222 /* Prepare handlers (what == 0) are called in opposite order of
2223 calls to pthread_atfork. Parent and child handlers are called
2224 in the same order as calls to pthread_atfork. */
2225 if (what == 0)
2226 n_h = n_handlers - 1;
2227 else
2228 n_h = 0;
2229
2230 for (i = 0; i < n_handlers; i++) {
2231 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2232 VG_USERREQ__GET_FHSTACK_ENTRY,
2233 n_h, &entry, 0, 0);
2234 my_assert(res == 0);
2235 switch (what) {
2236 case 0: if (entry.prepare) entry.prepare();
2237 n_h--; break;
2238 case 1: if (entry.parent) entry.parent();
2239 n_h++; break;
2240 case 2: if (entry.child) entry.child();
2241 n_h++; break;
2242 default: barf("run_fork_handlers: invalid what");
2243 }
2244 }
2245
2246 if (what != 0 /* prepare */) {
2247 /* Empty out the stack. */
2248 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2249 VG_USERREQ__SET_FHSTACK_USED,
2250 0, 0, 0, 0);
2251 my_assert(res == 0);
2252 }
2253}
2254
2255extern
2256pid_t __libc_fork(void);
2257pid_t __fork(void)
2258{
2259 pid_t pid;
2260 __my_pthread_testcancel();
2261 __pthread_mutex_lock(&pthread_atfork_lock);
2262
2263 run_fork_handlers(0 /* prepare */);
2264 pid = __libc_fork();
2265 if (pid == 0) {
2266 /* I am the child */
2267 run_fork_handlers(2 /* child */);
sewardjd8acdf22002-11-13 21:57:52 +00002268 __pthread_mutex_unlock(&pthread_atfork_lock);
sewardj2cb00342002-06-28 01:46:26 +00002269 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2270 } else {
2271 /* I am the parent */
2272 run_fork_handlers(1 /* parent */);
2273 __pthread_mutex_unlock(&pthread_atfork_lock);
2274 }
2275 return pid;
2276}
2277
2278
njn25e49d8e72002-09-23 09:36:25 +00002279pid_t __vfork(void)
2280{
2281 return __fork();
2282}
sewardj2cb00342002-06-28 01:46:26 +00002283
2284
sewardj3b13f0e2002-04-25 20:17:29 +00002285/* ---------------------------------------------------------------------
2286 Nonblocking implementations of select() and poll(). This stuff will
2287 surely rot your mind.
2288 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00002289
sewardj08a4c3f2002-04-13 03:45:44 +00002290/*--------------------------------------------------*/
2291
2292#include "vg_kerneliface.h"
2293
2294static
2295__inline__
2296int is_kerror ( int res )
2297{
2298 if (res >= -4095 && res <= -1)
2299 return 1;
2300 else
2301 return 0;
2302}
2303
2304
2305static
2306int my_do_syscall1 ( int syscallno, int arg1 )
2307{
2308 int __res;
2309 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2310 : "=a" (__res)
2311 : "0" (syscallno),
2312 "d" (arg1) );
2313 return __res;
2314}
2315
2316static
2317int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00002318 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00002319{
2320 int __res;
2321 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2322 : "=a" (__res)
2323 : "0" (syscallno),
2324 "d" (arg1),
2325 "c" (arg2) );
2326 return __res;
2327}
2328
2329static
sewardjf854f472002-04-21 12:19:41 +00002330int my_do_syscall3 ( int syscallno,
2331 int arg1, int arg2, int arg3 )
2332{
2333 int __res;
2334 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
2335 : "=a" (__res)
2336 : "0" (syscallno),
2337 "S" (arg1),
2338 "c" (arg2),
2339 "d" (arg3) );
2340 return __res;
2341}
2342
sewardjd5bef572002-10-23 21:49:33 +00002343static inline
2344int my_do_syscall5 ( int syscallno,
2345 int arg1, int arg2, int arg3, int arg4, int arg5 )
2346{
2347 int __res;
2348 __asm__ volatile ("int $0x80"
2349 : "=a" (__res)
2350 : "0" (syscallno),
2351 "b" (arg1),
2352 "c" (arg2),
2353 "d" (arg3),
2354 "S" (arg4),
2355 "D" (arg5));
2356 return __res;
2357}
2358
sewardjf854f472002-04-21 12:19:41 +00002359static
sewardj08a4c3f2002-04-13 03:45:44 +00002360int do_syscall_select( int n,
2361 vki_fd_set* readfds,
2362 vki_fd_set* writefds,
2363 vki_fd_set* exceptfds,
2364 struct vki_timeval * timeout )
2365{
2366 int res;
2367 int args[5];
2368 args[0] = n;
2369 args[1] = (int)readfds;
2370 args[2] = (int)writefds;
2371 args[3] = (int)exceptfds;
2372 args[4] = (int)timeout;
2373 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00002374 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00002375}
2376
2377
2378/* This is a wrapper round select(), which makes it thread-safe,
2379 meaning that only this thread will block, rather than the entire
2380 process. This wrapper in turn depends on nanosleep() not to block
2381 the entire process, but I think (hope? suspect?) that POSIX
2382 pthreads guarantees that to be the case.
2383
2384 Basic idea is: modify the timeout parameter to select so that it
2385 returns immediately. Poll like this until select returns non-zero,
2386 indicating something interesting happened, or until our time is up.
njn25e49d8e72002-09-23 09:36:25 +00002387 Space out the polls with nanosleeps of say 11 milliseconds, which
sewardj08a4c3f2002-04-13 03:45:44 +00002388 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00002389
2390 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00002391 * (checked via my_assert) types fd_set and vki_fd_set are identical.
2392 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00002393 * (unchecked) libc error numbers (EINTR etc) are the negation of the
2394 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00002395*/
sewardj08a4c3f2002-04-13 03:45:44 +00002396
sewardj7db011a2002-11-13 22:00:20 +00002397int VGL_(select) ( int n,
2398 fd_set *rfds,
2399 fd_set *wfds,
2400 fd_set *xfds,
2401 struct timeval *timeout )
sewardj08a4c3f2002-04-13 03:45:44 +00002402{
sewardj5f07b662002-04-23 16:52:51 +00002403 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00002404 int res;
2405 fd_set rfds_copy;
2406 fd_set wfds_copy;
2407 fd_set xfds_copy;
2408 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00002409 struct vki_timeval zero_timeout;
2410 struct vki_timespec nanosleep_interval;
2411
sewardjd140e442002-05-29 01:21:19 +00002412 __my_pthread_testcancel();
2413
sewardj5f07b662002-04-23 16:52:51 +00002414 /* gcc's complains about ms_end being used uninitialised -- classic
2415 case it can't understand, where ms_end is both defined and used
2416 only if timeout != NULL. Hence ... */
2417 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00002418
2419 /* We assume that the kernel and libc data layouts are identical
2420 for the following types. These asserts provide a crude
2421 check. */
2422 if (sizeof(fd_set) != sizeof(vki_fd_set)
2423 || sizeof(struct timeval) != sizeof(struct vki_timeval))
2424 barf("valgrind's hacky non-blocking select(): data sizes error");
2425
sewardj5f07b662002-04-23 16:52:51 +00002426 /* Detect the current time and simultaneously find out if we are
2427 running on Valgrind. */
2428 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2429 VG_USERREQ__READ_MILLISECOND_TIMER,
2430 0, 0, 0, 0);
2431
2432 /* If a zero timeout specified, this call is harmless. Also go
2433 this route if we're not running on Valgrind, for whatever
2434 reason. */
2435 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
2436 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00002437 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00002438 (vki_fd_set*)wfds,
2439 (vki_fd_set*)xfds,
2440 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00002441 if (is_kerror(res)) {
2442 * (__errno_location()) = -res;
2443 return -1;
2444 } else {
2445 return res;
2446 }
2447 }
sewardj08a4c3f2002-04-13 03:45:44 +00002448
sewardj5f07b662002-04-23 16:52:51 +00002449 /* If a timeout was specified, set ms_end to be the end millisecond
2450 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00002451 if (timeout) {
2452 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00002453 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00002454 ms_end = ms_now;
2455 ms_end += (timeout->tv_usec / 1000);
2456 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00002457 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00002458 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00002459 }
2460
2461 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
2462
2463 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00002464 NULL, in which case ms_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002465
sewardj08a4c3f2002-04-13 03:45:44 +00002466 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002467
2468 /* First, do a return-immediately select(). */
sewardj08a4c3f2002-04-13 03:45:44 +00002469
2470 /* These could be trashed each time round the loop, so restore
2471 them each time. */
2472 if (rfds) rfds_copy = *rfds;
2473 if (wfds) wfds_copy = *wfds;
2474 if (xfds) xfds_copy = *xfds;
2475
2476 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
2477
2478 res = do_syscall_select( n,
2479 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
2480 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
2481 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
2482 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00002483 if (is_kerror(res)) {
2484 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00002485 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00002486 * (__errno_location()) = -res;
2487 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00002488 }
2489 if (res > 0) {
2490 /* one or more fds is ready. Copy out resulting sets and
2491 return. */
2492 if (rfds) *rfds = rfds_copy;
2493 if (wfds) *wfds = wfds_copy;
2494 if (xfds) *xfds = xfds_copy;
2495 return res;
2496 }
sewardj05bb2c92002-06-26 00:47:17 +00002497
2498 /* Nothing interesting happened, so we go to sleep for a
2499 while. */
2500
sewardj08a4c3f2002-04-13 03:45:44 +00002501 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
2502 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00002503 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002504 nanosleep_interval.tv_nsec = 11 * 1000 * 1000; /* 11 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00002505 /* It's critical here that valgrind's nanosleep implementation
2506 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00002507 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00002508 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00002509 if (res == -VKI_EINTR) {
2510 /* The nanosleep was interrupted by a signal. So we do the
2511 same. */
2512 * (__errno_location()) = EINTR;
2513 return -1;
2514 }
sewardj05bb2c92002-06-26 00:47:17 +00002515
2516 /* Sleeping finished. If a finite timeout, check to see if it
2517 has expired yet. */
2518 if (timeout) {
2519 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2520 VG_USERREQ__READ_MILLISECOND_TIMER,
2521 0, 0, 0, 0);
2522 my_assert(ms_now != 0xFFFFFFFF);
2523 if (ms_now >= ms_end) {
2524 /* timeout; nothing interesting happened. */
2525 if (rfds) FD_ZERO(rfds);
2526 if (wfds) FD_ZERO(wfds);
2527 if (xfds) FD_ZERO(xfds);
2528 return 0;
2529 }
2530 }
2531
sewardjf854f472002-04-21 12:19:41 +00002532 }
2533}
2534
2535
2536
2537
2538#include <sys/poll.h>
2539
sewardj3e909ce2002-06-03 13:27:15 +00002540#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00002541typedef unsigned long int nfds_t;
2542#endif
2543
sewardj705d3cb2002-05-23 13:13:12 +00002544
sewardj7db011a2002-11-13 22:00:20 +00002545int VGL_(poll) (struct pollfd *__fds, nfds_t __nfds, int __timeout)
sewardjf854f472002-04-21 12:19:41 +00002546{
sewardj5f07b662002-04-23 16:52:51 +00002547 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00002548 int res, i;
sewardjf854f472002-04-21 12:19:41 +00002549 struct vki_timespec nanosleep_interval;
2550
sewardjd140e442002-05-29 01:21:19 +00002551 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00002552 ensure_valgrind("poll");
2553
sewardj5f07b662002-04-23 16:52:51 +00002554 /* Detect the current time and simultaneously find out if we are
2555 running on Valgrind. */
2556 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2557 VG_USERREQ__READ_MILLISECOND_TIMER,
2558 0, 0, 0, 0);
2559
sewardjf854f472002-04-21 12:19:41 +00002560 if (/* CHECK SIZES FOR struct pollfd */
2561 sizeof(struct timeval) != sizeof(struct vki_timeval))
2562 barf("valgrind's hacky non-blocking poll(): data sizes error");
2563
sewardj5f07b662002-04-23 16:52:51 +00002564 /* dummy initialisation to keep gcc -Wall happy */
2565 ms_end = 0;
2566
2567 /* If a zero timeout specified, this call is harmless. Also do
2568 this if not running on Valgrind. */
2569 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00002570 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
2571 if (is_kerror(res)) {
2572 * (__errno_location()) = -res;
2573 return -1;
2574 } else {
2575 return res;
2576 }
2577 }
2578
sewardj5f07b662002-04-23 16:52:51 +00002579 /* If a timeout was specified, set ms_end to be the end wallclock
2580 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002581 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002582 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002583 }
2584
2585 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2586
2587 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2588 in which case t_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002589
sewardj2d94c112002-06-03 01:25:54 +00002590 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002591
sewardjf854f472002-04-21 12:19:41 +00002592 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002593
2594 /* Do a return-immediately poll. */
2595
2596 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2597 if (is_kerror(res)) {
2598 /* Some kind of error. Set errno and return. */
2599 * (__errno_location()) = -res;
2600 return -1;
2601 }
2602 if (res > 0) {
2603 /* One or more fds is ready. Return now. */
2604 return res;
2605 }
2606
2607 /* Nothing interesting happened, so we go to sleep for a
2608 while. */
2609
2610 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2611 /* nanosleep and go round again */
2612 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002613 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
sewardj05bb2c92002-06-26 00:47:17 +00002614 /* It's critical here that valgrind's nanosleep implementation
2615 is nonblocking. */
2616 (void)my_do_syscall2(__NR_nanosleep,
2617 (int)(&nanosleep_interval), (int)NULL);
2618
2619 /* Sleeping finished. If a finite timeout, check to see if it
2620 has expired yet. */
sewardjf854f472002-04-21 12:19:41 +00002621 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002622 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2623 VG_USERREQ__READ_MILLISECOND_TIMER,
2624 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002625 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002626 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002627 /* timeout; nothing interesting happened. */
2628 for (i = 0; i < __nfds; i++)
2629 __fds[i].revents = 0;
2630 return 0;
2631 }
2632 }
2633
sewardj08a4c3f2002-04-13 03:45:44 +00002634 }
2635}
sewardj3b13f0e2002-04-25 20:17:29 +00002636
2637
sewardj705d3cb2002-05-23 13:13:12 +00002638/* Helper function used to make accept() non-blocking. Idea is to use
2639 the above nonblocking poll() to make this thread ONLY wait for the
2640 specified fd to become ready, and then return. */
sewardjd1c1cf22002-06-26 00:13:36 +00002641
2642/* Sigh -- a hack. We're not supposed to include this file directly;
2643 should do it via /usr/include/fcntl.h, but that introduces a
2644 varargs prototype for fcntl itself, which we can't mimic. */
2645#define _FCNTL_H
2646#include <bits/fcntl.h>
2647
sewardj705d3cb2002-05-23 13:13:12 +00002648static void wait_for_fd_to_be_readable_or_erring ( int fd )
2649{
2650 struct pollfd pfd;
sewardjd1c1cf22002-06-26 00:13:36 +00002651 int res;
2652
sewardj6e6cbaa2002-05-24 02:12:52 +00002653 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardjd1c1cf22002-06-26 00:13:36 +00002654
2655 /* First check to see if the fd is nonblocking, and/or invalid. In
2656 either case return immediately. */
2657 res = __libc_fcntl(fd, F_GETFL, 0);
2658 if (res == -1) return; /* fd is invalid somehow */
2659 if (res & O_NONBLOCK) return; /* fd is nonblocking */
2660
2661 /* Ok, we'd better wait with poll. */
sewardj705d3cb2002-05-23 13:13:12 +00002662 pfd.fd = fd;
2663 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2664 /* ... but not POLLOUT, you may notice. */
2665 pfd.revents = 0;
2666 (void)poll(&pfd, 1, -1 /* forever */);
2667}
2668
2669
sewardj3b13f0e2002-04-25 20:17:29 +00002670/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002671 Hacky implementation of semaphores.
2672 ------------------------------------------------------------------ */
2673
2674#include <semaphore.h>
2675
2676/* This is a terrible way to do the remapping. Plan is to import an
2677 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002678
2679typedef
2680 struct {
2681 pthread_mutex_t se_mx;
2682 pthread_cond_t se_cv;
2683 int count;
2684 }
2685 vg_sem_t;
2686
2687static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2688
2689static int se_remap_used = 0;
2690static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2691static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2692
2693static vg_sem_t* se_remap ( sem_t* orig )
2694{
2695 int res, i;
2696 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002697 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002698
2699 for (i = 0; i < se_remap_used; i++) {
2700 if (se_remap_orig[i] == orig)
2701 break;
2702 }
2703 if (i == se_remap_used) {
2704 if (se_remap_used == VG_N_SEMAPHORES) {
2705 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002706 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002707 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002708 }
2709 se_remap_used++;
2710 se_remap_orig[i] = orig;
2711 /* printf("allocated semaphore %d\n", i); */
2712 }
2713 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002714 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002715 return &se_remap_new[i];
2716}
2717
2718
2719int sem_init(sem_t *sem, int pshared, unsigned int value)
2720{
2721 int res;
2722 vg_sem_t* vg_sem;
2723 ensure_valgrind("sem_init");
2724 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002725 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002726 errno = ENOSYS;
2727 return -1;
2728 }
2729 vg_sem = se_remap(sem);
2730 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002731 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002732 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002733 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002734 vg_sem->count = value;
2735 return 0;
2736}
2737
2738
2739int sem_wait ( sem_t* sem )
2740{
2741 int res;
2742 vg_sem_t* vg_sem;
2743 ensure_valgrind("sem_wait");
2744 vg_sem = se_remap(sem);
2745 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002746 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002747 while (vg_sem->count == 0) {
2748 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002749 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002750 }
2751 vg_sem->count--;
2752 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002753 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002754 return 0;
2755}
2756
2757int sem_post ( sem_t* sem )
2758{
2759 int res;
2760 vg_sem_t* vg_sem;
2761 ensure_valgrind("sem_post");
2762 vg_sem = se_remap(sem);
2763 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002764 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002765 if (vg_sem->count == 0) {
2766 vg_sem->count++;
2767 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002768 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002769 } else {
2770 vg_sem->count++;
2771 }
2772 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002773 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002774 return 0;
2775}
2776
2777
2778int sem_trywait ( sem_t* sem )
2779{
2780 int ret, res;
2781 vg_sem_t* vg_sem;
2782 ensure_valgrind("sem_trywait");
2783 vg_sem = se_remap(sem);
2784 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002785 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002786 if (vg_sem->count > 0) {
2787 vg_sem->count--;
2788 ret = 0;
2789 } else {
2790 ret = -1;
2791 errno = EAGAIN;
2792 }
2793 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002794 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002795 return ret;
2796}
2797
2798
2799int sem_getvalue(sem_t* sem, int * sval)
2800{
2801 vg_sem_t* vg_sem;
2802 ensure_valgrind("sem_trywait");
2803 vg_sem = se_remap(sem);
2804 *sval = vg_sem->count;
2805 return 0;
2806}
2807
2808
2809int sem_destroy(sem_t * sem)
2810{
2811 kludged("sem_destroy");
2812 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2813 return 0;
2814}
2815
sewardj9ad92d92002-10-16 19:45:06 +00002816
2817int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2818{
2819 int res;
2820 vg_sem_t* vg_sem;
2821 ensure_valgrind("sem_timedwait");
2822 vg_sem = se_remap(sem);
2823 res = __pthread_mutex_lock(&vg_sem->se_mx);
2824 my_assert(res == 0);
2825 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
2826 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
2827 }
2828 if ( vg_sem->count > 0 ) {
2829 vg_sem->count--;
2830 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2831 my_assert(res == 0 );
2832 return 0;
2833 } else {
2834 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2835 my_assert(res == 0 );
2836 *(__errno_location()) = ETIMEDOUT;
2837 return -1;
2838 }
2839}
2840
sewardj8f253ff2002-05-19 00:13:34 +00002841
2842/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002843 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002844 ------------------------------------------------------------------ */
2845
sewardj2d8b3f02002-06-01 14:14:19 +00002846typedef
2847 struct {
2848 int initted; /* != 0 --> in use; sanity check only */
2849 int prefer_w; /* != 0 --> prefer writer */
2850 int nwait_r; /* # of waiting readers */
2851 int nwait_w; /* # of waiting writers */
2852 pthread_cond_t cv_r; /* for signalling readers */
2853 pthread_cond_t cv_w; /* for signalling writers */
2854 pthread_mutex_t mx;
2855 int status;
2856 /* allowed range for status: >= -1. -1 means 1 writer currently
2857 active, >= 0 means N readers currently active. */
2858 }
2859 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002860
2861
2862static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2863
2864static int rw_remap_used = 0;
2865static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2866static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2867
sewardj2d8b3f02002-06-01 14:14:19 +00002868
2869static
2870void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2871{
2872 int res = 0;
2873 vg_rwl->initted = 1;
2874 vg_rwl->prefer_w = 1;
2875 vg_rwl->nwait_r = 0;
2876 vg_rwl->nwait_w = 0;
2877 vg_rwl->status = 0;
2878 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2879 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2880 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002881 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002882}
2883
2884
sewardja1ac5cb2002-05-27 13:00:05 +00002885/* Take the address of a LinuxThreads rwlock_t and return the shadow
2886 address of our version. Further, if the LinuxThreads version
2887 appears to have been statically initialised, do the same to the one
2888 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2889 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2890 uninitialised and non-zero meaning initialised.
2891*/
2892static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2893{
2894 int res, i;
2895 vg_rwlock_t* vg_rwl;
2896 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002897 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002898
2899 for (i = 0; i < rw_remap_used; i++) {
2900 if (rw_remap_orig[i] == orig)
2901 break;
2902 }
2903 if (i == rw_remap_used) {
2904 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002905 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002906 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002907 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2908 }
2909 rw_remap_used++;
2910 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002911 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002912 if (0) printf("allocated rwlock %d\n", i);
2913 }
2914 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002915 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002916 vg_rwl = &rw_remap_new[i];
2917
sewardj2d8b3f02002-06-01 14:14:19 +00002918 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002919 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002920 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002921 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002922 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002923 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002924 }
2925
2926 return vg_rwl;
2927}
2928
2929
sewardja1ac5cb2002-05-27 13:00:05 +00002930int pthread_rwlock_init ( pthread_rwlock_t* orig,
2931 const pthread_rwlockattr_t* attr )
2932{
sewardja1ac5cb2002-05-27 13:00:05 +00002933 vg_rwlock_t* rwl;
2934 if (0) printf ("pthread_rwlock_init\n");
2935 /* Force the remapper to initialise the shadow. */
2936 orig->__rw_readers = 0;
2937 /* Install the lock preference; the remapper needs to know it. */
2938 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2939 if (attr)
2940 orig->__rw_kind = attr->__lockkind;
2941 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002942 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002943}
2944
sewardj2d8b3f02002-06-01 14:14:19 +00002945
2946static
2947void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002948{
sewardj2d8b3f02002-06-01 14:14:19 +00002949 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2950 rwl->nwait_r--;
2951 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002952}
2953
sewardj2d8b3f02002-06-01 14:14:19 +00002954
sewardja1ac5cb2002-05-27 13:00:05 +00002955int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2956{
2957 int res;
2958 vg_rwlock_t* rwl;
2959 if (0) printf ("pthread_rwlock_rdlock\n");
2960 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002961 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002962 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002963 if (!rwl->initted) {
2964 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002965 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002966 return EINVAL;
2967 }
2968 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002969 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002970 rwl->nwait_r++;
2971 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2972 while (1) {
2973 if (rwl->status == 0) break;
2974 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002975 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002976 }
2977 pthread_cleanup_pop(0);
2978 rwl->nwait_r--;
2979 }
sewardj2d94c112002-06-03 01:25:54 +00002980 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002981 rwl->status++;
2982 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002983 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002984 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002985}
2986
sewardj2d8b3f02002-06-01 14:14:19 +00002987
sewardja1ac5cb2002-05-27 13:00:05 +00002988int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2989{
2990 int res;
2991 vg_rwlock_t* rwl;
2992 if (0) printf ("pthread_rwlock_tryrdlock\n");
2993 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002994 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002995 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002996 if (!rwl->initted) {
2997 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002998 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002999 return EINVAL;
3000 }
3001 if (rwl->status == -1) {
3002 /* Writer active; we have to give up. */
3003 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003004 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003005 return EBUSY;
3006 }
3007 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00003008 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003009 rwl->status++;
3010 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003011 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003012 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003013}
3014
sewardj2d8b3f02002-06-01 14:14:19 +00003015
3016static
3017void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
3018{
3019 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
3020 rwl->nwait_w--;
3021 pthread_mutex_unlock (&rwl->mx);
3022}
3023
3024
sewardja1ac5cb2002-05-27 13:00:05 +00003025int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
3026{
3027 int res;
3028 vg_rwlock_t* rwl;
3029 if (0) printf ("pthread_rwlock_wrlock\n");
3030 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00003031 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003032 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003033 if (!rwl->initted) {
3034 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003035 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003036 return EINVAL;
3037 }
3038 if (rwl->status != 0) {
3039 rwl->nwait_w++;
3040 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
3041 while (1) {
3042 if (rwl->status == 0) break;
3043 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003044 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003045 }
3046 pthread_cleanup_pop(0);
3047 rwl->nwait_w--;
3048 }
sewardj2d94c112002-06-03 01:25:54 +00003049 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003050 rwl->status = -1;
3051 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003052 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003053 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003054}
3055
sewardj2d8b3f02002-06-01 14:14:19 +00003056
sewardja1ac5cb2002-05-27 13:00:05 +00003057int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
3058{
3059 int res;
3060 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00003061 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00003062 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00003063 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003064 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003065 if (!rwl->initted) {
3066 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003067 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003068 return EINVAL;
3069 }
3070 if (rwl->status != 0) {
3071 /* Reader(s) or a writer active; we have to give up. */
3072 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003073 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003074 return EBUSY;
3075 }
3076 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00003077 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003078 rwl->status = -1;
3079 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003080 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003081 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003082}
3083
sewardj2d8b3f02002-06-01 14:14:19 +00003084
sewardja1ac5cb2002-05-27 13:00:05 +00003085int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
3086{
3087 int res;
3088 vg_rwlock_t* rwl;
3089 if (0) printf ("pthread_rwlock_unlock\n");
3090 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00003091 rwl = rw_remap ( orig );
3092 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003093 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003094 if (!rwl->initted) {
3095 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003096 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003097 return EINVAL;
3098 }
3099 if (rwl->status == 0) {
3100 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003101 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003102 return EPERM;
3103 }
sewardj2d94c112002-06-03 01:25:54 +00003104 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003105 if (rwl->status == -1) {
3106 rwl->status = 0;
3107 } else {
sewardj2d94c112002-06-03 01:25:54 +00003108 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003109 rwl->status--;
3110 }
3111
sewardj2d94c112002-06-03 01:25:54 +00003112 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003113
3114 if (rwl->prefer_w) {
3115
3116 /* Favour waiting writers, if any. */
3117 if (rwl->nwait_w > 0) {
3118 /* Writer(s) are waiting. */
3119 if (rwl->status == 0) {
3120 /* We can let a writer in. */
3121 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00003122 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003123 } else {
3124 /* There are still readers active. Do nothing; eventually
3125 they will disappear, at which point a writer will be
3126 admitted. */
3127 }
3128 }
3129 else
3130 /* No waiting writers. */
3131 if (rwl->nwait_r > 0) {
3132 /* Let in a waiting reader. */
3133 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00003134 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003135 }
3136
3137 } else {
3138
3139 /* Favour waiting readers, if any. */
3140 if (rwl->nwait_r > 0) {
3141 /* Reader(s) are waiting; let one in. */
3142 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00003143 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003144 }
3145 else
3146 /* No waiting readers. */
3147 if (rwl->nwait_w > 0 && rwl->status == 0) {
3148 /* We have waiting writers and no active readers; let a
3149 writer in. */
3150 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00003151 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003152 }
3153 }
3154
3155 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003156 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003157 return 0;
3158}
3159
3160
3161int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
3162{
3163 int res;
3164 vg_rwlock_t* rwl;
3165 if (0) printf ("pthread_rwlock_destroy\n");
3166 rwl = rw_remap ( orig );
3167 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003168 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003169 if (!rwl->initted) {
3170 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003171 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003172 return EINVAL;
3173 }
3174 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
3175 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003176 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003177 return EBUSY;
3178 }
3179 rwl->initted = 0;
3180 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003181 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003182 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003183}
3184
3185
sewardj47e4e312002-06-18 09:24:34 +00003186/* Copied directly from LinuxThreads. */
3187int
3188pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
3189{
3190 attr->__lockkind = 0;
3191 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
3192
3193 return 0;
3194}
3195
sewardjfe18eb82002-07-13 12:58:44 +00003196/* Copied directly from LinuxThreads. */
3197int
3198pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
3199{
3200 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
3201 return EINVAL;
3202
3203 /* For now it is not possible to shared a conditional variable. */
3204 if (pshared != PTHREAD_PROCESS_PRIVATE)
3205 return ENOSYS;
3206
3207 attr->__pshared = pshared;
3208
3209 return 0;
3210}
3211
sewardj47e4e312002-06-18 09:24:34 +00003212
sewardja1ac5cb2002-05-27 13:00:05 +00003213/* ---------------------------------------------------------------------
sewardjd5bef572002-10-23 21:49:33 +00003214 Make SYSV IPC not block everything
3215 ------------------------------------------------------------------ */
3216
3217#include <sys/ipc.h>
3218#include <sys/msg.h>
3219#include <asm/ipc.h> /* for ipc_kludge */
3220
3221static inline int sys_ipc(unsigned call, int first, int second, int third, void *ptr)
3222{
3223 return my_do_syscall5(__NR_ipc, call, first, second, third, (int)ptr);
3224}
3225
3226/* Turn a blocking msgsnd() into a polling non-blocking one, so that
3227 other threads make progress */
sewardjf220ccc2002-10-23 21:53:49 +00003228int VGL_(msgsnd)(int msgid, const void *msgp, size_t msgsz, int msgflg)
sewardjd5bef572002-10-23 21:49:33 +00003229{
3230 struct vki_timespec nanosleep_interval;
3231 int err;
3232
3233 ensure_valgrind("msgsnd");
3234
3235 nanosleep_interval.tv_sec = 0;
3236 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
3237
3238 if (msgflg & IPC_NOWAIT) {
3239 /* If we aren't blocking anyway, just do it */
3240 err = sys_ipc(11, msgid, msgsz, msgflg, (void *)msgp);
3241 } else {
3242 /* Otherwise poll on the queue to let other things run */
3243 for(;;) {
3244 err = sys_ipc(11, msgid, msgsz, msgflg | IPC_NOWAIT, (void *)msgp);
3245
3246 if (err != -EAGAIN)
3247 break;
3248
3249 (void)my_do_syscall2(__NR_nanosleep,
3250 (int)(&nanosleep_interval), (int)NULL);
3251 }
3252 }
3253
3254 if (is_kerror(err)) {
3255 *(__errno_location()) = -err;
3256 return -1;
3257 }
3258 return 0;
3259}
3260
3261/* Turn a blocking msgrcv() into a polling non-blocking one, so that
3262 other threads make progress */
sewardjf220ccc2002-10-23 21:53:49 +00003263int VGL_(msgrcv)( int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg )
sewardjd5bef572002-10-23 21:49:33 +00003264{
3265 struct vki_timespec nanosleep_interval;
3266 int err;
3267 struct ipc_kludge tmp;
3268
3269 ensure_valgrind("msgrcv");
3270
3271 nanosleep_interval.tv_sec = 0;
3272 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
3273
3274 tmp.msgp = msgp;
3275 tmp.msgtyp = msgtyp;
3276
3277 if (msgflg & IPC_NOWAIT) {
3278 /* If we aren't blocking anyway, just do it */
3279 err = sys_ipc(12, msqid, msgsz, msgflg, &tmp );
3280 } else {
3281 /* Otherwise poll on the queue to let other things run */
3282 for(;;) {
3283 err = sys_ipc(12, msqid, msgsz, msgflg | IPC_NOWAIT, &tmp );
3284
3285 if (err != -ENOMSG)
3286 break;
3287
3288 (void)my_do_syscall2(__NR_nanosleep,
3289 (int)(&nanosleep_interval), (int)NULL);
3290 }
3291 }
3292
3293 if (is_kerror(err)) {
3294 *(__errno_location()) = -err;
3295 return -1;
3296 }
3297
3298 return 0;
3299}
3300
3301
3302
3303/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00003304 B'stard.
3305 ------------------------------------------------------------------ */
3306
3307# define strong_alias(name, aliasname) \
3308 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
3309
sewardj5905fae2002-04-26 13:25:00 +00003310# define weak_alias(name, aliasname) \
3311 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00003312
sewardj5905fae2002-04-26 13:25:00 +00003313strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
3314strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
3315strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
3316strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
3317 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
3318strong_alias(__pthread_mutex_init, pthread_mutex_init)
3319strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
3320strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
3321strong_alias(__pthread_once, pthread_once)
3322strong_alias(__pthread_atfork, pthread_atfork)
3323strong_alias(__pthread_key_create, pthread_key_create)
3324strong_alias(__pthread_getspecific, pthread_getspecific)
3325strong_alias(__pthread_setspecific, pthread_setspecific)
3326
sewardjd529a442002-05-04 19:49:21 +00003327#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00003328strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00003329#endif
3330
sewardj5905fae2002-04-26 13:25:00 +00003331strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00003332strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00003333strong_alias(lseek, __lseek)
3334strong_alias(open, __open)
3335strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00003336strong_alias(read, __read)
3337strong_alias(wait, __wait)
3338strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00003339strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00003340strong_alias(send, __send)
3341
sewardj726c4122002-05-16 23:39:10 +00003342weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00003343weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00003344weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00003345weak_alias(__vfork, vfork)
sewardj7f6456d2002-05-21 00:51:21 +00003346
sewardjf0b06452002-06-04 08:38:04 +00003347weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00003348
3349/*--------------------------------------------------*/
3350
sewardj5905fae2002-04-26 13:25:00 +00003351weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00003352weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00003353weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00003354
sewardja1ac5cb2002-05-27 13:00:05 +00003355weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
3356weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
3357weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
3358weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
3359
sewardj060b04f2002-04-26 21:01:13 +00003360
sewardj3b13f0e2002-04-25 20:17:29 +00003361/* I've no idea what these are, but they get called quite a lot.
3362 Anybody know? */
3363
3364#undef _IO_flockfile
3365void _IO_flockfile ( _IO_FILE * file )
3366{
sewardj853f55d2002-04-26 00:27:53 +00003367 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003368}
sewardj5905fae2002-04-26 13:25:00 +00003369weak_alias(_IO_flockfile, flockfile);
3370
sewardj3b13f0e2002-04-25 20:17:29 +00003371
3372#undef _IO_funlockfile
3373void _IO_funlockfile ( _IO_FILE * file )
3374{
sewardj853f55d2002-04-26 00:27:53 +00003375 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003376}
sewardj5905fae2002-04-26 13:25:00 +00003377weak_alias(_IO_funlockfile, funlockfile);
3378
sewardj3b13f0e2002-04-25 20:17:29 +00003379
sewardjd4f2c712002-04-30 10:20:10 +00003380/* This doesn't seem to be needed to simulate libpthread.so's external
3381 interface, but many people complain about its absence. */
3382
3383strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
3384weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00003385
3386
3387/*--------------------------------------------------------------------*/
3388/*--- end vg_libpthread.c ---*/
3389/*--------------------------------------------------------------------*/