blob: 771ed74de594f3a60ccaa9c194e8c6593d5c5c8f [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
sewardje663cb92002-04-12 10:26:32 +000068
sewardj2d94c112002-06-03 01:25:54 +000069#include <stdio.h>
70
sewardj705d3cb2002-05-23 13:13:12 +000071
72/* ---------------------------------------------------------------------
73 Forwardses.
74 ------------------------------------------------------------------ */
75
76static void wait_for_fd_to_be_readable_or_erring ( int fd );
77
sewardj9a2224b2002-06-19 10:17:40 +000078static
sewardj08c7f012002-10-07 23:56:55 +000079int my_do_syscall1 ( int syscallno, int arg1 );
80
81static
sewardj9a2224b2002-06-19 10:17:40 +000082int my_do_syscall2 ( int syscallno,
83 int arg1, int arg2 );
84
sewardj08c7f012002-10-07 23:56:55 +000085static
86int my_do_syscall3 ( int syscallno,
87 int arg1, int arg2, int arg3 );
88
89
90#ifdef GLIBC_2_3
91 /* kludge by JRS (not from glibc) ... */
92 typedef void* __locale_t;
93
94 /* Copied from locale/locale.h in glibc-2.2.93 sources */
95 /* This value can be passed to `uselocale' and may be returned by
96 it. Passing this value to any other function has undefined
97 behavior. */
98# define LC_GLOBAL_LOCALE ((__locale_t) -1L)
99 extern __locale_t __uselocale ( __locale_t );
100#endif
101
sewardj00a66b12002-10-12 16:42:35 +0000102static
103void init_libc_tsd_keys ( void );
104
sewardj705d3cb2002-05-23 13:13:12 +0000105
sewardje663cb92002-04-12 10:26:32 +0000106/* ---------------------------------------------------------------------
107 Helpers. We have to be pretty self-sufficient.
108 ------------------------------------------------------------------ */
109
sewardj436e0582002-04-26 14:31:40 +0000110/* Number of times any given error message is printed. */
111#define N_MOANS 3
112
sewardj45b4b372002-04-16 22:50:32 +0000113/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
114 Returns 0 (none) if not running on Valgrind. */
115static
116int get_pt_trace_level ( void )
117{
118 int res;
119 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
120 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
121 0, 0, 0, 0);
122 return res;
123}
124
sewardje663cb92002-04-12 10:26:32 +0000125static
sewardj2d94c112002-06-03 01:25:54 +0000126void my_exit ( int arg )
sewardje663cb92002-04-12 10:26:32 +0000127{
sewardj08c7f012002-10-07 23:56:55 +0000128 my_do_syscall1(__NR_exit, arg);
129 /*NOTREACHED*/
sewardje663cb92002-04-12 10:26:32 +0000130}
131
sewardj08c7f012002-10-07 23:56:55 +0000132static
133void my_write ( int fd, const void *buf, int count )
134{
135 my_do_syscall3(__NR_write, fd, (int)buf, count );
136}
sewardje663cb92002-04-12 10:26:32 +0000137
sewardj68b2dd92002-05-10 21:03:56 +0000138/* We need this guy -- it's in valgrind.so. */
139extern void VG_(startup) ( void );
140
141
142/* Just start up Valgrind if it's not already going. VG_(startup)()
143 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000144static __inline__
sewardje663cb92002-04-12 10:26:32 +0000145void ensure_valgrind ( char* caller )
146{
sewardj68b2dd92002-05-10 21:03:56 +0000147 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000148}
149
sewardjbea1caa2002-05-10 23:20:58 +0000150/* While we're at it ... hook our own startup function into this
151 game. */
152__asm__ (
153 ".section .init\n"
154 "\tcall vgPlain_startup"
155);
156
sewardje663cb92002-04-12 10:26:32 +0000157
158static
sewardj3b5d8862002-04-20 13:53:23 +0000159__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +0000160void barf ( char* str )
161{
162 char buf[100];
163 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000164 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000165 strcat(buf, str);
166 strcat(buf, "\n\n");
sewardj08c7f012002-10-07 23:56:55 +0000167 my_write(2, buf, strlen(buf));
sewardj2d94c112002-06-03 01:25:54 +0000168 my_exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000169 /* We have to persuade gcc into believing this doesn't return. */
170 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000171}
172
173
sewardj2a3d28c2002-04-14 13:27:00 +0000174static void ignored ( char* msg )
175{
sewardj436e0582002-04-26 14:31:40 +0000176 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000177 char* ig = "valgrind's libpthread.so: IGNORED call to: ";
sewardj08c7f012002-10-07 23:56:55 +0000178 my_write(2, ig, strlen(ig));
179 my_write(2, msg, strlen(msg));
sewardj45b4b372002-04-16 22:50:32 +0000180 ig = "\n";
sewardj08c7f012002-10-07 23:56:55 +0000181 my_write(2, ig, strlen(ig));
sewardj45b4b372002-04-16 22:50:32 +0000182 }
sewardj2a3d28c2002-04-14 13:27:00 +0000183}
184
sewardj30671ff2002-04-21 00:13:57 +0000185static void kludged ( char* msg )
186{
sewardj436e0582002-04-26 14:31:40 +0000187 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000188 char* ig = "valgrind's libpthread.so: KLUDGED call to: ";
sewardj08c7f012002-10-07 23:56:55 +0000189 my_write(2, ig, strlen(ig));
190 my_write(2, msg, strlen(msg));
sewardj439d45e2002-05-03 20:43:10 +0000191 ig = "\n";
sewardj08c7f012002-10-07 23:56:55 +0000192 my_write(2, ig, strlen(ig));
sewardj439d45e2002-05-03 20:43:10 +0000193 }
194}
195
196static void not_inside ( char* msg )
197{
sewardj68b2dd92002-05-10 21:03:56 +0000198 VG_(startup)();
sewardj30671ff2002-04-21 00:13:57 +0000199}
200
sewardjccef2e62002-05-29 19:26:32 +0000201__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000202void vgPlain_unimp ( char* what )
203{
sewardj439d45e2002-05-03 20:43:10 +0000204 char* ig = "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ";
sewardj08c7f012002-10-07 23:56:55 +0000205 my_write(2, ig, strlen(ig));
206 my_write(2, what, strlen(what));
sewardj3b13f0e2002-04-25 20:17:29 +0000207 ig = "\n";
sewardj08c7f012002-10-07 23:56:55 +0000208 my_write(2, ig, strlen(ig));
sewardj3b13f0e2002-04-25 20:17:29 +0000209 barf("Please report this bug to me at: jseward@acm.org");
210}
211
sewardje663cb92002-04-12 10:26:32 +0000212
sewardj457cc472002-06-03 23:13:47 +0000213static
sewardj2d94c112002-06-03 01:25:54 +0000214void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
215{
216 static Bool entered = False;
217 if (entered)
218 my_exit(2);
219 entered = True;
220 fprintf(stderr, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
221 "valgrind", file, line, fn, expr );
222 fprintf(stderr, "Please report this bug to me at: %s\n\n",
223 VG_EMAIL_ADDR);
224 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;
sewardj436e0582002-04-26 14:31:40 +0000894 static int moans = N_MOANS;
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 {
901 if (moans-- > 0)
902 not_inside("pthread_mutex_lock");
903 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000904 }
905}
906
sewardj439d45e2002-05-03 20:43:10 +0000907
sewardj5905fae2002-04-26 13:25:00 +0000908int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000909{
910 int res;
sewardj436e0582002-04-26 14:31:40 +0000911 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000912 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000913 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
914 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
915 mutex, 0, 0, 0);
916 return res;
sewardj439d45e2002-05-03 20:43:10 +0000917 } else {
918 if (moans-- > 0)
919 not_inside("pthread_mutex_trylock");
920 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000921 }
922}
923
sewardj439d45e2002-05-03 20:43:10 +0000924
sewardj5905fae2002-04-26 13:25:00 +0000925int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000926{
927 int res;
sewardj436e0582002-04-26 14:31:40 +0000928 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000929 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000930 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
931 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
932 mutex, 0, 0, 0);
933 return res;
sewardj439d45e2002-05-03 20:43:10 +0000934 } else {
935 if (moans-- > 0)
936 not_inside("pthread_mutex_unlock");
937 return 0;
sewardje663cb92002-04-12 10:26:32 +0000938 }
939}
940
sewardj439d45e2002-05-03 20:43:10 +0000941
sewardj5905fae2002-04-26 13:25:00 +0000942int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000943{
sewardj604ec3c2002-04-18 22:38:41 +0000944 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
945 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +0000946 if (mutex->__m_count > 0) {
947 pthread_error("pthread_mutex_destroy: "
948 "mutex is still in use");
sewardj604ec3c2002-04-18 22:38:41 +0000949 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +0000950 }
951 mutex->__m_count = 0;
952 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
953 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
954 return 0;
sewardje663cb92002-04-12 10:26:32 +0000955}
956
957
sewardjf8f819e2002-04-17 23:21:37 +0000958/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000959 CONDITION VARIABLES
960 ------------------------------------------------ */
961
962/* LinuxThreads supports no attributes for conditions. Hence ... */
963
964int pthread_condattr_init(pthread_condattr_t *attr)
965{
966 return 0;
967}
968
sewardj0738a592002-04-20 13:59:33 +0000969int pthread_condattr_destroy(pthread_condattr_t *attr)
970{
971 return 0;
972}
sewardj6072c362002-04-19 14:40:57 +0000973
974int pthread_cond_init( pthread_cond_t *cond,
975 const pthread_condattr_t *cond_attr)
976{
977 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
978 return 0;
979}
980
sewardjf854f472002-04-21 12:19:41 +0000981int pthread_cond_destroy(pthread_cond_t *cond)
982{
983 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000984 static int moans = N_MOANS;
985 if (moans-- > 0)
986 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000987 return 0;
988}
sewardj6072c362002-04-19 14:40:57 +0000989
990/* ---------------------------------------------------
991 SCHEDULING
992 ------------------------------------------------ */
993
994/* This is completely bogus. */
995int pthread_getschedparam(pthread_t target_thread,
996 int *policy,
997 struct sched_param *param)
998{
sewardj436e0582002-04-26 14:31:40 +0000999 static int moans = N_MOANS;
1000 if (moans-- > 0)
1001 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +00001002 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +00001003# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +00001004 if (param) param->sched_priority = 0; /* who knows */
1005# else
sewardj6072c362002-04-19 14:40:57 +00001006 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +00001007# endif
sewardj6072c362002-04-19 14:40:57 +00001008 return 0;
1009}
1010
1011int pthread_setschedparam(pthread_t target_thread,
1012 int policy,
1013 const struct sched_param *param)
1014{
sewardj436e0582002-04-26 14:31:40 +00001015 static int moans = N_MOANS;
1016 if (moans-- > 0)
1017 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +00001018 return 0;
1019}
1020
sewardj3b5d8862002-04-20 13:53:23 +00001021int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
1022{
1023 int res;
1024 ensure_valgrind("pthread_cond_wait");
1025 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1026 VG_USERREQ__PTHREAD_COND_WAIT,
1027 cond, mutex, 0, 0);
1028 return res;
1029}
1030
sewardj5f07b662002-04-23 16:52:51 +00001031int pthread_cond_timedwait ( pthread_cond_t *cond,
1032 pthread_mutex_t *mutex,
1033 const struct timespec *abstime )
1034{
1035 int res;
1036 unsigned int ms_now, ms_end;
1037 struct timeval timeval_now;
1038 unsigned long long int ull_ms_now_after_1970;
1039 unsigned long long int ull_ms_end_after_1970;
1040
1041 ensure_valgrind("pthread_cond_timedwait");
1042 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1043 VG_USERREQ__READ_MILLISECOND_TIMER,
1044 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001045 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001046 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +00001047 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001048
1049 ull_ms_now_after_1970
1050 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
1051 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
1052 ull_ms_end_after_1970
1053 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
1054 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +00001055 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
1056 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +00001057 ms_end
1058 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
1059 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1060 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
1061 cond, mutex, ms_end, 0);
1062 return res;
1063}
1064
1065
sewardj3b5d8862002-04-20 13:53:23 +00001066int pthread_cond_signal(pthread_cond_t *cond)
1067{
1068 int res;
1069 ensure_valgrind("pthread_cond_signal");
1070 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1071 VG_USERREQ__PTHREAD_COND_SIGNAL,
1072 cond, 0, 0, 0);
1073 return res;
1074}
1075
1076int pthread_cond_broadcast(pthread_cond_t *cond)
1077{
1078 int res;
1079 ensure_valgrind("pthread_cond_broadcast");
1080 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1081 VG_USERREQ__PTHREAD_COND_BROADCAST,
1082 cond, 0, 0, 0);
1083 return res;
1084}
1085
sewardj6072c362002-04-19 14:40:57 +00001086
1087/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001088 CANCELLATION
1089 ------------------------------------------------ */
1090
sewardj853f55d2002-04-26 00:27:53 +00001091int pthread_setcancelstate(int state, int *oldstate)
1092{
sewardj20917d82002-05-28 01:36:45 +00001093 int res;
1094 ensure_valgrind("pthread_setcancelstate");
1095 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +00001096 && state != PTHREAD_CANCEL_DISABLE) {
1097 pthread_error("pthread_setcancelstate: "
1098 "invalid state");
sewardj20917d82002-05-28 01:36:45 +00001099 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001100 }
sewardj2d94c112002-06-03 01:25:54 +00001101 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1102 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001103 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1104 VG_USERREQ__SET_CANCELSTATE,
1105 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001106 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001107 if (oldstate)
1108 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001109 return 0;
1110}
1111
sewardje663cb92002-04-12 10:26:32 +00001112int pthread_setcanceltype(int type, int *oldtype)
1113{
sewardj20917d82002-05-28 01:36:45 +00001114 int res;
1115 ensure_valgrind("pthread_setcanceltype");
1116 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001117 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1118 pthread_error("pthread_setcanceltype: "
1119 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001120 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001121 }
sewardj2d94c112002-06-03 01:25:54 +00001122 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1123 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001124 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1125 VG_USERREQ__SET_CANCELTYPE,
1126 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001127 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001128 if (oldtype)
1129 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001130 return 0;
1131}
1132
sewardje663cb92002-04-12 10:26:32 +00001133int pthread_cancel(pthread_t thread)
1134{
1135 int res;
1136 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001137 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1138 VG_USERREQ__SET_CANCELPEND,
1139 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001140 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001141 return res;
1142}
1143
sewardjd140e442002-05-29 01:21:19 +00001144static __inline__
1145void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001146{
sewardj20917d82002-05-28 01:36:45 +00001147 int res;
njn25e49d8e72002-09-23 09:36:25 +00001148 ensure_valgrind("__my_pthread_testcancel");
sewardj20917d82002-05-28 01:36:45 +00001149 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1150 VG_USERREQ__TESTCANCEL,
1151 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001152 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001153}
1154
sewardjd140e442002-05-29 01:21:19 +00001155void pthread_testcancel ( void )
1156{
1157 __my_pthread_testcancel();
1158}
1159
sewardj20917d82002-05-28 01:36:45 +00001160
sewardjef037c72002-05-30 00:40:03 +00001161/* Not really sure what this is for. I suspect for doing the POSIX
1162 requirements for fork() and exec(). We do this internally anyway
1163 whenever those syscalls are observed, so this could be superfluous,
1164 but hey ...
1165*/
sewardj853f55d2002-04-26 00:27:53 +00001166void __pthread_kill_other_threads_np ( void )
1167{
sewardjef037c72002-05-30 00:40:03 +00001168 int res;
1169 ensure_valgrind("__pthread_kill_other_threads_np");
1170 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1171 VG_USERREQ__NUKE_OTHER_THREADS,
1172 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001173 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001174}
1175
sewardje663cb92002-04-12 10:26:32 +00001176
sewardjf8f819e2002-04-17 23:21:37 +00001177/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001178 SIGNALS
1179 ------------------------------------------------ */
1180
1181#include <signal.h>
1182
1183int pthread_sigmask(int how, const sigset_t *newmask,
1184 sigset_t *oldmask)
1185{
1186 int res;
1187
1188 /* A bit subtle, because the scheduler expects newmask and oldmask
1189 to be vki_sigset_t* rather than sigset_t*, and the two are
1190 different. Fortunately the first 64 bits of a sigset_t are
1191 exactly a vki_sigset_t, so we just pass the pointers through
1192 unmodified. Haaaack!
1193
1194 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001195 constants to VKI_ constants, so that the former do not have to
1196 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001197
1198 ensure_valgrind("pthread_sigmask");
1199
1200 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001201 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1202 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1203 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001204 default: pthread_error("pthread_sigmask: invalid how");
1205 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001206 }
1207
1208 /* Crude check */
1209 if (newmask == NULL)
1210 return EFAULT;
1211
1212 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1213 VG_USERREQ__PTHREAD_SIGMASK,
1214 how, newmask, oldmask, 0);
1215
1216 /* The scheduler tells us of any memory violations. */
1217 return res == 0 ? 0 : EFAULT;
1218}
1219
1220
1221int sigwait ( const sigset_t* set, int* sig )
1222{
1223 int res;
1224 ensure_valgrind("sigwait");
1225 /* As with pthread_sigmask we deliberately confuse sigset_t with
1226 vki_ksigset_t. */
1227 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1228 VG_USERREQ__SIGWAIT,
1229 set, sig, 0, 0);
1230 return res;
1231}
1232
1233
sewardj018f7622002-05-15 21:13:39 +00001234int pthread_kill(pthread_t thread, int signo)
1235{
1236 int res;
1237 ensure_valgrind("pthread_kill");
1238 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1239 VG_USERREQ__PTHREAD_KILL,
1240 thread, signo, 0, 0);
1241 return res;
1242}
1243
1244
sewardj3665ded2002-05-16 16:57:25 +00001245/* Copied verbatim from Linuxthreads */
1246/* Redefine raise() to send signal to calling thread only,
1247 as per POSIX 1003.1c */
1248int raise (int sig)
1249{
1250 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001251 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001252 return 0;
sewardj4dced352002-06-04 22:54:20 +00001253 } else {
sewardj3665ded2002-05-16 16:57:25 +00001254 errno = retcode;
1255 return -1;
1256 }
1257}
1258
1259
sewardj9a2224b2002-06-19 10:17:40 +00001260int pause ( void )
1261{
1262 unsigned int n_orig, n_now;
1263 struct vki_timespec nanosleep_interval;
1264 ensure_valgrind("pause");
1265
1266 /* This is surely a cancellation point. */
1267 __my_pthread_testcancel();
1268
1269 VALGRIND_MAGIC_SEQUENCE(n_orig, 0xFFFFFFFF /* default */,
1270 VG_USERREQ__GET_N_SIGS_RETURNED,
1271 0, 0, 0, 0);
1272 my_assert(n_orig != 0xFFFFFFFF);
1273
1274 while (1) {
1275 VALGRIND_MAGIC_SEQUENCE(n_now, 0xFFFFFFFF /* default */,
1276 VG_USERREQ__GET_N_SIGS_RETURNED,
1277 0, 0, 0, 0);
1278 my_assert(n_now != 0xFFFFFFFF);
1279 my_assert(n_now >= n_orig);
1280 if (n_now != n_orig) break;
1281
1282 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001283 nanosleep_interval.tv_nsec = 12 * 1000 * 1000; /* 12 milliseconds */
sewardj9a2224b2002-06-19 10:17:40 +00001284 /* It's critical here that valgrind's nanosleep implementation
1285 is nonblocking. */
1286 (void)my_do_syscall2(__NR_nanosleep,
1287 (int)(&nanosleep_interval), (int)NULL);
1288 }
1289
1290 * (__errno_location()) = EINTR;
1291 return -1;
1292}
1293
1294
sewardjb48e5002002-05-13 00:16:03 +00001295/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001296 THREAD-SPECIFICs
1297 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001298
sewardj00a66b12002-10-12 16:42:35 +00001299static
1300int key_is_valid (pthread_key_t key)
1301{
1302 int res;
1303 VALGRIND_MAGIC_SEQUENCE(res, 2 /* default */,
1304 VG_USERREQ__PTHREAD_KEY_VALIDATE,
1305 key, 0, 0, 0);
1306 my_assert(res != 2);
1307 return res;
1308}
1309
1310
1311/* Returns NULL if thread is invalid. Otherwise, if the thread
1312 already has a specifics area, return that. Otherwise allocate it
1313 one. */
1314static
1315void** get_or_allocate_specifics_ptr ( pthread_t thread )
1316{
1317 int res, i;
1318 void** specifics_ptr;
1319 ensure_valgrind("get_or_allocate_specifics_ptr");
1320
1321 /* Returns zero if the thread has no specific_ptr. One if thread
1322 is invalid. Otherwise, the specific_ptr value. This is
1323 allocated with my_malloc and so is aligned and cannot be
1324 confused with 1 or 3. */
1325 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
1326 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
1327 thread, 0, 0, 0);
1328 my_assert(specifics_ptr != (void**)3);
1329
1330 if (specifics_ptr == (void**)1)
1331 return NULL; /* invalid thread */
1332
1333 if (specifics_ptr != NULL)
1334 return specifics_ptr; /* already has a specifics ptr. */
1335
1336 /* None yet ... allocate a new one. Should never fail. */
1337 specifics_ptr = my_malloc( VG_N_THREAD_KEYS * sizeof(void*) );
1338 my_assert(specifics_ptr != NULL);
1339
1340 VALGRIND_MAGIC_SEQUENCE(res, -1 /* default */,
1341 VG_USERREQ__PTHREAD_SETSPECIFIC_PTR,
1342 specifics_ptr, 0, 0, 0);
1343 my_assert(res == 0);
1344
1345 /* POSIX sez: "Upon thread creation, the value NULL shall be
1346 associated with all defined keys in the new thread." This
1347 allocation is in effect a delayed allocation of the specific
1348 data for a thread, at its first-use. Hence we initialise it
1349 here. */
1350 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
1351 specifics_ptr[i] = NULL;
1352 }
1353
1354 return specifics_ptr;
1355}
1356
1357
sewardj5905fae2002-04-26 13:25:00 +00001358int __pthread_key_create(pthread_key_t *key,
1359 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001360{
sewardj00a66b12002-10-12 16:42:35 +00001361 void** specifics_ptr;
1362 int res, i;
sewardj5f07b662002-04-23 16:52:51 +00001363 ensure_valgrind("pthread_key_create");
sewardj00a66b12002-10-12 16:42:35 +00001364
1365 /* This writes *key if successful. It should never fail. */
1366 VALGRIND_MAGIC_SEQUENCE(res, 1 /* default */,
sewardj5f07b662002-04-23 16:52:51 +00001367 VG_USERREQ__PTHREAD_KEY_CREATE,
1368 key, destr_function, 0, 0);
sewardj00a66b12002-10-12 16:42:35 +00001369 my_assert(res == 0);
1370
1371 /* POSIX sez: "Upon key creation, the value NULL shall be
1372 associated with the new key in all active threads." */
1373 for (i = 0; i < VG_N_THREADS; i++) {
1374 specifics_ptr = get_or_allocate_specifics_ptr(i);
1375 /* we get NULL if i is an invalid thread. */
1376 if (specifics_ptr != NULL)
1377 specifics_ptr[*key] = NULL;
1378 }
1379
sewardj5f07b662002-04-23 16:52:51 +00001380 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001381}
1382
1383int pthread_key_delete(pthread_key_t key)
1384{
sewardj00a66b12002-10-12 16:42:35 +00001385 int res;
1386 ensure_valgrind("pthread_key_create");
1387 if (!key_is_valid(key))
1388 return EINVAL;
1389 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1390 VG_USERREQ__PTHREAD_KEY_DELETE,
1391 key, 0, 0, 0);
1392 my_assert(res == 0);
sewardj5e5fa512002-04-14 13:13:05 +00001393 return 0;
1394}
1395
sewardj5905fae2002-04-26 13:25:00 +00001396int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001397{
sewardj00a66b12002-10-12 16:42:35 +00001398 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001399 ensure_valgrind("pthread_setspecific");
sewardj00a66b12002-10-12 16:42:35 +00001400
1401 if (!key_is_valid(key))
1402 return EINVAL;
1403
1404 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1405 specifics_ptr[key] = (void*)pointer;
1406 return 0;
sewardj5e5fa512002-04-14 13:13:05 +00001407}
1408
sewardj5905fae2002-04-26 13:25:00 +00001409void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001410{
sewardj00a66b12002-10-12 16:42:35 +00001411 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001412 ensure_valgrind("pthread_getspecific");
sewardj00a66b12002-10-12 16:42:35 +00001413
1414 if (!key_is_valid(key))
1415 return NULL;
1416
1417 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1418 return specifics_ptr[key];
1419}
1420
1421
sewardj9aa918d2002-10-20 16:25:55 +00001422#ifdef GLIBC_2_3
sewardj00a66b12002-10-12 16:42:35 +00001423static
1424void ** __pthread_getspecific_addr(pthread_key_t key)
1425{
1426 void** specifics_ptr;
1427 ensure_valgrind("pthread_getspecific_addr");
1428
1429 if (!key_is_valid(key))
1430 return NULL;
1431
1432 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1433 return &(specifics_ptr[key]);
sewardj5e5fa512002-04-14 13:13:05 +00001434}
sewardj9aa918d2002-10-20 16:25:55 +00001435#endif
sewardjf8f819e2002-04-17 23:21:37 +00001436
1437/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001438 ONCEry
1439 ------------------------------------------------ */
1440
1441static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1442
1443
sewardj5905fae2002-04-26 13:25:00 +00001444int __pthread_once ( pthread_once_t *once_control,
1445 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001446{
1447 int res;
1448 ensure_valgrind("pthread_once");
1449
sewardj68b2dd92002-05-10 21:03:56 +00001450 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001451
sewardj68b2dd92002-05-10 21:03:56 +00001452 if (res != 0) {
sewardj89d3d852002-04-24 19:21:39 +00001453 barf("pthread_once: Looks like your program's "
1454 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001455 }
sewardj89d3d852002-04-24 19:21:39 +00001456
1457 if (*once_control == 0) {
1458 *once_control = 1;
1459 init_routine();
1460 }
1461
sewardj68b2dd92002-05-10 21:03:56 +00001462 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001463
1464 return 0;
1465}
1466
1467
1468/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001469 MISC
1470 ------------------------------------------------ */
1471
sewardj2cb00342002-06-28 01:46:26 +00001472static pthread_mutex_t pthread_atfork_lock
1473 = PTHREAD_MUTEX_INITIALIZER;
1474
sewardj5905fae2002-04-26 13:25:00 +00001475int __pthread_atfork ( void (*prepare)(void),
1476 void (*parent)(void),
1477 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001478{
sewardj2cb00342002-06-28 01:46:26 +00001479 int n, res;
1480 ForkHandlerEntry entry;
1481
1482 ensure_valgrind("pthread_atfork");
1483 __pthread_mutex_lock(&pthread_atfork_lock);
1484
1485 /* Fetch old counter */
1486 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1487 VG_USERREQ__GET_FHSTACK_USED,
1488 0, 0, 0, 0);
1489 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1490 if (n == VG_N_FORKHANDLERSTACK-1)
1491 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1492 "increase and recompile");
1493
1494 /* Add entry */
1495 entry.prepare = *prepare;
1496 entry.parent = *parent;
1497 entry.child = *child;
1498 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1499 VG_USERREQ__SET_FHSTACK_ENTRY,
1500 n, &entry, 0, 0);
1501 my_assert(res == 0);
1502
1503 /* Bump counter */
1504 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1505 VG_USERREQ__SET_FHSTACK_USED,
1506 n+1, 0, 0, 0);
1507 my_assert(res == 0);
1508
1509 __pthread_mutex_unlock(&pthread_atfork_lock);
1510 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001511}
1512
1513
sewardjbb990782002-05-08 02:01:14 +00001514__attribute__((weak))
1515void __pthread_initialize ( void )
1516{
sewardjbea1caa2002-05-10 23:20:58 +00001517 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001518}
1519
1520
sewardj853f55d2002-04-26 00:27:53 +00001521/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001522 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001523 ------------------------------------------------ */
1524
sewardj3b13f0e2002-04-25 20:17:29 +00001525#include <resolv.h>
1526static int thread_specific_errno[VG_N_THREADS];
1527static int thread_specific_h_errno[VG_N_THREADS];
1528static struct __res_state
1529 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001530
sewardj3b13f0e2002-04-25 20:17:29 +00001531int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001532{
1533 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001534 /* ensure_valgrind("__errno_location"); */
1535 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001536 VG_USERREQ__PTHREAD_GET_THREADID,
1537 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001538 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001539 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001540 barf("__errno_location: invalid ThreadId");
1541 return & thread_specific_errno[tid];
1542}
1543
1544int* __h_errno_location ( void )
1545{
1546 int tid;
1547 /* ensure_valgrind("__h_errno_location"); */
1548 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1549 VG_USERREQ__PTHREAD_GET_THREADID,
1550 0, 0, 0, 0);
1551 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001552 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001553 barf("__h_errno_location: invalid ThreadId");
1554 return & thread_specific_h_errno[tid];
1555}
1556
sewardjb0ff1032002-08-06 09:02:53 +00001557
1558#undef _res
1559extern struct __res_state _res;
1560
sewardj3b13f0e2002-04-25 20:17:29 +00001561struct __res_state* __res_state ( void )
1562{
1563 int tid;
1564 /* ensure_valgrind("__res_state"); */
1565 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1566 VG_USERREQ__PTHREAD_GET_THREADID,
1567 0, 0, 0, 0);
1568 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001569 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001570 barf("__res_state: invalid ThreadId");
sewardjb0ff1032002-08-06 09:02:53 +00001571 if (tid == 1)
1572 return & _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001573 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001574}
1575
1576
sewardj5716dbb2002-04-26 03:28:18 +00001577/* ---------------------------------------------------
1578 LIBC-PRIVATE SPECIFIC DATA
1579 ------------------------------------------------ */
1580
1581/* Relies on assumption that initial private data is NULL. This
1582 should be fixed somehow. */
1583
njn25e49d8e72002-09-23 09:36:25 +00001584/* The allowable keys (indices) (all 3 of them).
sewardj5716dbb2002-04-26 03:28:18 +00001585 From sysdeps/pthread/bits/libc-tsd.h
1586*/
sewardjcb7f08a2002-10-02 09:41:49 +00001587/* as per glibc anoncvs HEAD of 20021001. */
sewardj5716dbb2002-04-26 03:28:18 +00001588enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1589 _LIBC_TSD_KEY_DL_ERROR,
njn25e49d8e72002-09-23 09:36:25 +00001590 _LIBC_TSD_KEY_RPC_VARS,
sewardjcb7f08a2002-10-02 09:41:49 +00001591 _LIBC_TSD_KEY_LOCALE,
1592 _LIBC_TSD_KEY_CTYPE_B,
1593 _LIBC_TSD_KEY_CTYPE_TOLOWER,
1594 _LIBC_TSD_KEY_CTYPE_TOUPPER,
sewardj5716dbb2002-04-26 03:28:18 +00001595 _LIBC_TSD_KEY_N };
1596
1597/* Auto-initialising subsystem. libc_specifics_inited is set
1598 after initialisation. libc_specifics_inited_mx guards it. */
1599static int libc_specifics_inited = 0;
1600static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1601
sewardj00a66b12002-10-12 16:42:35 +00001602
sewardj5716dbb2002-04-26 03:28:18 +00001603/* These are the keys we must initialise the first time. */
sewardjcb7f08a2002-10-02 09:41:49 +00001604static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N];
sewardj5716dbb2002-04-26 03:28:18 +00001605
sewardj00a66b12002-10-12 16:42:35 +00001606
sewardjcb7f08a2002-10-02 09:41:49 +00001607/* Initialise the keys, if they are not already initialised. */
sewardj5716dbb2002-04-26 03:28:18 +00001608static
1609void init_libc_tsd_keys ( void )
1610{
1611 int res, i;
1612 pthread_key_t k;
1613
sewardj08c7f012002-10-07 23:56:55 +00001614 /* Don't fall into deadlock if we get called again whilst we still
1615 hold the lock, via the __uselocale() call herein. */
1616 if (libc_specifics_inited != 0)
1617 return;
1618
1619 /* Take the lock. */
sewardj00a66b12002-10-12 16:42:35 +00001620 res = __pthread_mutex_lock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001621 if (res != 0) barf("init_libc_tsd_keys: lock");
1622
sewardj08c7f012002-10-07 23:56:55 +00001623 /* Now test again, to be sure there is no mistake. */
1624 if (libc_specifics_inited != 0) {
sewardj00a66b12002-10-12 16:42:35 +00001625 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj08c7f012002-10-07 23:56:55 +00001626 if (res != 0) barf("init_libc_tsd_keys: unlock(1)");
1627 return;
sewardj5716dbb2002-04-26 03:28:18 +00001628 }
1629
sewardj08c7f012002-10-07 23:56:55 +00001630 /* Actually do the initialisation. */
1631 /* printf("INIT libc specifics\n"); */
1632 for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
sewardj00a66b12002-10-12 16:42:35 +00001633 res = __pthread_key_create(&k, NULL);
sewardj08c7f012002-10-07 23:56:55 +00001634 if (res != 0) barf("init_libc_tsd_keys: create");
1635 libc_specifics_keys[i] = k;
1636 }
1637
1638 /* Signify init done. */
1639 libc_specifics_inited = 1;
1640
1641# ifdef GLIBC_2_3
1642 /* Set the initialising thread's locale to the global (default)
sewardj00a66b12002-10-12 16:42:35 +00001643 locale. A hack in support of glibc-2.3. This does the biz for
1644 the root thread. For all other threads we run this in
1645 thread_wrapper(), which does the real work of
1646 pthread_create(). */
1647 /* assert that we are the root thread. I don't know if this is
1648 really a valid assertion to make; if it breaks I'll reconsider
1649 it. */
1650 my_assert(pthread_self() == 1);
sewardj08c7f012002-10-07 23:56:55 +00001651 __uselocale(LC_GLOBAL_LOCALE);
1652# endif
1653
1654 /* Unlock and return. */
sewardj00a66b12002-10-12 16:42:35 +00001655 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001656 if (res != 0) barf("init_libc_tsd_keys: unlock");
1657}
1658
1659
1660static int
1661libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1662 const void * pointer )
1663{
sewardjcb7f08a2002-10-02 09:41:49 +00001664 int res;
sewardj5716dbb2002-04-26 03:28:18 +00001665 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardjcb7f08a2002-10-02 09:41:49 +00001666 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001667 barf("libc_internal_tsd_set: invalid key");
1668 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001669 res = __pthread_setspecific(libc_specifics_keys[key], pointer);
sewardj5716dbb2002-04-26 03:28:18 +00001670 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1671 return 0;
1672}
1673
1674static void *
1675libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1676{
sewardjcb7f08a2002-10-02 09:41:49 +00001677 void* v;
sewardj5716dbb2002-04-26 03:28:18 +00001678 /* printf("GET GET GET key %d\n", key); */
sewardjcb7f08a2002-10-02 09:41:49 +00001679 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001680 barf("libc_internal_tsd_get: invalid key");
1681 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001682 v = __pthread_getspecific(libc_specifics_keys[key]);
sewardj5716dbb2002-04-26 03:28:18 +00001683 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1684 return v;
1685}
1686
1687
sewardj70adeb22002-04-27 01:35:38 +00001688int (*__libc_internal_tsd_set)
1689 (enum __libc_tsd_key_t key, const void * pointer)
1690 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001691
sewardj70adeb22002-04-27 01:35:38 +00001692void* (*__libc_internal_tsd_get)
1693 (enum __libc_tsd_key_t key)
1694 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001695
1696
sewardj00a66b12002-10-12 16:42:35 +00001697#ifdef GLIBC_2_3
1698/* This one was first spotted be me in the glibc-2.2.93 sources. */
1699static void**
1700libc_internal_tsd_address ( enum __libc_tsd_key_t key )
1701{
1702 void** v;
1703 /* printf("ADDR ADDR ADDR key %d\n", key); */
1704 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
1705 barf("libc_internal_tsd_address: invalid key");
1706 init_libc_tsd_keys();
1707 v = __pthread_getspecific_addr(libc_specifics_keys[key]);
1708 return v;
1709}
1710
1711void ** (*__libc_internal_tsd_address)
1712 (enum __libc_tsd_key_t key)
1713 = libc_internal_tsd_address;
1714#endif
1715
1716
sewardje663cb92002-04-12 10:26:32 +00001717/* ---------------------------------------------------------------------
1718 These are here (I think) because they are deemed cancellation
1719 points by POSIX. For the moment we'll simply pass the call along
1720 to the corresponding thread-unaware (?) libc routine.
1721 ------------------------------------------------------------------ */
1722
sewardje663cb92002-04-12 10:26:32 +00001723#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001724#include <sys/types.h>
1725#include <sys/socket.h>
1726
sewardjd529a442002-05-04 19:49:21 +00001727#ifdef GLIBC_2_1
1728extern
1729int __sigaction
1730 (int signum,
1731 const struct sigaction *act,
1732 struct sigaction *oldact);
1733#else
sewardje663cb92002-04-12 10:26:32 +00001734extern
1735int __libc_sigaction
1736 (int signum,
1737 const struct sigaction *act,
1738 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001739#endif
sewardje663cb92002-04-12 10:26:32 +00001740int sigaction(int signum,
1741 const struct sigaction *act,
1742 struct sigaction *oldact)
1743{
sewardjd140e442002-05-29 01:21:19 +00001744 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001745# ifdef GLIBC_2_1
1746 return __sigaction(signum, act, oldact);
1747# else
sewardj45b4b372002-04-16 22:50:32 +00001748 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001749# endif
sewardje663cb92002-04-12 10:26:32 +00001750}
1751
1752
1753extern
1754int __libc_connect(int sockfd,
1755 const struct sockaddr *serv_addr,
1756 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001757__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001758int connect(int sockfd,
1759 const struct sockaddr *serv_addr,
1760 socklen_t addrlen)
1761{
sewardjd140e442002-05-29 01:21:19 +00001762 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001763 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001764}
1765
1766
1767extern
1768int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001769__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001770int fcntl(int fd, int cmd, long arg)
1771{
sewardjd140e442002-05-29 01:21:19 +00001772 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001773 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001774}
1775
1776
1777extern
1778ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001779__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001780ssize_t write(int fd, const void *buf, size_t count)
1781{
sewardjd140e442002-05-29 01:21:19 +00001782 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001783 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001784}
1785
1786
1787extern
1788ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001789__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001790ssize_t read(int fd, void *buf, size_t count)
1791{
sewardjd140e442002-05-29 01:21:19 +00001792 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001793 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001794}
1795
sewardjbe32e452002-04-24 20:29:58 +00001796
1797extern
sewardj853f55d2002-04-26 00:27:53 +00001798int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001799__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001800int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001801{
sewardjd140e442002-05-29 01:21:19 +00001802 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001803 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001804}
1805
sewardje663cb92002-04-12 10:26:32 +00001806
1807extern
sewardj853f55d2002-04-26 00:27:53 +00001808int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001809__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001810int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001811{
sewardjd140e442002-05-29 01:21:19 +00001812 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001813 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001814}
1815
1816
1817extern
1818int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001819__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001820int close(int fd)
1821{
sewardjd140e442002-05-29 01:21:19 +00001822 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001823 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001824}
1825
1826
1827extern
1828int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001829__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001830int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1831{
sewardjd140e442002-05-29 01:21:19 +00001832 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001833 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001834 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001835 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001836}
1837
1838
1839extern
sewardje663cb92002-04-12 10:26:32 +00001840pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001841__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001842pid_t waitpid(pid_t pid, int *status, int options)
1843{
sewardjd140e442002-05-29 01:21:19 +00001844 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001845 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001846}
1847
1848
1849extern
1850int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001851__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001852int nanosleep(const struct timespec *req, struct timespec *rem)
1853{
sewardjd140e442002-05-29 01:21:19 +00001854 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001855 return __libc_nanosleep(req, rem);
1856}
1857
sewardjbe32e452002-04-24 20:29:58 +00001858
sewardje663cb92002-04-12 10:26:32 +00001859extern
1860int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001861__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001862int fsync(int fd)
1863{
sewardjd140e442002-05-29 01:21:19 +00001864 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001865 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001866}
1867
sewardjbe32e452002-04-24 20:29:58 +00001868
sewardj70c75362002-04-13 04:18:32 +00001869extern
1870off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001871__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001872off_t lseek(int fildes, off_t offset, int whence)
1873{
sewardjd140e442002-05-29 01:21:19 +00001874 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001875 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001876}
1877
sewardjbe32e452002-04-24 20:29:58 +00001878
1879extern
1880__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001881__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001882__off64_t lseek64(int fildes, __off64_t offset, int whence)
1883{
sewardjd140e442002-05-29 01:21:19 +00001884 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001885 return __libc_lseek64(fildes, offset, whence);
1886}
1887
1888
sewardj726c4122002-05-16 23:39:10 +00001889extern
1890ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1891 __off64_t __offset);
1892ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1893 __off64_t __offset)
1894{
sewardjd140e442002-05-29 01:21:19 +00001895 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001896 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1897}
1898
1899
sewardja18e2102002-05-18 10:43:22 +00001900extern
1901ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1902 __off64_t __offset);
1903ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1904 __off64_t __offset)
1905{
sewardjd140e442002-05-29 01:21:19 +00001906 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001907 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1908}
1909
sewardj726c4122002-05-16 23:39:10 +00001910
sewardj39b93b12002-05-18 10:56:27 +00001911extern
1912ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1913__attribute__((weak))
1914ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1915{
sewardjd140e442002-05-29 01:21:19 +00001916 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001917 return __libc_pwrite(fd, buf, count, offset);
1918}
1919
1920
1921extern
1922ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1923__attribute__((weak))
1924ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1925{
sewardjd140e442002-05-29 01:21:19 +00001926 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001927 return __libc_pread(fd, buf, count, offset);
1928}
1929
1930
sewardj6af4b5d2002-04-16 04:40:49 +00001931extern
1932void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001933/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001934void longjmp(jmp_buf env, int val)
1935{
1936 __libc_longjmp(env, val);
1937}
1938
sewardjbe32e452002-04-24 20:29:58 +00001939
sewardj436c2db2002-06-18 09:07:54 +00001940extern void __libc_siglongjmp (sigjmp_buf env, int val)
1941 __attribute__ ((noreturn));
1942void siglongjmp(sigjmp_buf env, int val)
1943{
1944 kludged("siglongjmp (cleanup handlers are ignored)");
1945 __libc_siglongjmp(env, val);
1946}
1947
1948
sewardj6af4b5d2002-04-16 04:40:49 +00001949extern
1950int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001951__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001952int send(int s, const void *msg, size_t len, int flags)
1953{
sewardjd140e442002-05-29 01:21:19 +00001954 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001955 return __libc_send(s, msg, len, flags);
1956}
1957
sewardjbe32e452002-04-24 20:29:58 +00001958
sewardj1e8cdc92002-04-18 11:37:52 +00001959extern
1960int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001961__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001962int recv(int s, void *buf, size_t len, int flags)
1963{
sewardjd140e442002-05-29 01:21:19 +00001964 __my_pthread_testcancel();
sewardj1d6b3a22002-06-20 07:58:33 +00001965 wait_for_fd_to_be_readable_or_erring(s);
1966 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001967 return __libc_recv(s, buf, len, flags);
1968}
1969
sewardjbe32e452002-04-24 20:29:58 +00001970
sewardj3665ded2002-05-16 16:57:25 +00001971extern
1972int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1973__attribute__((weak))
1974int sendmsg(int s, const struct msghdr *msg, int flags)
1975{
sewardjd140e442002-05-29 01:21:19 +00001976 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001977 return __libc_sendmsg(s, msg, flags);
1978}
1979
1980
sewardj796d6a22002-04-24 02:28:34 +00001981extern
sewardj59da27a2002-06-06 08:33:54 +00001982int __libc_recvmsg(int s, struct msghdr *msg, int flags);
1983__attribute__((weak))
1984int recvmsg(int s, struct msghdr *msg, int flags)
1985{
1986 __my_pthread_testcancel();
1987 return __libc_recvmsg(s, msg, flags);
1988}
1989
1990
1991extern
sewardj436e0582002-04-26 14:31:40 +00001992int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1993 struct sockaddr *from, socklen_t *fromlen);
1994__attribute__((weak))
1995int recvfrom(int s, void *buf, size_t len, int flags,
1996 struct sockaddr *from, socklen_t *fromlen)
1997{
sewardjd140e442002-05-29 01:21:19 +00001998 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00001999 wait_for_fd_to_be_readable_or_erring(s);
2000 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00002001 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
2002}
2003
2004
2005extern
sewardj796d6a22002-04-24 02:28:34 +00002006int __libc_sendto(int s, const void *msg, size_t len, int flags,
2007 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00002008__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00002009int sendto(int s, const void *msg, size_t len, int flags,
2010 const struct sockaddr *to, socklen_t tolen)
2011{
sewardjd140e442002-05-29 01:21:19 +00002012 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00002013 return __libc_sendto(s, msg, len, flags, to, tolen);
2014}
2015
sewardjbe32e452002-04-24 20:29:58 +00002016
sewardj369b1702002-04-24 13:28:15 +00002017extern
2018int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00002019__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00002020int system(const char* str)
2021{
sewardjd140e442002-05-29 01:21:19 +00002022 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00002023 return __libc_system(str);
2024}
2025
sewardjbe32e452002-04-24 20:29:58 +00002026
sewardjab0b1c32002-04-24 19:26:47 +00002027extern
2028pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00002029__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00002030pid_t wait(int *status)
2031{
sewardjd140e442002-05-29 01:21:19 +00002032 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00002033 return __libc_wait(status);
2034}
2035
sewardj45b4b372002-04-16 22:50:32 +00002036
sewardj67f1d582002-05-24 02:11:32 +00002037extern
2038int __libc_msync(const void *start, size_t length, int flags);
2039__attribute__((weak))
2040int msync(const void *start, size_t length, int flags)
2041{
sewardjd140e442002-05-29 01:21:19 +00002042 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00002043 return __libc_msync(start, length, flags);
2044}
2045
sewardj5905fae2002-04-26 13:25:00 +00002046
sewardj2cb00342002-06-28 01:46:26 +00002047/*--- fork and its helper ---*/
2048
2049static
2050void run_fork_handlers ( int what )
2051{
2052 ForkHandlerEntry entry;
2053 int n_h, n_handlers, i, res;
2054
2055 my_assert(what == 0 || what == 1 || what == 2);
2056
2057 /* Fetch old counter */
2058 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2059 VG_USERREQ__GET_FHSTACK_USED,
2060 0, 0, 0, 0);
2061 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2062
2063 /* Prepare handlers (what == 0) are called in opposite order of
2064 calls to pthread_atfork. Parent and child handlers are called
2065 in the same order as calls to pthread_atfork. */
2066 if (what == 0)
2067 n_h = n_handlers - 1;
2068 else
2069 n_h = 0;
2070
2071 for (i = 0; i < n_handlers; i++) {
2072 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2073 VG_USERREQ__GET_FHSTACK_ENTRY,
2074 n_h, &entry, 0, 0);
2075 my_assert(res == 0);
2076 switch (what) {
2077 case 0: if (entry.prepare) entry.prepare();
2078 n_h--; break;
2079 case 1: if (entry.parent) entry.parent();
2080 n_h++; break;
2081 case 2: if (entry.child) entry.child();
2082 n_h++; break;
2083 default: barf("run_fork_handlers: invalid what");
2084 }
2085 }
2086
2087 if (what != 0 /* prepare */) {
2088 /* Empty out the stack. */
2089 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2090 VG_USERREQ__SET_FHSTACK_USED,
2091 0, 0, 0, 0);
2092 my_assert(res == 0);
2093 }
2094}
2095
2096extern
2097pid_t __libc_fork(void);
2098pid_t __fork(void)
2099{
2100 pid_t pid;
2101 __my_pthread_testcancel();
2102 __pthread_mutex_lock(&pthread_atfork_lock);
2103
2104 run_fork_handlers(0 /* prepare */);
2105 pid = __libc_fork();
2106 if (pid == 0) {
2107 /* I am the child */
2108 run_fork_handlers(2 /* child */);
2109 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2110 } else {
2111 /* I am the parent */
2112 run_fork_handlers(1 /* parent */);
2113 __pthread_mutex_unlock(&pthread_atfork_lock);
2114 }
2115 return pid;
2116}
2117
2118
njn25e49d8e72002-09-23 09:36:25 +00002119pid_t __vfork(void)
2120{
2121 return __fork();
2122}
sewardj2cb00342002-06-28 01:46:26 +00002123
2124
sewardj3b13f0e2002-04-25 20:17:29 +00002125/* ---------------------------------------------------------------------
2126 Nonblocking implementations of select() and poll(). This stuff will
2127 surely rot your mind.
2128 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00002129
sewardj08a4c3f2002-04-13 03:45:44 +00002130/*--------------------------------------------------*/
2131
2132#include "vg_kerneliface.h"
2133
2134static
2135__inline__
2136int is_kerror ( int res )
2137{
2138 if (res >= -4095 && res <= -1)
2139 return 1;
2140 else
2141 return 0;
2142}
2143
2144
2145static
2146int my_do_syscall1 ( int syscallno, int arg1 )
2147{
2148 int __res;
2149 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2150 : "=a" (__res)
2151 : "0" (syscallno),
2152 "d" (arg1) );
2153 return __res;
2154}
2155
2156static
2157int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00002158 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00002159{
2160 int __res;
2161 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2162 : "=a" (__res)
2163 : "0" (syscallno),
2164 "d" (arg1),
2165 "c" (arg2) );
2166 return __res;
2167}
2168
2169static
sewardjf854f472002-04-21 12:19:41 +00002170int my_do_syscall3 ( int syscallno,
2171 int arg1, int arg2, int arg3 )
2172{
2173 int __res;
2174 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
2175 : "=a" (__res)
2176 : "0" (syscallno),
2177 "S" (arg1),
2178 "c" (arg2),
2179 "d" (arg3) );
2180 return __res;
2181}
2182
sewardjd5bef572002-10-23 21:49:33 +00002183static inline
2184int my_do_syscall5 ( int syscallno,
2185 int arg1, int arg2, int arg3, int arg4, int arg5 )
2186{
2187 int __res;
2188 __asm__ volatile ("int $0x80"
2189 : "=a" (__res)
2190 : "0" (syscallno),
2191 "b" (arg1),
2192 "c" (arg2),
2193 "d" (arg3),
2194 "S" (arg4),
2195 "D" (arg5));
2196 return __res;
2197}
2198
sewardjf854f472002-04-21 12:19:41 +00002199static
sewardj08a4c3f2002-04-13 03:45:44 +00002200int do_syscall_select( int n,
2201 vki_fd_set* readfds,
2202 vki_fd_set* writefds,
2203 vki_fd_set* exceptfds,
2204 struct vki_timeval * timeout )
2205{
2206 int res;
2207 int args[5];
2208 args[0] = n;
2209 args[1] = (int)readfds;
2210 args[2] = (int)writefds;
2211 args[3] = (int)exceptfds;
2212 args[4] = (int)timeout;
2213 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00002214 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00002215}
2216
2217
2218/* This is a wrapper round select(), which makes it thread-safe,
2219 meaning that only this thread will block, rather than the entire
2220 process. This wrapper in turn depends on nanosleep() not to block
2221 the entire process, but I think (hope? suspect?) that POSIX
2222 pthreads guarantees that to be the case.
2223
2224 Basic idea is: modify the timeout parameter to select so that it
2225 returns immediately. Poll like this until select returns non-zero,
2226 indicating something interesting happened, or until our time is up.
njn25e49d8e72002-09-23 09:36:25 +00002227 Space out the polls with nanosleeps of say 11 milliseconds, which
sewardj08a4c3f2002-04-13 03:45:44 +00002228 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00002229
2230 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00002231 * (checked via my_assert) types fd_set and vki_fd_set are identical.
2232 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00002233 * (unchecked) libc error numbers (EINTR etc) are the negation of the
2234 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00002235*/
sewardj08a4c3f2002-04-13 03:45:44 +00002236
sewardj5905fae2002-04-26 13:25:00 +00002237/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00002238int select ( int n,
2239 fd_set *rfds,
2240 fd_set *wfds,
2241 fd_set *xfds,
2242 struct timeval *timeout )
2243{
sewardj5f07b662002-04-23 16:52:51 +00002244 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00002245 int res;
2246 fd_set rfds_copy;
2247 fd_set wfds_copy;
2248 fd_set xfds_copy;
2249 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00002250 struct vki_timeval zero_timeout;
2251 struct vki_timespec nanosleep_interval;
2252
sewardjd140e442002-05-29 01:21:19 +00002253 __my_pthread_testcancel();
2254
sewardj5f07b662002-04-23 16:52:51 +00002255 /* gcc's complains about ms_end being used uninitialised -- classic
2256 case it can't understand, where ms_end is both defined and used
2257 only if timeout != NULL. Hence ... */
2258 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00002259
2260 /* We assume that the kernel and libc data layouts are identical
2261 for the following types. These asserts provide a crude
2262 check. */
2263 if (sizeof(fd_set) != sizeof(vki_fd_set)
2264 || sizeof(struct timeval) != sizeof(struct vki_timeval))
2265 barf("valgrind's hacky non-blocking select(): data sizes error");
2266
sewardj5f07b662002-04-23 16:52:51 +00002267 /* Detect the current time and simultaneously find out if we are
2268 running on Valgrind. */
2269 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2270 VG_USERREQ__READ_MILLISECOND_TIMER,
2271 0, 0, 0, 0);
2272
2273 /* If a zero timeout specified, this call is harmless. Also go
2274 this route if we're not running on Valgrind, for whatever
2275 reason. */
2276 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
2277 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00002278 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00002279 (vki_fd_set*)wfds,
2280 (vki_fd_set*)xfds,
2281 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00002282 if (is_kerror(res)) {
2283 * (__errno_location()) = -res;
2284 return -1;
2285 } else {
2286 return res;
2287 }
2288 }
sewardj08a4c3f2002-04-13 03:45:44 +00002289
sewardj5f07b662002-04-23 16:52:51 +00002290 /* If a timeout was specified, set ms_end to be the end millisecond
2291 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00002292 if (timeout) {
2293 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00002294 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00002295 ms_end = ms_now;
2296 ms_end += (timeout->tv_usec / 1000);
2297 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00002298 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00002299 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00002300 }
2301
2302 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
2303
2304 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00002305 NULL, in which case ms_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002306
sewardj08a4c3f2002-04-13 03:45:44 +00002307 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002308
2309 /* First, do a return-immediately select(). */
sewardj08a4c3f2002-04-13 03:45:44 +00002310
2311 /* These could be trashed each time round the loop, so restore
2312 them each time. */
2313 if (rfds) rfds_copy = *rfds;
2314 if (wfds) wfds_copy = *wfds;
2315 if (xfds) xfds_copy = *xfds;
2316
2317 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
2318
2319 res = do_syscall_select( n,
2320 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
2321 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
2322 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
2323 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00002324 if (is_kerror(res)) {
2325 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00002326 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00002327 * (__errno_location()) = -res;
2328 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00002329 }
2330 if (res > 0) {
2331 /* one or more fds is ready. Copy out resulting sets and
2332 return. */
2333 if (rfds) *rfds = rfds_copy;
2334 if (wfds) *wfds = wfds_copy;
2335 if (xfds) *xfds = xfds_copy;
2336 return res;
2337 }
sewardj05bb2c92002-06-26 00:47:17 +00002338
2339 /* Nothing interesting happened, so we go to sleep for a
2340 while. */
2341
sewardj08a4c3f2002-04-13 03:45:44 +00002342 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
2343 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00002344 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002345 nanosleep_interval.tv_nsec = 11 * 1000 * 1000; /* 11 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00002346 /* It's critical here that valgrind's nanosleep implementation
2347 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00002348 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00002349 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00002350 if (res == -VKI_EINTR) {
2351 /* The nanosleep was interrupted by a signal. So we do the
2352 same. */
2353 * (__errno_location()) = EINTR;
2354 return -1;
2355 }
sewardj05bb2c92002-06-26 00:47:17 +00002356
2357 /* Sleeping finished. If a finite timeout, check to see if it
2358 has expired yet. */
2359 if (timeout) {
2360 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2361 VG_USERREQ__READ_MILLISECOND_TIMER,
2362 0, 0, 0, 0);
2363 my_assert(ms_now != 0xFFFFFFFF);
2364 if (ms_now >= ms_end) {
2365 /* timeout; nothing interesting happened. */
2366 if (rfds) FD_ZERO(rfds);
2367 if (wfds) FD_ZERO(wfds);
2368 if (xfds) FD_ZERO(xfds);
2369 return 0;
2370 }
2371 }
2372
sewardjf854f472002-04-21 12:19:41 +00002373 }
2374}
2375
2376
2377
2378
2379#include <sys/poll.h>
2380
sewardj3e909ce2002-06-03 13:27:15 +00002381#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00002382typedef unsigned long int nfds_t;
2383#endif
2384
sewardj705d3cb2002-05-23 13:13:12 +00002385
sewardj5905fae2002-04-26 13:25:00 +00002386/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00002387int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2388{
sewardj5f07b662002-04-23 16:52:51 +00002389 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00002390 int res, i;
sewardjf854f472002-04-21 12:19:41 +00002391 struct vki_timespec nanosleep_interval;
2392
sewardjd140e442002-05-29 01:21:19 +00002393 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00002394 ensure_valgrind("poll");
2395
sewardj5f07b662002-04-23 16:52:51 +00002396 /* Detect the current time and simultaneously find out if we are
2397 running on Valgrind. */
2398 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2399 VG_USERREQ__READ_MILLISECOND_TIMER,
2400 0, 0, 0, 0);
2401
sewardjf854f472002-04-21 12:19:41 +00002402 if (/* CHECK SIZES FOR struct pollfd */
2403 sizeof(struct timeval) != sizeof(struct vki_timeval))
2404 barf("valgrind's hacky non-blocking poll(): data sizes error");
2405
sewardj5f07b662002-04-23 16:52:51 +00002406 /* dummy initialisation to keep gcc -Wall happy */
2407 ms_end = 0;
2408
2409 /* If a zero timeout specified, this call is harmless. Also do
2410 this if not running on Valgrind. */
2411 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00002412 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
2413 if (is_kerror(res)) {
2414 * (__errno_location()) = -res;
2415 return -1;
2416 } else {
2417 return res;
2418 }
2419 }
2420
sewardj5f07b662002-04-23 16:52:51 +00002421 /* If a timeout was specified, set ms_end to be the end wallclock
2422 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002423 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002424 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002425 }
2426
2427 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2428
2429 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2430 in which case t_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002431
sewardj2d94c112002-06-03 01:25:54 +00002432 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002433
sewardjf854f472002-04-21 12:19:41 +00002434 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002435
2436 /* Do a return-immediately poll. */
2437
2438 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2439 if (is_kerror(res)) {
2440 /* Some kind of error. Set errno and return. */
2441 * (__errno_location()) = -res;
2442 return -1;
2443 }
2444 if (res > 0) {
2445 /* One or more fds is ready. Return now. */
2446 return res;
2447 }
2448
2449 /* Nothing interesting happened, so we go to sleep for a
2450 while. */
2451
2452 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2453 /* nanosleep and go round again */
2454 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002455 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
sewardj05bb2c92002-06-26 00:47:17 +00002456 /* It's critical here that valgrind's nanosleep implementation
2457 is nonblocking. */
2458 (void)my_do_syscall2(__NR_nanosleep,
2459 (int)(&nanosleep_interval), (int)NULL);
2460
2461 /* Sleeping finished. If a finite timeout, check to see if it
2462 has expired yet. */
sewardjf854f472002-04-21 12:19:41 +00002463 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002464 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2465 VG_USERREQ__READ_MILLISECOND_TIMER,
2466 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002467 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002468 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002469 /* timeout; nothing interesting happened. */
2470 for (i = 0; i < __nfds; i++)
2471 __fds[i].revents = 0;
2472 return 0;
2473 }
2474 }
2475
sewardj08a4c3f2002-04-13 03:45:44 +00002476 }
2477}
sewardj3b13f0e2002-04-25 20:17:29 +00002478
2479
sewardj705d3cb2002-05-23 13:13:12 +00002480/* Helper function used to make accept() non-blocking. Idea is to use
2481 the above nonblocking poll() to make this thread ONLY wait for the
2482 specified fd to become ready, and then return. */
sewardjd1c1cf22002-06-26 00:13:36 +00002483
2484/* Sigh -- a hack. We're not supposed to include this file directly;
2485 should do it via /usr/include/fcntl.h, but that introduces a
2486 varargs prototype for fcntl itself, which we can't mimic. */
2487#define _FCNTL_H
2488#include <bits/fcntl.h>
2489
sewardj705d3cb2002-05-23 13:13:12 +00002490static void wait_for_fd_to_be_readable_or_erring ( int fd )
2491{
2492 struct pollfd pfd;
sewardjd1c1cf22002-06-26 00:13:36 +00002493 int res;
2494
sewardj6e6cbaa2002-05-24 02:12:52 +00002495 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardjd1c1cf22002-06-26 00:13:36 +00002496
2497 /* First check to see if the fd is nonblocking, and/or invalid. In
2498 either case return immediately. */
2499 res = __libc_fcntl(fd, F_GETFL, 0);
2500 if (res == -1) return; /* fd is invalid somehow */
2501 if (res & O_NONBLOCK) return; /* fd is nonblocking */
2502
2503 /* Ok, we'd better wait with poll. */
sewardj705d3cb2002-05-23 13:13:12 +00002504 pfd.fd = fd;
2505 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2506 /* ... but not POLLOUT, you may notice. */
2507 pfd.revents = 0;
2508 (void)poll(&pfd, 1, -1 /* forever */);
2509}
2510
2511
sewardj3b13f0e2002-04-25 20:17:29 +00002512/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002513 Hacky implementation of semaphores.
2514 ------------------------------------------------------------------ */
2515
2516#include <semaphore.h>
2517
2518/* This is a terrible way to do the remapping. Plan is to import an
2519 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002520
2521typedef
2522 struct {
2523 pthread_mutex_t se_mx;
2524 pthread_cond_t se_cv;
2525 int count;
2526 }
2527 vg_sem_t;
2528
2529static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2530
2531static int se_remap_used = 0;
2532static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2533static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2534
2535static vg_sem_t* se_remap ( sem_t* orig )
2536{
2537 int res, i;
2538 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002539 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002540
2541 for (i = 0; i < se_remap_used; i++) {
2542 if (se_remap_orig[i] == orig)
2543 break;
2544 }
2545 if (i == se_remap_used) {
2546 if (se_remap_used == VG_N_SEMAPHORES) {
2547 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002548 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002549 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002550 }
2551 se_remap_used++;
2552 se_remap_orig[i] = orig;
2553 /* printf("allocated semaphore %d\n", i); */
2554 }
2555 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002556 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002557 return &se_remap_new[i];
2558}
2559
2560
2561int sem_init(sem_t *sem, int pshared, unsigned int value)
2562{
2563 int res;
2564 vg_sem_t* vg_sem;
2565 ensure_valgrind("sem_init");
2566 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002567 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002568 errno = ENOSYS;
2569 return -1;
2570 }
2571 vg_sem = se_remap(sem);
2572 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002573 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002574 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002575 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002576 vg_sem->count = value;
2577 return 0;
2578}
2579
2580
2581int sem_wait ( sem_t* sem )
2582{
2583 int res;
2584 vg_sem_t* vg_sem;
2585 ensure_valgrind("sem_wait");
2586 vg_sem = se_remap(sem);
2587 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002588 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002589 while (vg_sem->count == 0) {
2590 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002591 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002592 }
2593 vg_sem->count--;
2594 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002595 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002596 return 0;
2597}
2598
2599int sem_post ( sem_t* sem )
2600{
2601 int res;
2602 vg_sem_t* vg_sem;
2603 ensure_valgrind("sem_post");
2604 vg_sem = se_remap(sem);
2605 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002606 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002607 if (vg_sem->count == 0) {
2608 vg_sem->count++;
2609 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002610 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002611 } else {
2612 vg_sem->count++;
2613 }
2614 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002615 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002616 return 0;
2617}
2618
2619
2620int sem_trywait ( sem_t* sem )
2621{
2622 int ret, res;
2623 vg_sem_t* vg_sem;
2624 ensure_valgrind("sem_trywait");
2625 vg_sem = se_remap(sem);
2626 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002627 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002628 if (vg_sem->count > 0) {
2629 vg_sem->count--;
2630 ret = 0;
2631 } else {
2632 ret = -1;
2633 errno = EAGAIN;
2634 }
2635 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002636 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002637 return ret;
2638}
2639
2640
2641int sem_getvalue(sem_t* sem, int * sval)
2642{
2643 vg_sem_t* vg_sem;
2644 ensure_valgrind("sem_trywait");
2645 vg_sem = se_remap(sem);
2646 *sval = vg_sem->count;
2647 return 0;
2648}
2649
2650
2651int sem_destroy(sem_t * sem)
2652{
2653 kludged("sem_destroy");
2654 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2655 return 0;
2656}
2657
sewardj9ad92d92002-10-16 19:45:06 +00002658
2659int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2660{
2661 int res;
2662 vg_sem_t* vg_sem;
2663 ensure_valgrind("sem_timedwait");
2664 vg_sem = se_remap(sem);
2665 res = __pthread_mutex_lock(&vg_sem->se_mx);
2666 my_assert(res == 0);
2667 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
2668 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
2669 }
2670 if ( vg_sem->count > 0 ) {
2671 vg_sem->count--;
2672 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2673 my_assert(res == 0 );
2674 return 0;
2675 } else {
2676 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2677 my_assert(res == 0 );
2678 *(__errno_location()) = ETIMEDOUT;
2679 return -1;
2680 }
2681}
2682
sewardj8f253ff2002-05-19 00:13:34 +00002683
2684/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002685 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002686 ------------------------------------------------------------------ */
2687
sewardj2d8b3f02002-06-01 14:14:19 +00002688typedef
2689 struct {
2690 int initted; /* != 0 --> in use; sanity check only */
2691 int prefer_w; /* != 0 --> prefer writer */
2692 int nwait_r; /* # of waiting readers */
2693 int nwait_w; /* # of waiting writers */
2694 pthread_cond_t cv_r; /* for signalling readers */
2695 pthread_cond_t cv_w; /* for signalling writers */
2696 pthread_mutex_t mx;
2697 int status;
2698 /* allowed range for status: >= -1. -1 means 1 writer currently
2699 active, >= 0 means N readers currently active. */
2700 }
2701 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002702
2703
2704static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2705
2706static int rw_remap_used = 0;
2707static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2708static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2709
sewardj2d8b3f02002-06-01 14:14:19 +00002710
2711static
2712void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2713{
2714 int res = 0;
2715 vg_rwl->initted = 1;
2716 vg_rwl->prefer_w = 1;
2717 vg_rwl->nwait_r = 0;
2718 vg_rwl->nwait_w = 0;
2719 vg_rwl->status = 0;
2720 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2721 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2722 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002723 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002724}
2725
2726
sewardja1ac5cb2002-05-27 13:00:05 +00002727/* Take the address of a LinuxThreads rwlock_t and return the shadow
2728 address of our version. Further, if the LinuxThreads version
2729 appears to have been statically initialised, do the same to the one
2730 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2731 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2732 uninitialised and non-zero meaning initialised.
2733*/
2734static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2735{
2736 int res, i;
2737 vg_rwlock_t* vg_rwl;
2738 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002739 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002740
2741 for (i = 0; i < rw_remap_used; i++) {
2742 if (rw_remap_orig[i] == orig)
2743 break;
2744 }
2745 if (i == rw_remap_used) {
2746 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002747 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002748 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002749 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2750 }
2751 rw_remap_used++;
2752 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002753 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002754 if (0) printf("allocated rwlock %d\n", i);
2755 }
2756 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002757 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002758 vg_rwl = &rw_remap_new[i];
2759
sewardj2d8b3f02002-06-01 14:14:19 +00002760 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002761 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002762 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002763 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002764 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002765 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002766 }
2767
2768 return vg_rwl;
2769}
2770
2771
sewardja1ac5cb2002-05-27 13:00:05 +00002772int pthread_rwlock_init ( pthread_rwlock_t* orig,
2773 const pthread_rwlockattr_t* attr )
2774{
sewardja1ac5cb2002-05-27 13:00:05 +00002775 vg_rwlock_t* rwl;
2776 if (0) printf ("pthread_rwlock_init\n");
2777 /* Force the remapper to initialise the shadow. */
2778 orig->__rw_readers = 0;
2779 /* Install the lock preference; the remapper needs to know it. */
2780 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2781 if (attr)
2782 orig->__rw_kind = attr->__lockkind;
2783 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002784 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002785}
2786
sewardj2d8b3f02002-06-01 14:14:19 +00002787
2788static
2789void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002790{
sewardj2d8b3f02002-06-01 14:14:19 +00002791 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2792 rwl->nwait_r--;
2793 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002794}
2795
sewardj2d8b3f02002-06-01 14:14:19 +00002796
sewardja1ac5cb2002-05-27 13:00:05 +00002797int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2798{
2799 int res;
2800 vg_rwlock_t* rwl;
2801 if (0) printf ("pthread_rwlock_rdlock\n");
2802 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002803 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002804 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002805 if (!rwl->initted) {
2806 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002807 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002808 return EINVAL;
2809 }
2810 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002811 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002812 rwl->nwait_r++;
2813 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2814 while (1) {
2815 if (rwl->status == 0) break;
2816 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002817 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002818 }
2819 pthread_cleanup_pop(0);
2820 rwl->nwait_r--;
2821 }
sewardj2d94c112002-06-03 01:25:54 +00002822 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002823 rwl->status++;
2824 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002825 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002826 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002827}
2828
sewardj2d8b3f02002-06-01 14:14:19 +00002829
sewardja1ac5cb2002-05-27 13:00:05 +00002830int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2831{
2832 int res;
2833 vg_rwlock_t* rwl;
2834 if (0) printf ("pthread_rwlock_tryrdlock\n");
2835 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002836 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002837 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002838 if (!rwl->initted) {
2839 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002840 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002841 return EINVAL;
2842 }
2843 if (rwl->status == -1) {
2844 /* Writer active; we have to give up. */
2845 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002846 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002847 return EBUSY;
2848 }
2849 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002850 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002851 rwl->status++;
2852 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002853 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002854 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002855}
2856
sewardj2d8b3f02002-06-01 14:14:19 +00002857
2858static
2859void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2860{
2861 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2862 rwl->nwait_w--;
2863 pthread_mutex_unlock (&rwl->mx);
2864}
2865
2866
sewardja1ac5cb2002-05-27 13:00:05 +00002867int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2868{
2869 int res;
2870 vg_rwlock_t* rwl;
2871 if (0) printf ("pthread_rwlock_wrlock\n");
2872 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002873 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002874 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002875 if (!rwl->initted) {
2876 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002877 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002878 return EINVAL;
2879 }
2880 if (rwl->status != 0) {
2881 rwl->nwait_w++;
2882 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2883 while (1) {
2884 if (rwl->status == 0) break;
2885 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002886 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002887 }
2888 pthread_cleanup_pop(0);
2889 rwl->nwait_w--;
2890 }
sewardj2d94c112002-06-03 01:25:54 +00002891 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002892 rwl->status = -1;
2893 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002894 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002895 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002896}
2897
sewardj2d8b3f02002-06-01 14:14:19 +00002898
sewardja1ac5cb2002-05-27 13:00:05 +00002899int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2900{
2901 int res;
2902 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002903 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002904 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002905 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002906 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002907 if (!rwl->initted) {
2908 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002909 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002910 return EINVAL;
2911 }
2912 if (rwl->status != 0) {
2913 /* Reader(s) or a writer active; we have to give up. */
2914 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002915 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002916 return EBUSY;
2917 }
2918 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002919 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002920 rwl->status = -1;
2921 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002922 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002923 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002924}
2925
sewardj2d8b3f02002-06-01 14:14:19 +00002926
sewardja1ac5cb2002-05-27 13:00:05 +00002927int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2928{
2929 int res;
2930 vg_rwlock_t* rwl;
2931 if (0) printf ("pthread_rwlock_unlock\n");
2932 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002933 rwl = rw_remap ( orig );
2934 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002935 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002936 if (!rwl->initted) {
2937 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002938 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002939 return EINVAL;
2940 }
2941 if (rwl->status == 0) {
2942 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002943 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002944 return EPERM;
2945 }
sewardj2d94c112002-06-03 01:25:54 +00002946 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002947 if (rwl->status == -1) {
2948 rwl->status = 0;
2949 } else {
sewardj2d94c112002-06-03 01:25:54 +00002950 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002951 rwl->status--;
2952 }
2953
sewardj2d94c112002-06-03 01:25:54 +00002954 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002955
2956 if (rwl->prefer_w) {
2957
2958 /* Favour waiting writers, if any. */
2959 if (rwl->nwait_w > 0) {
2960 /* Writer(s) are waiting. */
2961 if (rwl->status == 0) {
2962 /* We can let a writer in. */
2963 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002964 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002965 } else {
2966 /* There are still readers active. Do nothing; eventually
2967 they will disappear, at which point a writer will be
2968 admitted. */
2969 }
2970 }
2971 else
2972 /* No waiting writers. */
2973 if (rwl->nwait_r > 0) {
2974 /* Let in a waiting reader. */
2975 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002976 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002977 }
2978
2979 } else {
2980
2981 /* Favour waiting readers, if any. */
2982 if (rwl->nwait_r > 0) {
2983 /* Reader(s) are waiting; let one in. */
2984 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002985 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002986 }
2987 else
2988 /* No waiting readers. */
2989 if (rwl->nwait_w > 0 && rwl->status == 0) {
2990 /* We have waiting writers and no active readers; let a
2991 writer in. */
2992 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002993 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002994 }
2995 }
2996
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 0;
3000}
3001
3002
3003int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
3004{
3005 int res;
3006 vg_rwlock_t* rwl;
3007 if (0) printf ("pthread_rwlock_destroy\n");
3008 rwl = rw_remap ( orig );
3009 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003010 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003011 if (!rwl->initted) {
3012 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003013 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003014 return EINVAL;
3015 }
3016 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
3017 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003018 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003019 return EBUSY;
3020 }
3021 rwl->initted = 0;
3022 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003023 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003024 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003025}
3026
3027
sewardj47e4e312002-06-18 09:24:34 +00003028/* Copied directly from LinuxThreads. */
3029int
3030pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
3031{
3032 attr->__lockkind = 0;
3033 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
3034
3035 return 0;
3036}
3037
sewardjfe18eb82002-07-13 12:58:44 +00003038/* Copied directly from LinuxThreads. */
3039int
3040pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
3041{
3042 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
3043 return EINVAL;
3044
3045 /* For now it is not possible to shared a conditional variable. */
3046 if (pshared != PTHREAD_PROCESS_PRIVATE)
3047 return ENOSYS;
3048
3049 attr->__pshared = pshared;
3050
3051 return 0;
3052}
3053
sewardj47e4e312002-06-18 09:24:34 +00003054
sewardja1ac5cb2002-05-27 13:00:05 +00003055/* ---------------------------------------------------------------------
sewardjd5bef572002-10-23 21:49:33 +00003056 Make SYSV IPC not block everything
3057 ------------------------------------------------------------------ */
3058
3059#include <sys/ipc.h>
3060#include <sys/msg.h>
3061#include <asm/ipc.h> /* for ipc_kludge */
3062
3063static inline int sys_ipc(unsigned call, int first, int second, int third, void *ptr)
3064{
3065 return my_do_syscall5(__NR_ipc, call, first, second, third, (int)ptr);
3066}
3067
3068/* Turn a blocking msgsnd() into a polling non-blocking one, so that
3069 other threads make progress */
3070int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
3071{
3072 struct vki_timespec nanosleep_interval;
3073 int err;
3074
3075 ensure_valgrind("msgsnd");
3076
3077 nanosleep_interval.tv_sec = 0;
3078 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
3079
3080 if (msgflg & IPC_NOWAIT) {
3081 /* If we aren't blocking anyway, just do it */
3082 err = sys_ipc(11, msgid, msgsz, msgflg, (void *)msgp);
3083 } else {
3084 /* Otherwise poll on the queue to let other things run */
3085 for(;;) {
3086 err = sys_ipc(11, msgid, msgsz, msgflg | IPC_NOWAIT, (void *)msgp);
3087
3088 if (err != -EAGAIN)
3089 break;
3090
3091 (void)my_do_syscall2(__NR_nanosleep,
3092 (int)(&nanosleep_interval), (int)NULL);
3093 }
3094 }
3095
3096 if (is_kerror(err)) {
3097 *(__errno_location()) = -err;
3098 return -1;
3099 }
3100 return 0;
3101}
3102
3103/* Turn a blocking msgrcv() into a polling non-blocking one, so that
3104 other threads make progress */
3105int msgrcv( int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg )
3106{
3107 struct vki_timespec nanosleep_interval;
3108 int err;
3109 struct ipc_kludge tmp;
3110
3111 ensure_valgrind("msgrcv");
3112
3113 nanosleep_interval.tv_sec = 0;
3114 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
3115
3116 tmp.msgp = msgp;
3117 tmp.msgtyp = msgtyp;
3118
3119 if (msgflg & IPC_NOWAIT) {
3120 /* If we aren't blocking anyway, just do it */
3121 err = sys_ipc(12, msqid, msgsz, msgflg, &tmp );
3122 } else {
3123 /* Otherwise poll on the queue to let other things run */
3124 for(;;) {
3125 err = sys_ipc(12, msqid, msgsz, msgflg | IPC_NOWAIT, &tmp );
3126
3127 if (err != -ENOMSG)
3128 break;
3129
3130 (void)my_do_syscall2(__NR_nanosleep,
3131 (int)(&nanosleep_interval), (int)NULL);
3132 }
3133 }
3134
3135 if (is_kerror(err)) {
3136 *(__errno_location()) = -err;
3137 return -1;
3138 }
3139
3140 return 0;
3141}
3142
3143
3144
3145/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00003146 B'stard.
3147 ------------------------------------------------------------------ */
3148
3149# define strong_alias(name, aliasname) \
3150 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
3151
sewardj5905fae2002-04-26 13:25:00 +00003152# define weak_alias(name, aliasname) \
3153 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00003154
sewardj5905fae2002-04-26 13:25:00 +00003155strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
3156strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
3157strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
3158strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
3159 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
3160strong_alias(__pthread_mutex_init, pthread_mutex_init)
3161strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
3162strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
3163strong_alias(__pthread_once, pthread_once)
3164strong_alias(__pthread_atfork, pthread_atfork)
3165strong_alias(__pthread_key_create, pthread_key_create)
3166strong_alias(__pthread_getspecific, pthread_getspecific)
3167strong_alias(__pthread_setspecific, pthread_setspecific)
3168
sewardjd529a442002-05-04 19:49:21 +00003169#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00003170strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00003171#endif
3172
sewardj5905fae2002-04-26 13:25:00 +00003173strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00003174strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00003175strong_alias(lseek, __lseek)
3176strong_alias(open, __open)
3177strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00003178strong_alias(read, __read)
3179strong_alias(wait, __wait)
3180strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00003181strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00003182strong_alias(send, __send)
sewardj3fd559e2002-10-20 16:24:04 +00003183strong_alias(poll, __poll)
3184strong_alias(select, __select)
sewardj5905fae2002-04-26 13:25:00 +00003185
sewardj726c4122002-05-16 23:39:10 +00003186weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00003187weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00003188weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00003189weak_alias(__vfork, vfork)
sewardj7f6456d2002-05-21 00:51:21 +00003190
sewardjf0b06452002-06-04 08:38:04 +00003191weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00003192
3193/*--------------------------------------------------*/
3194
sewardj5905fae2002-04-26 13:25:00 +00003195weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00003196weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00003197weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00003198
sewardja1ac5cb2002-05-27 13:00:05 +00003199weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
3200weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
3201weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
3202weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
3203
sewardj060b04f2002-04-26 21:01:13 +00003204
sewardj3b13f0e2002-04-25 20:17:29 +00003205/* I've no idea what these are, but they get called quite a lot.
3206 Anybody know? */
3207
3208#undef _IO_flockfile
3209void _IO_flockfile ( _IO_FILE * file )
3210{
sewardj853f55d2002-04-26 00:27:53 +00003211 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003212}
sewardj5905fae2002-04-26 13:25:00 +00003213weak_alias(_IO_flockfile, flockfile);
3214
sewardj3b13f0e2002-04-25 20:17:29 +00003215
3216#undef _IO_funlockfile
3217void _IO_funlockfile ( _IO_FILE * file )
3218{
sewardj853f55d2002-04-26 00:27:53 +00003219 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003220}
sewardj5905fae2002-04-26 13:25:00 +00003221weak_alias(_IO_funlockfile, funlockfile);
3222
sewardj3b13f0e2002-04-25 20:17:29 +00003223
sewardjd4f2c712002-04-30 10:20:10 +00003224/* This doesn't seem to be needed to simulate libpthread.so's external
3225 interface, but many people complain about its absence. */
3226
3227strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
3228weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00003229
3230
3231/*--------------------------------------------------------------------*/
3232/*--- end vg_libpthread.c ---*/
3233/*--------------------------------------------------------------------*/