blob: aa5104c9206d4d78b2f7d49e8517d1463a167701 [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);
sewardjf220ccc2002-10-23 21:53:49 +00001829
1830int VGL_(accept)(int s, struct sockaddr *addr, socklen_t *addrlen)
sewardje663cb92002-04-12 10:26:32 +00001831{
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
sewardj0c573af92002-10-23 21:55:01 +00001838extern
1839int __libc_recv(int s, void *buf, size_t len, int flags);
1840
1841int VGL_(recv)(int s, void *buf, size_t len, int flags)
1842{
1843 __my_pthread_testcancel();
1844 wait_for_fd_to_be_readable_or_erring(s);
1845 __my_pthread_testcancel();
1846 return __libc_recv(s, buf, len, flags);
1847}
1848
sewardje663cb92002-04-12 10:26:32 +00001849
1850extern
sewardje663cb92002-04-12 10:26:32 +00001851pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001852__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001853pid_t waitpid(pid_t pid, int *status, int options)
1854{
sewardjd140e442002-05-29 01:21:19 +00001855 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001856 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001857}
1858
1859
1860extern
1861int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001862__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001863int nanosleep(const struct timespec *req, struct timespec *rem)
1864{
sewardjd140e442002-05-29 01:21:19 +00001865 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001866 return __libc_nanosleep(req, rem);
1867}
1868
sewardjbe32e452002-04-24 20:29:58 +00001869
sewardje663cb92002-04-12 10:26:32 +00001870extern
1871int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001872__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001873int fsync(int fd)
1874{
sewardjd140e442002-05-29 01:21:19 +00001875 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001876 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001877}
1878
sewardjbe32e452002-04-24 20:29:58 +00001879
sewardj70c75362002-04-13 04:18:32 +00001880extern
1881off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001882__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001883off_t lseek(int fildes, off_t offset, int whence)
1884{
sewardjd140e442002-05-29 01:21:19 +00001885 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001886 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001887}
1888
sewardjbe32e452002-04-24 20:29:58 +00001889
1890extern
1891__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001892__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001893__off64_t lseek64(int fildes, __off64_t offset, int whence)
1894{
sewardjd140e442002-05-29 01:21:19 +00001895 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001896 return __libc_lseek64(fildes, offset, whence);
1897}
1898
1899
sewardj726c4122002-05-16 23:39:10 +00001900extern
1901ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1902 __off64_t __offset);
1903ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1904 __off64_t __offset)
1905{
sewardjd140e442002-05-29 01:21:19 +00001906 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001907 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1908}
1909
1910
sewardja18e2102002-05-18 10:43:22 +00001911extern
1912ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1913 __off64_t __offset);
1914ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1915 __off64_t __offset)
1916{
sewardjd140e442002-05-29 01:21:19 +00001917 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001918 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1919}
1920
sewardj726c4122002-05-16 23:39:10 +00001921
sewardj39b93b12002-05-18 10:56:27 +00001922extern
1923ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1924__attribute__((weak))
1925ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1926{
sewardjd140e442002-05-29 01:21:19 +00001927 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001928 return __libc_pwrite(fd, buf, count, offset);
1929}
1930
1931
1932extern
1933ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1934__attribute__((weak))
1935ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1936{
sewardjd140e442002-05-29 01:21:19 +00001937 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001938 return __libc_pread(fd, buf, count, offset);
1939}
1940
1941
sewardj6af4b5d2002-04-16 04:40:49 +00001942extern
1943void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001944/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001945void longjmp(jmp_buf env, int val)
1946{
1947 __libc_longjmp(env, val);
1948}
1949
sewardjbe32e452002-04-24 20:29:58 +00001950
sewardj436c2db2002-06-18 09:07:54 +00001951extern void __libc_siglongjmp (sigjmp_buf env, int val)
1952 __attribute__ ((noreturn));
1953void siglongjmp(sigjmp_buf env, int val)
1954{
1955 kludged("siglongjmp (cleanup handlers are ignored)");
1956 __libc_siglongjmp(env, val);
1957}
1958
1959
sewardj6af4b5d2002-04-16 04:40:49 +00001960extern
1961int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001962__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001963int send(int s, const void *msg, size_t len, int flags)
1964{
sewardjd140e442002-05-29 01:21:19 +00001965 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001966 return __libc_send(s, msg, len, flags);
1967}
1968
sewardjbe32e452002-04-24 20:29:58 +00001969
sewardj1e8cdc92002-04-18 11:37:52 +00001970extern
1971int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001972__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001973int recv(int s, void *buf, size_t len, int flags)
1974{
sewardjd140e442002-05-29 01:21:19 +00001975 __my_pthread_testcancel();
sewardj1d6b3a22002-06-20 07:58:33 +00001976 wait_for_fd_to_be_readable_or_erring(s);
1977 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001978 return __libc_recv(s, buf, len, flags);
1979}
1980
sewardjbe32e452002-04-24 20:29:58 +00001981
sewardj3665ded2002-05-16 16:57:25 +00001982extern
1983int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1984__attribute__((weak))
1985int sendmsg(int s, const struct msghdr *msg, int flags)
1986{
sewardjd140e442002-05-29 01:21:19 +00001987 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001988 return __libc_sendmsg(s, msg, flags);
1989}
1990
1991
sewardj796d6a22002-04-24 02:28:34 +00001992extern
sewardj59da27a2002-06-06 08:33:54 +00001993int __libc_recvmsg(int s, struct msghdr *msg, int flags);
1994__attribute__((weak))
1995int recvmsg(int s, struct msghdr *msg, int flags)
1996{
1997 __my_pthread_testcancel();
1998 return __libc_recvmsg(s, msg, flags);
1999}
2000
2001
2002extern
sewardj436e0582002-04-26 14:31:40 +00002003int __libc_recvfrom(int s, void *buf, size_t len, int flags,
2004 struct sockaddr *from, socklen_t *fromlen);
2005__attribute__((weak))
2006int recvfrom(int s, void *buf, size_t len, int flags,
2007 struct sockaddr *from, socklen_t *fromlen)
2008{
sewardjd140e442002-05-29 01:21:19 +00002009 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00002010 wait_for_fd_to_be_readable_or_erring(s);
2011 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00002012 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
2013}
2014
2015
2016extern
sewardj796d6a22002-04-24 02:28:34 +00002017int __libc_sendto(int s, const void *msg, size_t len, int flags,
2018 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00002019__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00002020int sendto(int s, const void *msg, size_t len, int flags,
2021 const struct sockaddr *to, socklen_t tolen)
2022{
sewardjd140e442002-05-29 01:21:19 +00002023 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00002024 return __libc_sendto(s, msg, len, flags, to, tolen);
2025}
2026
sewardjbe32e452002-04-24 20:29:58 +00002027
sewardj369b1702002-04-24 13:28:15 +00002028extern
2029int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00002030__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00002031int system(const char* str)
2032{
sewardjd140e442002-05-29 01:21:19 +00002033 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00002034 return __libc_system(str);
2035}
2036
sewardjbe32e452002-04-24 20:29:58 +00002037
sewardjab0b1c32002-04-24 19:26:47 +00002038extern
2039pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00002040__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00002041pid_t wait(int *status)
2042{
sewardjd140e442002-05-29 01:21:19 +00002043 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00002044 return __libc_wait(status);
2045}
2046
sewardj45b4b372002-04-16 22:50:32 +00002047
sewardj67f1d582002-05-24 02:11:32 +00002048extern
2049int __libc_msync(const void *start, size_t length, int flags);
2050__attribute__((weak))
2051int msync(const void *start, size_t length, int flags)
2052{
sewardjd140e442002-05-29 01:21:19 +00002053 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00002054 return __libc_msync(start, length, flags);
2055}
2056
sewardj5905fae2002-04-26 13:25:00 +00002057
sewardj2cb00342002-06-28 01:46:26 +00002058/*--- fork and its helper ---*/
2059
2060static
2061void run_fork_handlers ( int what )
2062{
2063 ForkHandlerEntry entry;
2064 int n_h, n_handlers, i, res;
2065
2066 my_assert(what == 0 || what == 1 || what == 2);
2067
2068 /* Fetch old counter */
2069 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2070 VG_USERREQ__GET_FHSTACK_USED,
2071 0, 0, 0, 0);
2072 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2073
2074 /* Prepare handlers (what == 0) are called in opposite order of
2075 calls to pthread_atfork. Parent and child handlers are called
2076 in the same order as calls to pthread_atfork. */
2077 if (what == 0)
2078 n_h = n_handlers - 1;
2079 else
2080 n_h = 0;
2081
2082 for (i = 0; i < n_handlers; i++) {
2083 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2084 VG_USERREQ__GET_FHSTACK_ENTRY,
2085 n_h, &entry, 0, 0);
2086 my_assert(res == 0);
2087 switch (what) {
2088 case 0: if (entry.prepare) entry.prepare();
2089 n_h--; break;
2090 case 1: if (entry.parent) entry.parent();
2091 n_h++; break;
2092 case 2: if (entry.child) entry.child();
2093 n_h++; break;
2094 default: barf("run_fork_handlers: invalid what");
2095 }
2096 }
2097
2098 if (what != 0 /* prepare */) {
2099 /* Empty out the stack. */
2100 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2101 VG_USERREQ__SET_FHSTACK_USED,
2102 0, 0, 0, 0);
2103 my_assert(res == 0);
2104 }
2105}
2106
2107extern
2108pid_t __libc_fork(void);
2109pid_t __fork(void)
2110{
2111 pid_t pid;
2112 __my_pthread_testcancel();
2113 __pthread_mutex_lock(&pthread_atfork_lock);
2114
2115 run_fork_handlers(0 /* prepare */);
2116 pid = __libc_fork();
2117 if (pid == 0) {
2118 /* I am the child */
2119 run_fork_handlers(2 /* child */);
2120 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2121 } else {
2122 /* I am the parent */
2123 run_fork_handlers(1 /* parent */);
2124 __pthread_mutex_unlock(&pthread_atfork_lock);
2125 }
2126 return pid;
2127}
2128
2129
njn25e49d8e72002-09-23 09:36:25 +00002130pid_t __vfork(void)
2131{
2132 return __fork();
2133}
sewardj2cb00342002-06-28 01:46:26 +00002134
2135
sewardj3b13f0e2002-04-25 20:17:29 +00002136/* ---------------------------------------------------------------------
2137 Nonblocking implementations of select() and poll(). This stuff will
2138 surely rot your mind.
2139 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00002140
sewardj08a4c3f2002-04-13 03:45:44 +00002141/*--------------------------------------------------*/
2142
2143#include "vg_kerneliface.h"
2144
2145static
2146__inline__
2147int is_kerror ( int res )
2148{
2149 if (res >= -4095 && res <= -1)
2150 return 1;
2151 else
2152 return 0;
2153}
2154
2155
2156static
2157int my_do_syscall1 ( int syscallno, int arg1 )
2158{
2159 int __res;
2160 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2161 : "=a" (__res)
2162 : "0" (syscallno),
2163 "d" (arg1) );
2164 return __res;
2165}
2166
2167static
2168int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00002169 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00002170{
2171 int __res;
2172 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2173 : "=a" (__res)
2174 : "0" (syscallno),
2175 "d" (arg1),
2176 "c" (arg2) );
2177 return __res;
2178}
2179
2180static
sewardjf854f472002-04-21 12:19:41 +00002181int my_do_syscall3 ( int syscallno,
2182 int arg1, int arg2, int arg3 )
2183{
2184 int __res;
2185 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
2186 : "=a" (__res)
2187 : "0" (syscallno),
2188 "S" (arg1),
2189 "c" (arg2),
2190 "d" (arg3) );
2191 return __res;
2192}
2193
sewardjd5bef572002-10-23 21:49:33 +00002194static inline
2195int my_do_syscall5 ( int syscallno,
2196 int arg1, int arg2, int arg3, int arg4, int arg5 )
2197{
2198 int __res;
2199 __asm__ volatile ("int $0x80"
2200 : "=a" (__res)
2201 : "0" (syscallno),
2202 "b" (arg1),
2203 "c" (arg2),
2204 "d" (arg3),
2205 "S" (arg4),
2206 "D" (arg5));
2207 return __res;
2208}
2209
sewardjf854f472002-04-21 12:19:41 +00002210static
sewardj08a4c3f2002-04-13 03:45:44 +00002211int do_syscall_select( int n,
2212 vki_fd_set* readfds,
2213 vki_fd_set* writefds,
2214 vki_fd_set* exceptfds,
2215 struct vki_timeval * timeout )
2216{
2217 int res;
2218 int args[5];
2219 args[0] = n;
2220 args[1] = (int)readfds;
2221 args[2] = (int)writefds;
2222 args[3] = (int)exceptfds;
2223 args[4] = (int)timeout;
2224 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00002225 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00002226}
2227
2228
2229/* This is a wrapper round select(), which makes it thread-safe,
2230 meaning that only this thread will block, rather than the entire
2231 process. This wrapper in turn depends on nanosleep() not to block
2232 the entire process, but I think (hope? suspect?) that POSIX
2233 pthreads guarantees that to be the case.
2234
2235 Basic idea is: modify the timeout parameter to select so that it
2236 returns immediately. Poll like this until select returns non-zero,
2237 indicating something interesting happened, or until our time is up.
njn25e49d8e72002-09-23 09:36:25 +00002238 Space out the polls with nanosleeps of say 11 milliseconds, which
sewardj08a4c3f2002-04-13 03:45:44 +00002239 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00002240
2241 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00002242 * (checked via my_assert) types fd_set and vki_fd_set are identical.
2243 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00002244 * (unchecked) libc error numbers (EINTR etc) are the negation of the
2245 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00002246*/
sewardj08a4c3f2002-04-13 03:45:44 +00002247
sewardj5905fae2002-04-26 13:25:00 +00002248/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00002249int select ( int n,
2250 fd_set *rfds,
2251 fd_set *wfds,
2252 fd_set *xfds,
2253 struct timeval *timeout )
2254{
sewardj5f07b662002-04-23 16:52:51 +00002255 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00002256 int res;
2257 fd_set rfds_copy;
2258 fd_set wfds_copy;
2259 fd_set xfds_copy;
2260 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00002261 struct vki_timeval zero_timeout;
2262 struct vki_timespec nanosleep_interval;
2263
sewardjd140e442002-05-29 01:21:19 +00002264 __my_pthread_testcancel();
2265
sewardj5f07b662002-04-23 16:52:51 +00002266 /* gcc's complains about ms_end being used uninitialised -- classic
2267 case it can't understand, where ms_end is both defined and used
2268 only if timeout != NULL. Hence ... */
2269 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00002270
2271 /* We assume that the kernel and libc data layouts are identical
2272 for the following types. These asserts provide a crude
2273 check. */
2274 if (sizeof(fd_set) != sizeof(vki_fd_set)
2275 || sizeof(struct timeval) != sizeof(struct vki_timeval))
2276 barf("valgrind's hacky non-blocking select(): data sizes error");
2277
sewardj5f07b662002-04-23 16:52:51 +00002278 /* Detect the current time and simultaneously find out if we are
2279 running on Valgrind. */
2280 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2281 VG_USERREQ__READ_MILLISECOND_TIMER,
2282 0, 0, 0, 0);
2283
2284 /* If a zero timeout specified, this call is harmless. Also go
2285 this route if we're not running on Valgrind, for whatever
2286 reason. */
2287 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
2288 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00002289 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00002290 (vki_fd_set*)wfds,
2291 (vki_fd_set*)xfds,
2292 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00002293 if (is_kerror(res)) {
2294 * (__errno_location()) = -res;
2295 return -1;
2296 } else {
2297 return res;
2298 }
2299 }
sewardj08a4c3f2002-04-13 03:45:44 +00002300
sewardj5f07b662002-04-23 16:52:51 +00002301 /* If a timeout was specified, set ms_end to be the end millisecond
2302 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00002303 if (timeout) {
2304 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00002305 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00002306 ms_end = ms_now;
2307 ms_end += (timeout->tv_usec / 1000);
2308 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00002309 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00002310 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00002311 }
2312
2313 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
2314
2315 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00002316 NULL, in which case ms_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002317
sewardj08a4c3f2002-04-13 03:45:44 +00002318 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002319
2320 /* First, do a return-immediately select(). */
sewardj08a4c3f2002-04-13 03:45:44 +00002321
2322 /* These could be trashed each time round the loop, so restore
2323 them each time. */
2324 if (rfds) rfds_copy = *rfds;
2325 if (wfds) wfds_copy = *wfds;
2326 if (xfds) xfds_copy = *xfds;
2327
2328 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
2329
2330 res = do_syscall_select( n,
2331 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
2332 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
2333 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
2334 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00002335 if (is_kerror(res)) {
2336 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00002337 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00002338 * (__errno_location()) = -res;
2339 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00002340 }
2341 if (res > 0) {
2342 /* one or more fds is ready. Copy out resulting sets and
2343 return. */
2344 if (rfds) *rfds = rfds_copy;
2345 if (wfds) *wfds = wfds_copy;
2346 if (xfds) *xfds = xfds_copy;
2347 return res;
2348 }
sewardj05bb2c92002-06-26 00:47:17 +00002349
2350 /* Nothing interesting happened, so we go to sleep for a
2351 while. */
2352
sewardj08a4c3f2002-04-13 03:45:44 +00002353 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
2354 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00002355 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002356 nanosleep_interval.tv_nsec = 11 * 1000 * 1000; /* 11 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00002357 /* It's critical here that valgrind's nanosleep implementation
2358 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00002359 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00002360 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00002361 if (res == -VKI_EINTR) {
2362 /* The nanosleep was interrupted by a signal. So we do the
2363 same. */
2364 * (__errno_location()) = EINTR;
2365 return -1;
2366 }
sewardj05bb2c92002-06-26 00:47:17 +00002367
2368 /* Sleeping finished. If a finite timeout, check to see if it
2369 has expired yet. */
2370 if (timeout) {
2371 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2372 VG_USERREQ__READ_MILLISECOND_TIMER,
2373 0, 0, 0, 0);
2374 my_assert(ms_now != 0xFFFFFFFF);
2375 if (ms_now >= ms_end) {
2376 /* timeout; nothing interesting happened. */
2377 if (rfds) FD_ZERO(rfds);
2378 if (wfds) FD_ZERO(wfds);
2379 if (xfds) FD_ZERO(xfds);
2380 return 0;
2381 }
2382 }
2383
sewardjf854f472002-04-21 12:19:41 +00002384 }
2385}
2386
2387
2388
2389
2390#include <sys/poll.h>
2391
sewardj3e909ce2002-06-03 13:27:15 +00002392#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00002393typedef unsigned long int nfds_t;
2394#endif
2395
sewardj705d3cb2002-05-23 13:13:12 +00002396
sewardj5905fae2002-04-26 13:25:00 +00002397/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00002398int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2399{
sewardj5f07b662002-04-23 16:52:51 +00002400 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00002401 int res, i;
sewardjf854f472002-04-21 12:19:41 +00002402 struct vki_timespec nanosleep_interval;
2403
sewardjd140e442002-05-29 01:21:19 +00002404 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00002405 ensure_valgrind("poll");
2406
sewardj5f07b662002-04-23 16:52:51 +00002407 /* Detect the current time and simultaneously find out if we are
2408 running on Valgrind. */
2409 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2410 VG_USERREQ__READ_MILLISECOND_TIMER,
2411 0, 0, 0, 0);
2412
sewardjf854f472002-04-21 12:19:41 +00002413 if (/* CHECK SIZES FOR struct pollfd */
2414 sizeof(struct timeval) != sizeof(struct vki_timeval))
2415 barf("valgrind's hacky non-blocking poll(): data sizes error");
2416
sewardj5f07b662002-04-23 16:52:51 +00002417 /* dummy initialisation to keep gcc -Wall happy */
2418 ms_end = 0;
2419
2420 /* If a zero timeout specified, this call is harmless. Also do
2421 this if not running on Valgrind. */
2422 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00002423 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
2424 if (is_kerror(res)) {
2425 * (__errno_location()) = -res;
2426 return -1;
2427 } else {
2428 return res;
2429 }
2430 }
2431
sewardj5f07b662002-04-23 16:52:51 +00002432 /* If a timeout was specified, set ms_end to be the end wallclock
2433 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002434 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002435 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002436 }
2437
2438 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2439
2440 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2441 in which case t_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002442
sewardj2d94c112002-06-03 01:25:54 +00002443 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002444
sewardjf854f472002-04-21 12:19:41 +00002445 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002446
2447 /* Do a return-immediately poll. */
2448
2449 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2450 if (is_kerror(res)) {
2451 /* Some kind of error. Set errno and return. */
2452 * (__errno_location()) = -res;
2453 return -1;
2454 }
2455 if (res > 0) {
2456 /* One or more fds is ready. Return now. */
2457 return res;
2458 }
2459
2460 /* Nothing interesting happened, so we go to sleep for a
2461 while. */
2462
2463 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2464 /* nanosleep and go round again */
2465 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002466 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
sewardj05bb2c92002-06-26 00:47:17 +00002467 /* It's critical here that valgrind's nanosleep implementation
2468 is nonblocking. */
2469 (void)my_do_syscall2(__NR_nanosleep,
2470 (int)(&nanosleep_interval), (int)NULL);
2471
2472 /* Sleeping finished. If a finite timeout, check to see if it
2473 has expired yet. */
sewardjf854f472002-04-21 12:19:41 +00002474 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002475 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2476 VG_USERREQ__READ_MILLISECOND_TIMER,
2477 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002478 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002479 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002480 /* timeout; nothing interesting happened. */
2481 for (i = 0; i < __nfds; i++)
2482 __fds[i].revents = 0;
2483 return 0;
2484 }
2485 }
2486
sewardj08a4c3f2002-04-13 03:45:44 +00002487 }
2488}
sewardj3b13f0e2002-04-25 20:17:29 +00002489
2490
sewardj705d3cb2002-05-23 13:13:12 +00002491/* Helper function used to make accept() non-blocking. Idea is to use
2492 the above nonblocking poll() to make this thread ONLY wait for the
2493 specified fd to become ready, and then return. */
sewardjd1c1cf22002-06-26 00:13:36 +00002494
2495/* Sigh -- a hack. We're not supposed to include this file directly;
2496 should do it via /usr/include/fcntl.h, but that introduces a
2497 varargs prototype for fcntl itself, which we can't mimic. */
2498#define _FCNTL_H
2499#include <bits/fcntl.h>
2500
sewardj705d3cb2002-05-23 13:13:12 +00002501static void wait_for_fd_to_be_readable_or_erring ( int fd )
2502{
2503 struct pollfd pfd;
sewardjd1c1cf22002-06-26 00:13:36 +00002504 int res;
2505
sewardj6e6cbaa2002-05-24 02:12:52 +00002506 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardjd1c1cf22002-06-26 00:13:36 +00002507
2508 /* First check to see if the fd is nonblocking, and/or invalid. In
2509 either case return immediately. */
2510 res = __libc_fcntl(fd, F_GETFL, 0);
2511 if (res == -1) return; /* fd is invalid somehow */
2512 if (res & O_NONBLOCK) return; /* fd is nonblocking */
2513
2514 /* Ok, we'd better wait with poll. */
sewardj705d3cb2002-05-23 13:13:12 +00002515 pfd.fd = fd;
2516 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2517 /* ... but not POLLOUT, you may notice. */
2518 pfd.revents = 0;
2519 (void)poll(&pfd, 1, -1 /* forever */);
2520}
2521
2522
sewardj3b13f0e2002-04-25 20:17:29 +00002523/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002524 Hacky implementation of semaphores.
2525 ------------------------------------------------------------------ */
2526
2527#include <semaphore.h>
2528
2529/* This is a terrible way to do the remapping. Plan is to import an
2530 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002531
2532typedef
2533 struct {
2534 pthread_mutex_t se_mx;
2535 pthread_cond_t se_cv;
2536 int count;
2537 }
2538 vg_sem_t;
2539
2540static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2541
2542static int se_remap_used = 0;
2543static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2544static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2545
2546static vg_sem_t* se_remap ( sem_t* orig )
2547{
2548 int res, i;
2549 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002550 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002551
2552 for (i = 0; i < se_remap_used; i++) {
2553 if (se_remap_orig[i] == orig)
2554 break;
2555 }
2556 if (i == se_remap_used) {
2557 if (se_remap_used == VG_N_SEMAPHORES) {
2558 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002559 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002560 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002561 }
2562 se_remap_used++;
2563 se_remap_orig[i] = orig;
2564 /* printf("allocated semaphore %d\n", i); */
2565 }
2566 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002567 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002568 return &se_remap_new[i];
2569}
2570
2571
2572int sem_init(sem_t *sem, int pshared, unsigned int value)
2573{
2574 int res;
2575 vg_sem_t* vg_sem;
2576 ensure_valgrind("sem_init");
2577 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002578 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002579 errno = ENOSYS;
2580 return -1;
2581 }
2582 vg_sem = se_remap(sem);
2583 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002584 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002585 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002586 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002587 vg_sem->count = value;
2588 return 0;
2589}
2590
2591
2592int sem_wait ( sem_t* sem )
2593{
2594 int res;
2595 vg_sem_t* vg_sem;
2596 ensure_valgrind("sem_wait");
2597 vg_sem = se_remap(sem);
2598 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002599 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002600 while (vg_sem->count == 0) {
2601 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002602 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002603 }
2604 vg_sem->count--;
2605 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002606 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002607 return 0;
2608}
2609
2610int sem_post ( sem_t* sem )
2611{
2612 int res;
2613 vg_sem_t* vg_sem;
2614 ensure_valgrind("sem_post");
2615 vg_sem = se_remap(sem);
2616 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002617 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002618 if (vg_sem->count == 0) {
2619 vg_sem->count++;
2620 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002621 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002622 } else {
2623 vg_sem->count++;
2624 }
2625 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002626 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002627 return 0;
2628}
2629
2630
2631int sem_trywait ( sem_t* sem )
2632{
2633 int ret, res;
2634 vg_sem_t* vg_sem;
2635 ensure_valgrind("sem_trywait");
2636 vg_sem = se_remap(sem);
2637 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002638 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002639 if (vg_sem->count > 0) {
2640 vg_sem->count--;
2641 ret = 0;
2642 } else {
2643 ret = -1;
2644 errno = EAGAIN;
2645 }
2646 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002647 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002648 return ret;
2649}
2650
2651
2652int sem_getvalue(sem_t* sem, int * sval)
2653{
2654 vg_sem_t* vg_sem;
2655 ensure_valgrind("sem_trywait");
2656 vg_sem = se_remap(sem);
2657 *sval = vg_sem->count;
2658 return 0;
2659}
2660
2661
2662int sem_destroy(sem_t * sem)
2663{
2664 kludged("sem_destroy");
2665 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2666 return 0;
2667}
2668
sewardj9ad92d92002-10-16 19:45:06 +00002669
2670int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2671{
2672 int res;
2673 vg_sem_t* vg_sem;
2674 ensure_valgrind("sem_timedwait");
2675 vg_sem = se_remap(sem);
2676 res = __pthread_mutex_lock(&vg_sem->se_mx);
2677 my_assert(res == 0);
2678 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
2679 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
2680 }
2681 if ( vg_sem->count > 0 ) {
2682 vg_sem->count--;
2683 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2684 my_assert(res == 0 );
2685 return 0;
2686 } else {
2687 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2688 my_assert(res == 0 );
2689 *(__errno_location()) = ETIMEDOUT;
2690 return -1;
2691 }
2692}
2693
sewardj8f253ff2002-05-19 00:13:34 +00002694
2695/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002696 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002697 ------------------------------------------------------------------ */
2698
sewardj2d8b3f02002-06-01 14:14:19 +00002699typedef
2700 struct {
2701 int initted; /* != 0 --> in use; sanity check only */
2702 int prefer_w; /* != 0 --> prefer writer */
2703 int nwait_r; /* # of waiting readers */
2704 int nwait_w; /* # of waiting writers */
2705 pthread_cond_t cv_r; /* for signalling readers */
2706 pthread_cond_t cv_w; /* for signalling writers */
2707 pthread_mutex_t mx;
2708 int status;
2709 /* allowed range for status: >= -1. -1 means 1 writer currently
2710 active, >= 0 means N readers currently active. */
2711 }
2712 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002713
2714
2715static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2716
2717static int rw_remap_used = 0;
2718static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2719static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2720
sewardj2d8b3f02002-06-01 14:14:19 +00002721
2722static
2723void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2724{
2725 int res = 0;
2726 vg_rwl->initted = 1;
2727 vg_rwl->prefer_w = 1;
2728 vg_rwl->nwait_r = 0;
2729 vg_rwl->nwait_w = 0;
2730 vg_rwl->status = 0;
2731 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2732 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2733 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002734 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002735}
2736
2737
sewardja1ac5cb2002-05-27 13:00:05 +00002738/* Take the address of a LinuxThreads rwlock_t and return the shadow
2739 address of our version. Further, if the LinuxThreads version
2740 appears to have been statically initialised, do the same to the one
2741 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2742 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2743 uninitialised and non-zero meaning initialised.
2744*/
2745static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2746{
2747 int res, i;
2748 vg_rwlock_t* vg_rwl;
2749 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002750 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002751
2752 for (i = 0; i < rw_remap_used; i++) {
2753 if (rw_remap_orig[i] == orig)
2754 break;
2755 }
2756 if (i == rw_remap_used) {
2757 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002758 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002759 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002760 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2761 }
2762 rw_remap_used++;
2763 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002764 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002765 if (0) printf("allocated rwlock %d\n", i);
2766 }
2767 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002768 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002769 vg_rwl = &rw_remap_new[i];
2770
sewardj2d8b3f02002-06-01 14:14:19 +00002771 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002772 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002773 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002774 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002775 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002776 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002777 }
2778
2779 return vg_rwl;
2780}
2781
2782
sewardja1ac5cb2002-05-27 13:00:05 +00002783int pthread_rwlock_init ( pthread_rwlock_t* orig,
2784 const pthread_rwlockattr_t* attr )
2785{
sewardja1ac5cb2002-05-27 13:00:05 +00002786 vg_rwlock_t* rwl;
2787 if (0) printf ("pthread_rwlock_init\n");
2788 /* Force the remapper to initialise the shadow. */
2789 orig->__rw_readers = 0;
2790 /* Install the lock preference; the remapper needs to know it. */
2791 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2792 if (attr)
2793 orig->__rw_kind = attr->__lockkind;
2794 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002795 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002796}
2797
sewardj2d8b3f02002-06-01 14:14:19 +00002798
2799static
2800void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002801{
sewardj2d8b3f02002-06-01 14:14:19 +00002802 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2803 rwl->nwait_r--;
2804 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002805}
2806
sewardj2d8b3f02002-06-01 14:14:19 +00002807
sewardja1ac5cb2002-05-27 13:00:05 +00002808int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2809{
2810 int res;
2811 vg_rwlock_t* rwl;
2812 if (0) printf ("pthread_rwlock_rdlock\n");
2813 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002814 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002815 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002816 if (!rwl->initted) {
2817 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002818 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002819 return EINVAL;
2820 }
2821 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002822 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002823 rwl->nwait_r++;
2824 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2825 while (1) {
2826 if (rwl->status == 0) break;
2827 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002828 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002829 }
2830 pthread_cleanup_pop(0);
2831 rwl->nwait_r--;
2832 }
sewardj2d94c112002-06-03 01:25:54 +00002833 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002834 rwl->status++;
2835 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002836 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002837 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002838}
2839
sewardj2d8b3f02002-06-01 14:14:19 +00002840
sewardja1ac5cb2002-05-27 13:00:05 +00002841int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2842{
2843 int res;
2844 vg_rwlock_t* rwl;
2845 if (0) printf ("pthread_rwlock_tryrdlock\n");
2846 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002847 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002848 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002849 if (!rwl->initted) {
2850 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002851 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002852 return EINVAL;
2853 }
2854 if (rwl->status == -1) {
2855 /* Writer active; we have to give up. */
2856 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002857 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002858 return EBUSY;
2859 }
2860 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002861 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002862 rwl->status++;
2863 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002864 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002865 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002866}
2867
sewardj2d8b3f02002-06-01 14:14:19 +00002868
2869static
2870void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2871{
2872 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2873 rwl->nwait_w--;
2874 pthread_mutex_unlock (&rwl->mx);
2875}
2876
2877
sewardja1ac5cb2002-05-27 13:00:05 +00002878int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2879{
2880 int res;
2881 vg_rwlock_t* rwl;
2882 if (0) printf ("pthread_rwlock_wrlock\n");
2883 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002884 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002885 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002886 if (!rwl->initted) {
2887 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002888 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002889 return EINVAL;
2890 }
2891 if (rwl->status != 0) {
2892 rwl->nwait_w++;
2893 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2894 while (1) {
2895 if (rwl->status == 0) break;
2896 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002897 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002898 }
2899 pthread_cleanup_pop(0);
2900 rwl->nwait_w--;
2901 }
sewardj2d94c112002-06-03 01:25:54 +00002902 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002903 rwl->status = -1;
2904 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002905 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002906 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002907}
2908
sewardj2d8b3f02002-06-01 14:14:19 +00002909
sewardja1ac5cb2002-05-27 13:00:05 +00002910int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2911{
2912 int res;
2913 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002914 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002915 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002916 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002917 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002918 if (!rwl->initted) {
2919 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002920 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002921 return EINVAL;
2922 }
2923 if (rwl->status != 0) {
2924 /* Reader(s) or a writer active; we have to give up. */
2925 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002926 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002927 return EBUSY;
2928 }
2929 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002930 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002931 rwl->status = -1;
2932 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002933 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002934 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002935}
2936
sewardj2d8b3f02002-06-01 14:14:19 +00002937
sewardja1ac5cb2002-05-27 13:00:05 +00002938int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2939{
2940 int res;
2941 vg_rwlock_t* rwl;
2942 if (0) printf ("pthread_rwlock_unlock\n");
2943 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002944 rwl = rw_remap ( orig );
2945 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002946 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002947 if (!rwl->initted) {
2948 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002949 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002950 return EINVAL;
2951 }
2952 if (rwl->status == 0) {
2953 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002954 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002955 return EPERM;
2956 }
sewardj2d94c112002-06-03 01:25:54 +00002957 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002958 if (rwl->status == -1) {
2959 rwl->status = 0;
2960 } else {
sewardj2d94c112002-06-03 01:25:54 +00002961 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002962 rwl->status--;
2963 }
2964
sewardj2d94c112002-06-03 01:25:54 +00002965 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002966
2967 if (rwl->prefer_w) {
2968
2969 /* Favour waiting writers, if any. */
2970 if (rwl->nwait_w > 0) {
2971 /* Writer(s) are waiting. */
2972 if (rwl->status == 0) {
2973 /* We can let a writer in. */
2974 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002975 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002976 } else {
2977 /* There are still readers active. Do nothing; eventually
2978 they will disappear, at which point a writer will be
2979 admitted. */
2980 }
2981 }
2982 else
2983 /* No waiting writers. */
2984 if (rwl->nwait_r > 0) {
2985 /* Let in a waiting reader. */
2986 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002987 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002988 }
2989
2990 } else {
2991
2992 /* Favour waiting readers, if any. */
2993 if (rwl->nwait_r > 0) {
2994 /* Reader(s) are waiting; let one in. */
2995 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002996 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002997 }
2998 else
2999 /* No waiting readers. */
3000 if (rwl->nwait_w > 0 && rwl->status == 0) {
3001 /* We have waiting writers and no active readers; let a
3002 writer in. */
3003 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00003004 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003005 }
3006 }
3007
3008 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003009 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003010 return 0;
3011}
3012
3013
3014int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
3015{
3016 int res;
3017 vg_rwlock_t* rwl;
3018 if (0) printf ("pthread_rwlock_destroy\n");
3019 rwl = rw_remap ( orig );
3020 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003021 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003022 if (!rwl->initted) {
3023 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003024 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003025 return EINVAL;
3026 }
3027 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
3028 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003029 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003030 return EBUSY;
3031 }
3032 rwl->initted = 0;
3033 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003034 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003035 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003036}
3037
3038
sewardj47e4e312002-06-18 09:24:34 +00003039/* Copied directly from LinuxThreads. */
3040int
3041pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
3042{
3043 attr->__lockkind = 0;
3044 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
3045
3046 return 0;
3047}
3048
sewardjfe18eb82002-07-13 12:58:44 +00003049/* Copied directly from LinuxThreads. */
3050int
3051pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
3052{
3053 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
3054 return EINVAL;
3055
3056 /* For now it is not possible to shared a conditional variable. */
3057 if (pshared != PTHREAD_PROCESS_PRIVATE)
3058 return ENOSYS;
3059
3060 attr->__pshared = pshared;
3061
3062 return 0;
3063}
3064
sewardj47e4e312002-06-18 09:24:34 +00003065
sewardja1ac5cb2002-05-27 13:00:05 +00003066/* ---------------------------------------------------------------------
sewardjd5bef572002-10-23 21:49:33 +00003067 Make SYSV IPC not block everything
3068 ------------------------------------------------------------------ */
3069
3070#include <sys/ipc.h>
3071#include <sys/msg.h>
3072#include <asm/ipc.h> /* for ipc_kludge */
3073
3074static inline int sys_ipc(unsigned call, int first, int second, int third, void *ptr)
3075{
3076 return my_do_syscall5(__NR_ipc, call, first, second, third, (int)ptr);
3077}
3078
3079/* Turn a blocking msgsnd() into a polling non-blocking one, so that
3080 other threads make progress */
sewardjf220ccc2002-10-23 21:53:49 +00003081int VGL_(msgsnd)(int msgid, const void *msgp, size_t msgsz, int msgflg)
sewardjd5bef572002-10-23 21:49:33 +00003082{
3083 struct vki_timespec nanosleep_interval;
3084 int err;
3085
3086 ensure_valgrind("msgsnd");
3087
3088 nanosleep_interval.tv_sec = 0;
3089 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
3090
3091 if (msgflg & IPC_NOWAIT) {
3092 /* If we aren't blocking anyway, just do it */
3093 err = sys_ipc(11, msgid, msgsz, msgflg, (void *)msgp);
3094 } else {
3095 /* Otherwise poll on the queue to let other things run */
3096 for(;;) {
3097 err = sys_ipc(11, msgid, msgsz, msgflg | IPC_NOWAIT, (void *)msgp);
3098
3099 if (err != -EAGAIN)
3100 break;
3101
3102 (void)my_do_syscall2(__NR_nanosleep,
3103 (int)(&nanosleep_interval), (int)NULL);
3104 }
3105 }
3106
3107 if (is_kerror(err)) {
3108 *(__errno_location()) = -err;
3109 return -1;
3110 }
3111 return 0;
3112}
3113
3114/* Turn a blocking msgrcv() into a polling non-blocking one, so that
3115 other threads make progress */
sewardjf220ccc2002-10-23 21:53:49 +00003116int VGL_(msgrcv)( int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg )
sewardjd5bef572002-10-23 21:49:33 +00003117{
3118 struct vki_timespec nanosleep_interval;
3119 int err;
3120 struct ipc_kludge tmp;
3121
3122 ensure_valgrind("msgrcv");
3123
3124 nanosleep_interval.tv_sec = 0;
3125 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
3126
3127 tmp.msgp = msgp;
3128 tmp.msgtyp = msgtyp;
3129
3130 if (msgflg & IPC_NOWAIT) {
3131 /* If we aren't blocking anyway, just do it */
3132 err = sys_ipc(12, msqid, msgsz, msgflg, &tmp );
3133 } else {
3134 /* Otherwise poll on the queue to let other things run */
3135 for(;;) {
3136 err = sys_ipc(12, msqid, msgsz, msgflg | IPC_NOWAIT, &tmp );
3137
3138 if (err != -ENOMSG)
3139 break;
3140
3141 (void)my_do_syscall2(__NR_nanosleep,
3142 (int)(&nanosleep_interval), (int)NULL);
3143 }
3144 }
3145
3146 if (is_kerror(err)) {
3147 *(__errno_location()) = -err;
3148 return -1;
3149 }
3150
3151 return 0;
3152}
3153
3154
3155
3156/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00003157 B'stard.
3158 ------------------------------------------------------------------ */
3159
3160# define strong_alias(name, aliasname) \
3161 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
3162
sewardj5905fae2002-04-26 13:25:00 +00003163# define weak_alias(name, aliasname) \
3164 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00003165
sewardj5905fae2002-04-26 13:25:00 +00003166strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
3167strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
3168strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
3169strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
3170 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
3171strong_alias(__pthread_mutex_init, pthread_mutex_init)
3172strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
3173strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
3174strong_alias(__pthread_once, pthread_once)
3175strong_alias(__pthread_atfork, pthread_atfork)
3176strong_alias(__pthread_key_create, pthread_key_create)
3177strong_alias(__pthread_getspecific, pthread_getspecific)
3178strong_alias(__pthread_setspecific, pthread_setspecific)
3179
sewardjd529a442002-05-04 19:49:21 +00003180#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00003181strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00003182#endif
3183
sewardj5905fae2002-04-26 13:25:00 +00003184strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00003185strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00003186strong_alias(lseek, __lseek)
3187strong_alias(open, __open)
3188strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00003189strong_alias(read, __read)
3190strong_alias(wait, __wait)
3191strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00003192strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00003193strong_alias(send, __send)
sewardj3fd559e2002-10-20 16:24:04 +00003194strong_alias(poll, __poll)
3195strong_alias(select, __select)
sewardj5905fae2002-04-26 13:25:00 +00003196
sewardj726c4122002-05-16 23:39:10 +00003197weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00003198weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00003199weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00003200weak_alias(__vfork, vfork)
sewardj7f6456d2002-05-21 00:51:21 +00003201
sewardjf0b06452002-06-04 08:38:04 +00003202weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00003203
3204/*--------------------------------------------------*/
3205
sewardj5905fae2002-04-26 13:25:00 +00003206weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00003207weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00003208weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00003209
sewardja1ac5cb2002-05-27 13:00:05 +00003210weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
3211weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
3212weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
3213weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
3214
sewardj060b04f2002-04-26 21:01:13 +00003215
sewardj3b13f0e2002-04-25 20:17:29 +00003216/* I've no idea what these are, but they get called quite a lot.
3217 Anybody know? */
3218
3219#undef _IO_flockfile
3220void _IO_flockfile ( _IO_FILE * file )
3221{
sewardj853f55d2002-04-26 00:27:53 +00003222 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003223}
sewardj5905fae2002-04-26 13:25:00 +00003224weak_alias(_IO_flockfile, flockfile);
3225
sewardj3b13f0e2002-04-25 20:17:29 +00003226
3227#undef _IO_funlockfile
3228void _IO_funlockfile ( _IO_FILE * file )
3229{
sewardj853f55d2002-04-26 00:27:53 +00003230 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003231}
sewardj5905fae2002-04-26 13:25:00 +00003232weak_alias(_IO_funlockfile, funlockfile);
3233
sewardj3b13f0e2002-04-25 20:17:29 +00003234
sewardjd4f2c712002-04-30 10:20:10 +00003235/* This doesn't seem to be needed to simulate libpthread.so's external
3236 interface, but many people complain about its absence. */
3237
3238strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
3239weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00003240
3241
3242/*--------------------------------------------------------------------*/
3243/*--- end vg_libpthread.c ---*/
3244/*--------------------------------------------------------------------*/