blob: 363e6ffd2cfabf1594cdd1ce0cd2d0f6bb3fc2a0 [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
1422static
1423void ** __pthread_getspecific_addr(pthread_key_t key)
1424{
1425 void** specifics_ptr;
1426 ensure_valgrind("pthread_getspecific_addr");
1427
1428 if (!key_is_valid(key))
1429 return NULL;
1430
1431 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1432 return &(specifics_ptr[key]);
sewardj5e5fa512002-04-14 13:13:05 +00001433}
1434
sewardjf8f819e2002-04-17 23:21:37 +00001435
1436/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001437 ONCEry
1438 ------------------------------------------------ */
1439
1440static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1441
1442
sewardj5905fae2002-04-26 13:25:00 +00001443int __pthread_once ( pthread_once_t *once_control,
1444 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001445{
1446 int res;
1447 ensure_valgrind("pthread_once");
1448
sewardj68b2dd92002-05-10 21:03:56 +00001449 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001450
sewardj68b2dd92002-05-10 21:03:56 +00001451 if (res != 0) {
sewardj89d3d852002-04-24 19:21:39 +00001452 barf("pthread_once: Looks like your program's "
1453 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001454 }
sewardj89d3d852002-04-24 19:21:39 +00001455
1456 if (*once_control == 0) {
1457 *once_control = 1;
1458 init_routine();
1459 }
1460
sewardj68b2dd92002-05-10 21:03:56 +00001461 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001462
1463 return 0;
1464}
1465
1466
1467/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001468 MISC
1469 ------------------------------------------------ */
1470
sewardj2cb00342002-06-28 01:46:26 +00001471static pthread_mutex_t pthread_atfork_lock
1472 = PTHREAD_MUTEX_INITIALIZER;
1473
sewardj5905fae2002-04-26 13:25:00 +00001474int __pthread_atfork ( void (*prepare)(void),
1475 void (*parent)(void),
1476 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001477{
sewardj2cb00342002-06-28 01:46:26 +00001478 int n, res;
1479 ForkHandlerEntry entry;
1480
1481 ensure_valgrind("pthread_atfork");
1482 __pthread_mutex_lock(&pthread_atfork_lock);
1483
1484 /* Fetch old counter */
1485 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1486 VG_USERREQ__GET_FHSTACK_USED,
1487 0, 0, 0, 0);
1488 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1489 if (n == VG_N_FORKHANDLERSTACK-1)
1490 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1491 "increase and recompile");
1492
1493 /* Add entry */
1494 entry.prepare = *prepare;
1495 entry.parent = *parent;
1496 entry.child = *child;
1497 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1498 VG_USERREQ__SET_FHSTACK_ENTRY,
1499 n, &entry, 0, 0);
1500 my_assert(res == 0);
1501
1502 /* Bump counter */
1503 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1504 VG_USERREQ__SET_FHSTACK_USED,
1505 n+1, 0, 0, 0);
1506 my_assert(res == 0);
1507
1508 __pthread_mutex_unlock(&pthread_atfork_lock);
1509 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001510}
1511
1512
sewardjbb990782002-05-08 02:01:14 +00001513__attribute__((weak))
1514void __pthread_initialize ( void )
1515{
sewardjbea1caa2002-05-10 23:20:58 +00001516 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001517}
1518
1519
sewardj853f55d2002-04-26 00:27:53 +00001520/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001521 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001522 ------------------------------------------------ */
1523
sewardj3b13f0e2002-04-25 20:17:29 +00001524#include <resolv.h>
1525static int thread_specific_errno[VG_N_THREADS];
1526static int thread_specific_h_errno[VG_N_THREADS];
1527static struct __res_state
1528 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001529
sewardj3b13f0e2002-04-25 20:17:29 +00001530int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001531{
1532 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001533 /* ensure_valgrind("__errno_location"); */
1534 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001535 VG_USERREQ__PTHREAD_GET_THREADID,
1536 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001537 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001538 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001539 barf("__errno_location: invalid ThreadId");
1540 return & thread_specific_errno[tid];
1541}
1542
1543int* __h_errno_location ( void )
1544{
1545 int tid;
1546 /* ensure_valgrind("__h_errno_location"); */
1547 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1548 VG_USERREQ__PTHREAD_GET_THREADID,
1549 0, 0, 0, 0);
1550 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001551 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001552 barf("__h_errno_location: invalid ThreadId");
1553 return & thread_specific_h_errno[tid];
1554}
1555
sewardjb0ff1032002-08-06 09:02:53 +00001556
1557#undef _res
1558extern struct __res_state _res;
1559
sewardj3b13f0e2002-04-25 20:17:29 +00001560struct __res_state* __res_state ( void )
1561{
1562 int tid;
1563 /* ensure_valgrind("__res_state"); */
1564 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1565 VG_USERREQ__PTHREAD_GET_THREADID,
1566 0, 0, 0, 0);
1567 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001568 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001569 barf("__res_state: invalid ThreadId");
sewardjb0ff1032002-08-06 09:02:53 +00001570 if (tid == 1)
1571 return & _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001572 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001573}
1574
1575
sewardj5716dbb2002-04-26 03:28:18 +00001576/* ---------------------------------------------------
1577 LIBC-PRIVATE SPECIFIC DATA
1578 ------------------------------------------------ */
1579
1580/* Relies on assumption that initial private data is NULL. This
1581 should be fixed somehow. */
1582
njn25e49d8e72002-09-23 09:36:25 +00001583/* The allowable keys (indices) (all 3 of them).
sewardj5716dbb2002-04-26 03:28:18 +00001584 From sysdeps/pthread/bits/libc-tsd.h
1585*/
sewardjcb7f08a2002-10-02 09:41:49 +00001586/* as per glibc anoncvs HEAD of 20021001. */
sewardj5716dbb2002-04-26 03:28:18 +00001587enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1588 _LIBC_TSD_KEY_DL_ERROR,
njn25e49d8e72002-09-23 09:36:25 +00001589 _LIBC_TSD_KEY_RPC_VARS,
sewardjcb7f08a2002-10-02 09:41:49 +00001590 _LIBC_TSD_KEY_LOCALE,
1591 _LIBC_TSD_KEY_CTYPE_B,
1592 _LIBC_TSD_KEY_CTYPE_TOLOWER,
1593 _LIBC_TSD_KEY_CTYPE_TOUPPER,
sewardj5716dbb2002-04-26 03:28:18 +00001594 _LIBC_TSD_KEY_N };
1595
1596/* Auto-initialising subsystem. libc_specifics_inited is set
1597 after initialisation. libc_specifics_inited_mx guards it. */
1598static int libc_specifics_inited = 0;
1599static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1600
sewardj00a66b12002-10-12 16:42:35 +00001601
sewardj5716dbb2002-04-26 03:28:18 +00001602/* These are the keys we must initialise the first time. */
sewardjcb7f08a2002-10-02 09:41:49 +00001603static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N];
sewardj5716dbb2002-04-26 03:28:18 +00001604
sewardj00a66b12002-10-12 16:42:35 +00001605
sewardjcb7f08a2002-10-02 09:41:49 +00001606/* Initialise the keys, if they are not already initialised. */
sewardj5716dbb2002-04-26 03:28:18 +00001607static
1608void init_libc_tsd_keys ( void )
1609{
1610 int res, i;
1611 pthread_key_t k;
1612
sewardj08c7f012002-10-07 23:56:55 +00001613 /* Don't fall into deadlock if we get called again whilst we still
1614 hold the lock, via the __uselocale() call herein. */
1615 if (libc_specifics_inited != 0)
1616 return;
1617
1618 /* Take the lock. */
sewardj00a66b12002-10-12 16:42:35 +00001619 res = __pthread_mutex_lock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001620 if (res != 0) barf("init_libc_tsd_keys: lock");
1621
sewardj08c7f012002-10-07 23:56:55 +00001622 /* Now test again, to be sure there is no mistake. */
1623 if (libc_specifics_inited != 0) {
sewardj00a66b12002-10-12 16:42:35 +00001624 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj08c7f012002-10-07 23:56:55 +00001625 if (res != 0) barf("init_libc_tsd_keys: unlock(1)");
1626 return;
sewardj5716dbb2002-04-26 03:28:18 +00001627 }
1628
sewardj08c7f012002-10-07 23:56:55 +00001629 /* Actually do the initialisation. */
1630 /* printf("INIT libc specifics\n"); */
1631 for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
sewardj00a66b12002-10-12 16:42:35 +00001632 res = __pthread_key_create(&k, NULL);
sewardj08c7f012002-10-07 23:56:55 +00001633 if (res != 0) barf("init_libc_tsd_keys: create");
1634 libc_specifics_keys[i] = k;
1635 }
1636
1637 /* Signify init done. */
1638 libc_specifics_inited = 1;
1639
1640# ifdef GLIBC_2_3
1641 /* Set the initialising thread's locale to the global (default)
sewardj00a66b12002-10-12 16:42:35 +00001642 locale. A hack in support of glibc-2.3. This does the biz for
1643 the root thread. For all other threads we run this in
1644 thread_wrapper(), which does the real work of
1645 pthread_create(). */
1646 /* assert that we are the root thread. I don't know if this is
1647 really a valid assertion to make; if it breaks I'll reconsider
1648 it. */
1649 my_assert(pthread_self() == 1);
sewardj08c7f012002-10-07 23:56:55 +00001650 __uselocale(LC_GLOBAL_LOCALE);
1651# endif
1652
1653 /* Unlock and return. */
sewardj00a66b12002-10-12 16:42:35 +00001654 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001655 if (res != 0) barf("init_libc_tsd_keys: unlock");
1656}
1657
1658
1659static int
1660libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1661 const void * pointer )
1662{
sewardjcb7f08a2002-10-02 09:41:49 +00001663 int res;
sewardj5716dbb2002-04-26 03:28:18 +00001664 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardjcb7f08a2002-10-02 09:41:49 +00001665 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001666 barf("libc_internal_tsd_set: invalid key");
1667 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001668 res = __pthread_setspecific(libc_specifics_keys[key], pointer);
sewardj5716dbb2002-04-26 03:28:18 +00001669 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1670 return 0;
1671}
1672
1673static void *
1674libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1675{
sewardjcb7f08a2002-10-02 09:41:49 +00001676 void* v;
sewardj5716dbb2002-04-26 03:28:18 +00001677 /* printf("GET GET GET key %d\n", key); */
sewardjcb7f08a2002-10-02 09:41:49 +00001678 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001679 barf("libc_internal_tsd_get: invalid key");
1680 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001681 v = __pthread_getspecific(libc_specifics_keys[key]);
sewardj5716dbb2002-04-26 03:28:18 +00001682 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1683 return v;
1684}
1685
1686
sewardj70adeb22002-04-27 01:35:38 +00001687int (*__libc_internal_tsd_set)
1688 (enum __libc_tsd_key_t key, const void * pointer)
1689 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001690
sewardj70adeb22002-04-27 01:35:38 +00001691void* (*__libc_internal_tsd_get)
1692 (enum __libc_tsd_key_t key)
1693 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001694
1695
sewardj00a66b12002-10-12 16:42:35 +00001696#ifdef GLIBC_2_3
1697/* This one was first spotted be me in the glibc-2.2.93 sources. */
1698static void**
1699libc_internal_tsd_address ( enum __libc_tsd_key_t key )
1700{
1701 void** v;
1702 /* printf("ADDR ADDR ADDR key %d\n", key); */
1703 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
1704 barf("libc_internal_tsd_address: invalid key");
1705 init_libc_tsd_keys();
1706 v = __pthread_getspecific_addr(libc_specifics_keys[key]);
1707 return v;
1708}
1709
1710void ** (*__libc_internal_tsd_address)
1711 (enum __libc_tsd_key_t key)
1712 = libc_internal_tsd_address;
1713#endif
1714
1715
sewardje663cb92002-04-12 10:26:32 +00001716/* ---------------------------------------------------------------------
1717 These are here (I think) because they are deemed cancellation
1718 points by POSIX. For the moment we'll simply pass the call along
1719 to the corresponding thread-unaware (?) libc routine.
1720 ------------------------------------------------------------------ */
1721
sewardje663cb92002-04-12 10:26:32 +00001722#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001723#include <sys/types.h>
1724#include <sys/socket.h>
1725
sewardjd529a442002-05-04 19:49:21 +00001726#ifdef GLIBC_2_1
1727extern
1728int __sigaction
1729 (int signum,
1730 const struct sigaction *act,
1731 struct sigaction *oldact);
1732#else
sewardje663cb92002-04-12 10:26:32 +00001733extern
1734int __libc_sigaction
1735 (int signum,
1736 const struct sigaction *act,
1737 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001738#endif
sewardje663cb92002-04-12 10:26:32 +00001739int sigaction(int signum,
1740 const struct sigaction *act,
1741 struct sigaction *oldact)
1742{
sewardjd140e442002-05-29 01:21:19 +00001743 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001744# ifdef GLIBC_2_1
1745 return __sigaction(signum, act, oldact);
1746# else
sewardj45b4b372002-04-16 22:50:32 +00001747 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001748# endif
sewardje663cb92002-04-12 10:26:32 +00001749}
1750
1751
1752extern
1753int __libc_connect(int sockfd,
1754 const struct sockaddr *serv_addr,
1755 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001756__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001757int connect(int sockfd,
1758 const struct sockaddr *serv_addr,
1759 socklen_t addrlen)
1760{
sewardjd140e442002-05-29 01:21:19 +00001761 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001762 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001763}
1764
1765
1766extern
1767int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001768__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001769int fcntl(int fd, int cmd, long arg)
1770{
sewardjd140e442002-05-29 01:21:19 +00001771 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001772 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001773}
1774
1775
1776extern
1777ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001778__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001779ssize_t write(int fd, const void *buf, size_t count)
1780{
sewardjd140e442002-05-29 01:21:19 +00001781 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001782 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001783}
1784
1785
1786extern
1787ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001788__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001789ssize_t read(int fd, void *buf, size_t count)
1790{
sewardjd140e442002-05-29 01:21:19 +00001791 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001792 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001793}
1794
sewardjbe32e452002-04-24 20:29:58 +00001795
1796extern
sewardj853f55d2002-04-26 00:27:53 +00001797int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001798__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001799int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001800{
sewardjd140e442002-05-29 01:21:19 +00001801 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001802 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001803}
1804
sewardje663cb92002-04-12 10:26:32 +00001805
1806extern
sewardj853f55d2002-04-26 00:27:53 +00001807int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001808__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001809int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001810{
sewardjd140e442002-05-29 01:21:19 +00001811 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001812 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001813}
1814
1815
1816extern
1817int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001818__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001819int close(int fd)
1820{
sewardjd140e442002-05-29 01:21:19 +00001821 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001822 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001823}
1824
1825
1826extern
1827int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001828__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001829int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1830{
sewardjd140e442002-05-29 01:21:19 +00001831 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001832 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001833 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001834 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001835}
1836
1837
1838extern
sewardje663cb92002-04-12 10:26:32 +00001839pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001840__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001841pid_t waitpid(pid_t pid, int *status, int options)
1842{
sewardjd140e442002-05-29 01:21:19 +00001843 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001844 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001845}
1846
1847
1848extern
1849int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001850__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001851int nanosleep(const struct timespec *req, struct timespec *rem)
1852{
sewardjd140e442002-05-29 01:21:19 +00001853 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001854 return __libc_nanosleep(req, rem);
1855}
1856
sewardjbe32e452002-04-24 20:29:58 +00001857
sewardje663cb92002-04-12 10:26:32 +00001858extern
1859int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001860__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001861int fsync(int fd)
1862{
sewardjd140e442002-05-29 01:21:19 +00001863 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001864 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001865}
1866
sewardjbe32e452002-04-24 20:29:58 +00001867
sewardj70c75362002-04-13 04:18:32 +00001868extern
1869off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001870__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001871off_t lseek(int fildes, off_t offset, int whence)
1872{
sewardjd140e442002-05-29 01:21:19 +00001873 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001874 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001875}
1876
sewardjbe32e452002-04-24 20:29:58 +00001877
1878extern
1879__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001880__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001881__off64_t lseek64(int fildes, __off64_t offset, int whence)
1882{
sewardjd140e442002-05-29 01:21:19 +00001883 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001884 return __libc_lseek64(fildes, offset, whence);
1885}
1886
1887
sewardj726c4122002-05-16 23:39:10 +00001888extern
1889ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1890 __off64_t __offset);
1891ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1892 __off64_t __offset)
1893{
sewardjd140e442002-05-29 01:21:19 +00001894 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001895 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1896}
1897
1898
sewardja18e2102002-05-18 10:43:22 +00001899extern
1900ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1901 __off64_t __offset);
1902ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1903 __off64_t __offset)
1904{
sewardjd140e442002-05-29 01:21:19 +00001905 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001906 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1907}
1908
sewardj726c4122002-05-16 23:39:10 +00001909
sewardj39b93b12002-05-18 10:56:27 +00001910extern
1911ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1912__attribute__((weak))
1913ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1914{
sewardjd140e442002-05-29 01:21:19 +00001915 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001916 return __libc_pwrite(fd, buf, count, offset);
1917}
1918
1919
1920extern
1921ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1922__attribute__((weak))
1923ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1924{
sewardjd140e442002-05-29 01:21:19 +00001925 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001926 return __libc_pread(fd, buf, count, offset);
1927}
1928
1929
sewardj6af4b5d2002-04-16 04:40:49 +00001930extern
1931void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001932/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001933void longjmp(jmp_buf env, int val)
1934{
1935 __libc_longjmp(env, val);
1936}
1937
sewardjbe32e452002-04-24 20:29:58 +00001938
sewardj436c2db2002-06-18 09:07:54 +00001939extern void __libc_siglongjmp (sigjmp_buf env, int val)
1940 __attribute__ ((noreturn));
1941void siglongjmp(sigjmp_buf env, int val)
1942{
1943 kludged("siglongjmp (cleanup handlers are ignored)");
1944 __libc_siglongjmp(env, val);
1945}
1946
1947
sewardj6af4b5d2002-04-16 04:40:49 +00001948extern
1949int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001950__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001951int send(int s, const void *msg, size_t len, int flags)
1952{
sewardjd140e442002-05-29 01:21:19 +00001953 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001954 return __libc_send(s, msg, len, flags);
1955}
1956
sewardjbe32e452002-04-24 20:29:58 +00001957
sewardj1e8cdc92002-04-18 11:37:52 +00001958extern
1959int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001960__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001961int recv(int s, void *buf, size_t len, int flags)
1962{
sewardjd140e442002-05-29 01:21:19 +00001963 __my_pthread_testcancel();
sewardj1d6b3a22002-06-20 07:58:33 +00001964 wait_for_fd_to_be_readable_or_erring(s);
1965 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001966 return __libc_recv(s, buf, len, flags);
1967}
1968
sewardjbe32e452002-04-24 20:29:58 +00001969
sewardj3665ded2002-05-16 16:57:25 +00001970extern
1971int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1972__attribute__((weak))
1973int sendmsg(int s, const struct msghdr *msg, int flags)
1974{
sewardjd140e442002-05-29 01:21:19 +00001975 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001976 return __libc_sendmsg(s, msg, flags);
1977}
1978
1979
sewardj796d6a22002-04-24 02:28:34 +00001980extern
sewardj59da27a2002-06-06 08:33:54 +00001981int __libc_recvmsg(int s, struct msghdr *msg, int flags);
1982__attribute__((weak))
1983int recvmsg(int s, struct msghdr *msg, int flags)
1984{
1985 __my_pthread_testcancel();
1986 return __libc_recvmsg(s, msg, flags);
1987}
1988
1989
1990extern
sewardj436e0582002-04-26 14:31:40 +00001991int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1992 struct sockaddr *from, socklen_t *fromlen);
1993__attribute__((weak))
1994int recvfrom(int s, void *buf, size_t len, int flags,
1995 struct sockaddr *from, socklen_t *fromlen)
1996{
sewardjd140e442002-05-29 01:21:19 +00001997 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00001998 wait_for_fd_to_be_readable_or_erring(s);
1999 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00002000 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
2001}
2002
2003
2004extern
sewardj796d6a22002-04-24 02:28:34 +00002005int __libc_sendto(int s, const void *msg, size_t len, int flags,
2006 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00002007__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00002008int sendto(int s, const void *msg, size_t len, int flags,
2009 const struct sockaddr *to, socklen_t tolen)
2010{
sewardjd140e442002-05-29 01:21:19 +00002011 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00002012 return __libc_sendto(s, msg, len, flags, to, tolen);
2013}
2014
sewardjbe32e452002-04-24 20:29:58 +00002015
sewardj369b1702002-04-24 13:28:15 +00002016extern
2017int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00002018__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00002019int system(const char* str)
2020{
sewardjd140e442002-05-29 01:21:19 +00002021 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00002022 return __libc_system(str);
2023}
2024
sewardjbe32e452002-04-24 20:29:58 +00002025
sewardjab0b1c32002-04-24 19:26:47 +00002026extern
2027pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00002028__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00002029pid_t wait(int *status)
2030{
sewardjd140e442002-05-29 01:21:19 +00002031 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00002032 return __libc_wait(status);
2033}
2034
sewardj45b4b372002-04-16 22:50:32 +00002035
sewardj67f1d582002-05-24 02:11:32 +00002036extern
2037int __libc_msync(const void *start, size_t length, int flags);
2038__attribute__((weak))
2039int msync(const void *start, size_t length, int flags)
2040{
sewardjd140e442002-05-29 01:21:19 +00002041 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00002042 return __libc_msync(start, length, flags);
2043}
2044
sewardj5905fae2002-04-26 13:25:00 +00002045
sewardj2cb00342002-06-28 01:46:26 +00002046/*--- fork and its helper ---*/
2047
2048static
2049void run_fork_handlers ( int what )
2050{
2051 ForkHandlerEntry entry;
2052 int n_h, n_handlers, i, res;
2053
2054 my_assert(what == 0 || what == 1 || what == 2);
2055
2056 /* Fetch old counter */
2057 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2058 VG_USERREQ__GET_FHSTACK_USED,
2059 0, 0, 0, 0);
2060 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2061
2062 /* Prepare handlers (what == 0) are called in opposite order of
2063 calls to pthread_atfork. Parent and child handlers are called
2064 in the same order as calls to pthread_atfork. */
2065 if (what == 0)
2066 n_h = n_handlers - 1;
2067 else
2068 n_h = 0;
2069
2070 for (i = 0; i < n_handlers; i++) {
2071 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2072 VG_USERREQ__GET_FHSTACK_ENTRY,
2073 n_h, &entry, 0, 0);
2074 my_assert(res == 0);
2075 switch (what) {
2076 case 0: if (entry.prepare) entry.prepare();
2077 n_h--; break;
2078 case 1: if (entry.parent) entry.parent();
2079 n_h++; break;
2080 case 2: if (entry.child) entry.child();
2081 n_h++; break;
2082 default: barf("run_fork_handlers: invalid what");
2083 }
2084 }
2085
2086 if (what != 0 /* prepare */) {
2087 /* Empty out the stack. */
2088 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2089 VG_USERREQ__SET_FHSTACK_USED,
2090 0, 0, 0, 0);
2091 my_assert(res == 0);
2092 }
2093}
2094
2095extern
2096pid_t __libc_fork(void);
2097pid_t __fork(void)
2098{
2099 pid_t pid;
2100 __my_pthread_testcancel();
2101 __pthread_mutex_lock(&pthread_atfork_lock);
2102
2103 run_fork_handlers(0 /* prepare */);
2104 pid = __libc_fork();
2105 if (pid == 0) {
2106 /* I am the child */
2107 run_fork_handlers(2 /* child */);
2108 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2109 } else {
2110 /* I am the parent */
2111 run_fork_handlers(1 /* parent */);
2112 __pthread_mutex_unlock(&pthread_atfork_lock);
2113 }
2114 return pid;
2115}
2116
2117
njn25e49d8e72002-09-23 09:36:25 +00002118pid_t __vfork(void)
2119{
2120 return __fork();
2121}
sewardj2cb00342002-06-28 01:46:26 +00002122
2123
sewardj3b13f0e2002-04-25 20:17:29 +00002124/* ---------------------------------------------------------------------
2125 Nonblocking implementations of select() and poll(). This stuff will
2126 surely rot your mind.
2127 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00002128
sewardj08a4c3f2002-04-13 03:45:44 +00002129/*--------------------------------------------------*/
2130
2131#include "vg_kerneliface.h"
2132
2133static
2134__inline__
2135int is_kerror ( int res )
2136{
2137 if (res >= -4095 && res <= -1)
2138 return 1;
2139 else
2140 return 0;
2141}
2142
2143
2144static
2145int my_do_syscall1 ( int syscallno, int arg1 )
2146{
2147 int __res;
2148 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2149 : "=a" (__res)
2150 : "0" (syscallno),
2151 "d" (arg1) );
2152 return __res;
2153}
2154
2155static
2156int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00002157 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00002158{
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 "c" (arg2) );
2165 return __res;
2166}
2167
2168static
sewardjf854f472002-04-21 12:19:41 +00002169int my_do_syscall3 ( int syscallno,
2170 int arg1, int arg2, int arg3 )
2171{
2172 int __res;
2173 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
2174 : "=a" (__res)
2175 : "0" (syscallno),
2176 "S" (arg1),
2177 "c" (arg2),
2178 "d" (arg3) );
2179 return __res;
2180}
2181
2182static
sewardj08a4c3f2002-04-13 03:45:44 +00002183int do_syscall_select( int n,
2184 vki_fd_set* readfds,
2185 vki_fd_set* writefds,
2186 vki_fd_set* exceptfds,
2187 struct vki_timeval * timeout )
2188{
2189 int res;
2190 int args[5];
2191 args[0] = n;
2192 args[1] = (int)readfds;
2193 args[2] = (int)writefds;
2194 args[3] = (int)exceptfds;
2195 args[4] = (int)timeout;
2196 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00002197 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00002198}
2199
2200
2201/* This is a wrapper round select(), which makes it thread-safe,
2202 meaning that only this thread will block, rather than the entire
2203 process. This wrapper in turn depends on nanosleep() not to block
2204 the entire process, but I think (hope? suspect?) that POSIX
2205 pthreads guarantees that to be the case.
2206
2207 Basic idea is: modify the timeout parameter to select so that it
2208 returns immediately. Poll like this until select returns non-zero,
2209 indicating something interesting happened, or until our time is up.
njn25e49d8e72002-09-23 09:36:25 +00002210 Space out the polls with nanosleeps of say 11 milliseconds, which
sewardj08a4c3f2002-04-13 03:45:44 +00002211 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00002212
2213 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00002214 * (checked via my_assert) types fd_set and vki_fd_set are identical.
2215 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00002216 * (unchecked) libc error numbers (EINTR etc) are the negation of the
2217 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00002218*/
sewardj08a4c3f2002-04-13 03:45:44 +00002219
sewardj5905fae2002-04-26 13:25:00 +00002220/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00002221int select ( int n,
2222 fd_set *rfds,
2223 fd_set *wfds,
2224 fd_set *xfds,
2225 struct timeval *timeout )
2226{
sewardj5f07b662002-04-23 16:52:51 +00002227 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00002228 int res;
2229 fd_set rfds_copy;
2230 fd_set wfds_copy;
2231 fd_set xfds_copy;
2232 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00002233 struct vki_timeval zero_timeout;
2234 struct vki_timespec nanosleep_interval;
2235
sewardjd140e442002-05-29 01:21:19 +00002236 __my_pthread_testcancel();
2237
sewardj5f07b662002-04-23 16:52:51 +00002238 /* gcc's complains about ms_end being used uninitialised -- classic
2239 case it can't understand, where ms_end is both defined and used
2240 only if timeout != NULL. Hence ... */
2241 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00002242
2243 /* We assume that the kernel and libc data layouts are identical
2244 for the following types. These asserts provide a crude
2245 check. */
2246 if (sizeof(fd_set) != sizeof(vki_fd_set)
2247 || sizeof(struct timeval) != sizeof(struct vki_timeval))
2248 barf("valgrind's hacky non-blocking select(): data sizes error");
2249
sewardj5f07b662002-04-23 16:52:51 +00002250 /* Detect the current time and simultaneously find out if we are
2251 running on Valgrind. */
2252 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2253 VG_USERREQ__READ_MILLISECOND_TIMER,
2254 0, 0, 0, 0);
2255
2256 /* If a zero timeout specified, this call is harmless. Also go
2257 this route if we're not running on Valgrind, for whatever
2258 reason. */
2259 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
2260 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00002261 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00002262 (vki_fd_set*)wfds,
2263 (vki_fd_set*)xfds,
2264 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00002265 if (is_kerror(res)) {
2266 * (__errno_location()) = -res;
2267 return -1;
2268 } else {
2269 return res;
2270 }
2271 }
sewardj08a4c3f2002-04-13 03:45:44 +00002272
sewardj5f07b662002-04-23 16:52:51 +00002273 /* If a timeout was specified, set ms_end to be the end millisecond
2274 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00002275 if (timeout) {
2276 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00002277 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00002278 ms_end = ms_now;
2279 ms_end += (timeout->tv_usec / 1000);
2280 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00002281 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00002282 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00002283 }
2284
2285 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
2286
2287 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00002288 NULL, in which case ms_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002289
sewardj08a4c3f2002-04-13 03:45:44 +00002290 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002291
2292 /* First, do a return-immediately select(). */
sewardj08a4c3f2002-04-13 03:45:44 +00002293
2294 /* These could be trashed each time round the loop, so restore
2295 them each time. */
2296 if (rfds) rfds_copy = *rfds;
2297 if (wfds) wfds_copy = *wfds;
2298 if (xfds) xfds_copy = *xfds;
2299
2300 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
2301
2302 res = do_syscall_select( n,
2303 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
2304 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
2305 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
2306 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00002307 if (is_kerror(res)) {
2308 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00002309 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00002310 * (__errno_location()) = -res;
2311 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00002312 }
2313 if (res > 0) {
2314 /* one or more fds is ready. Copy out resulting sets and
2315 return. */
2316 if (rfds) *rfds = rfds_copy;
2317 if (wfds) *wfds = wfds_copy;
2318 if (xfds) *xfds = xfds_copy;
2319 return res;
2320 }
sewardj05bb2c92002-06-26 00:47:17 +00002321
2322 /* Nothing interesting happened, so we go to sleep for a
2323 while. */
2324
sewardj08a4c3f2002-04-13 03:45:44 +00002325 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
2326 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00002327 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002328 nanosleep_interval.tv_nsec = 11 * 1000 * 1000; /* 11 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00002329 /* It's critical here that valgrind's nanosleep implementation
2330 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00002331 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00002332 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00002333 if (res == -VKI_EINTR) {
2334 /* The nanosleep was interrupted by a signal. So we do the
2335 same. */
2336 * (__errno_location()) = EINTR;
2337 return -1;
2338 }
sewardj05bb2c92002-06-26 00:47:17 +00002339
2340 /* Sleeping finished. If a finite timeout, check to see if it
2341 has expired yet. */
2342 if (timeout) {
2343 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2344 VG_USERREQ__READ_MILLISECOND_TIMER,
2345 0, 0, 0, 0);
2346 my_assert(ms_now != 0xFFFFFFFF);
2347 if (ms_now >= ms_end) {
2348 /* timeout; nothing interesting happened. */
2349 if (rfds) FD_ZERO(rfds);
2350 if (wfds) FD_ZERO(wfds);
2351 if (xfds) FD_ZERO(xfds);
2352 return 0;
2353 }
2354 }
2355
sewardjf854f472002-04-21 12:19:41 +00002356 }
2357}
2358
2359
2360
2361
2362#include <sys/poll.h>
2363
sewardj3e909ce2002-06-03 13:27:15 +00002364#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00002365typedef unsigned long int nfds_t;
2366#endif
2367
sewardj705d3cb2002-05-23 13:13:12 +00002368
sewardj5905fae2002-04-26 13:25:00 +00002369/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00002370int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2371{
sewardj5f07b662002-04-23 16:52:51 +00002372 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00002373 int res, i;
sewardjf854f472002-04-21 12:19:41 +00002374 struct vki_timespec nanosleep_interval;
2375
sewardjd140e442002-05-29 01:21:19 +00002376 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00002377 ensure_valgrind("poll");
2378
sewardj5f07b662002-04-23 16:52:51 +00002379 /* Detect the current time and simultaneously find out if we are
2380 running on Valgrind. */
2381 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2382 VG_USERREQ__READ_MILLISECOND_TIMER,
2383 0, 0, 0, 0);
2384
sewardjf854f472002-04-21 12:19:41 +00002385 if (/* CHECK SIZES FOR struct pollfd */
2386 sizeof(struct timeval) != sizeof(struct vki_timeval))
2387 barf("valgrind's hacky non-blocking poll(): data sizes error");
2388
sewardj5f07b662002-04-23 16:52:51 +00002389 /* dummy initialisation to keep gcc -Wall happy */
2390 ms_end = 0;
2391
2392 /* If a zero timeout specified, this call is harmless. Also do
2393 this if not running on Valgrind. */
2394 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00002395 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
2396 if (is_kerror(res)) {
2397 * (__errno_location()) = -res;
2398 return -1;
2399 } else {
2400 return res;
2401 }
2402 }
2403
sewardj5f07b662002-04-23 16:52:51 +00002404 /* If a timeout was specified, set ms_end to be the end wallclock
2405 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002406 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002407 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002408 }
2409
2410 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2411
2412 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2413 in which case t_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002414
sewardj2d94c112002-06-03 01:25:54 +00002415 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002416
sewardjf854f472002-04-21 12:19:41 +00002417 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002418
2419 /* Do a return-immediately poll. */
2420
2421 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2422 if (is_kerror(res)) {
2423 /* Some kind of error. Set errno and return. */
2424 * (__errno_location()) = -res;
2425 return -1;
2426 }
2427 if (res > 0) {
2428 /* One or more fds is ready. Return now. */
2429 return res;
2430 }
2431
2432 /* Nothing interesting happened, so we go to sleep for a
2433 while. */
2434
2435 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2436 /* nanosleep and go round again */
2437 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002438 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
sewardj05bb2c92002-06-26 00:47:17 +00002439 /* It's critical here that valgrind's nanosleep implementation
2440 is nonblocking. */
2441 (void)my_do_syscall2(__NR_nanosleep,
2442 (int)(&nanosleep_interval), (int)NULL);
2443
2444 /* Sleeping finished. If a finite timeout, check to see if it
2445 has expired yet. */
sewardjf854f472002-04-21 12:19:41 +00002446 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002447 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2448 VG_USERREQ__READ_MILLISECOND_TIMER,
2449 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002450 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002451 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002452 /* timeout; nothing interesting happened. */
2453 for (i = 0; i < __nfds; i++)
2454 __fds[i].revents = 0;
2455 return 0;
2456 }
2457 }
2458
sewardj08a4c3f2002-04-13 03:45:44 +00002459 }
2460}
sewardj3b13f0e2002-04-25 20:17:29 +00002461
2462
sewardj705d3cb2002-05-23 13:13:12 +00002463/* Helper function used to make accept() non-blocking. Idea is to use
2464 the above nonblocking poll() to make this thread ONLY wait for the
2465 specified fd to become ready, and then return. */
sewardjd1c1cf22002-06-26 00:13:36 +00002466
2467/* Sigh -- a hack. We're not supposed to include this file directly;
2468 should do it via /usr/include/fcntl.h, but that introduces a
2469 varargs prototype for fcntl itself, which we can't mimic. */
2470#define _FCNTL_H
2471#include <bits/fcntl.h>
2472
sewardj705d3cb2002-05-23 13:13:12 +00002473static void wait_for_fd_to_be_readable_or_erring ( int fd )
2474{
2475 struct pollfd pfd;
sewardjd1c1cf22002-06-26 00:13:36 +00002476 int res;
2477
sewardj6e6cbaa2002-05-24 02:12:52 +00002478 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardjd1c1cf22002-06-26 00:13:36 +00002479
2480 /* First check to see if the fd is nonblocking, and/or invalid. In
2481 either case return immediately. */
2482 res = __libc_fcntl(fd, F_GETFL, 0);
2483 if (res == -1) return; /* fd is invalid somehow */
2484 if (res & O_NONBLOCK) return; /* fd is nonblocking */
2485
2486 /* Ok, we'd better wait with poll. */
sewardj705d3cb2002-05-23 13:13:12 +00002487 pfd.fd = fd;
2488 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2489 /* ... but not POLLOUT, you may notice. */
2490 pfd.revents = 0;
2491 (void)poll(&pfd, 1, -1 /* forever */);
2492}
2493
2494
sewardj3b13f0e2002-04-25 20:17:29 +00002495/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002496 Hacky implementation of semaphores.
2497 ------------------------------------------------------------------ */
2498
2499#include <semaphore.h>
2500
2501/* This is a terrible way to do the remapping. Plan is to import an
2502 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002503
2504typedef
2505 struct {
2506 pthread_mutex_t se_mx;
2507 pthread_cond_t se_cv;
2508 int count;
2509 }
2510 vg_sem_t;
2511
2512static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2513
2514static int se_remap_used = 0;
2515static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2516static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2517
2518static vg_sem_t* se_remap ( sem_t* orig )
2519{
2520 int res, i;
2521 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002522 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002523
2524 for (i = 0; i < se_remap_used; i++) {
2525 if (se_remap_orig[i] == orig)
2526 break;
2527 }
2528 if (i == se_remap_used) {
2529 if (se_remap_used == VG_N_SEMAPHORES) {
2530 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002531 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002532 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002533 }
2534 se_remap_used++;
2535 se_remap_orig[i] = orig;
2536 /* printf("allocated semaphore %d\n", i); */
2537 }
2538 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002539 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002540 return &se_remap_new[i];
2541}
2542
2543
2544int sem_init(sem_t *sem, int pshared, unsigned int value)
2545{
2546 int res;
2547 vg_sem_t* vg_sem;
2548 ensure_valgrind("sem_init");
2549 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002550 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002551 errno = ENOSYS;
2552 return -1;
2553 }
2554 vg_sem = se_remap(sem);
2555 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002556 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002557 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002558 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002559 vg_sem->count = value;
2560 return 0;
2561}
2562
2563
2564int sem_wait ( sem_t* sem )
2565{
2566 int res;
2567 vg_sem_t* vg_sem;
2568 ensure_valgrind("sem_wait");
2569 vg_sem = se_remap(sem);
2570 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002571 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002572 while (vg_sem->count == 0) {
2573 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002574 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002575 }
2576 vg_sem->count--;
2577 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002578 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002579 return 0;
2580}
2581
2582int sem_post ( sem_t* sem )
2583{
2584 int res;
2585 vg_sem_t* vg_sem;
2586 ensure_valgrind("sem_post");
2587 vg_sem = se_remap(sem);
2588 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002589 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002590 if (vg_sem->count == 0) {
2591 vg_sem->count++;
2592 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002593 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002594 } else {
2595 vg_sem->count++;
2596 }
2597 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002598 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002599 return 0;
2600}
2601
2602
2603int sem_trywait ( sem_t* sem )
2604{
2605 int ret, res;
2606 vg_sem_t* vg_sem;
2607 ensure_valgrind("sem_trywait");
2608 vg_sem = se_remap(sem);
2609 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002610 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002611 if (vg_sem->count > 0) {
2612 vg_sem->count--;
2613 ret = 0;
2614 } else {
2615 ret = -1;
2616 errno = EAGAIN;
2617 }
2618 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002619 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002620 return ret;
2621}
2622
2623
2624int sem_getvalue(sem_t* sem, int * sval)
2625{
2626 vg_sem_t* vg_sem;
2627 ensure_valgrind("sem_trywait");
2628 vg_sem = se_remap(sem);
2629 *sval = vg_sem->count;
2630 return 0;
2631}
2632
2633
2634int sem_destroy(sem_t * sem)
2635{
2636 kludged("sem_destroy");
2637 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2638 return 0;
2639}
2640
sewardj9ad92d92002-10-16 19:45:06 +00002641
2642int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2643{
2644 int res;
2645 vg_sem_t* vg_sem;
2646 ensure_valgrind("sem_timedwait");
2647 vg_sem = se_remap(sem);
2648 res = __pthread_mutex_lock(&vg_sem->se_mx);
2649 my_assert(res == 0);
2650 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
2651 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
2652 }
2653 if ( vg_sem->count > 0 ) {
2654 vg_sem->count--;
2655 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2656 my_assert(res == 0 );
2657 return 0;
2658 } else {
2659 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2660 my_assert(res == 0 );
2661 *(__errno_location()) = ETIMEDOUT;
2662 return -1;
2663 }
2664}
2665
sewardj8f253ff2002-05-19 00:13:34 +00002666
2667/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002668 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002669 ------------------------------------------------------------------ */
2670
sewardj2d8b3f02002-06-01 14:14:19 +00002671typedef
2672 struct {
2673 int initted; /* != 0 --> in use; sanity check only */
2674 int prefer_w; /* != 0 --> prefer writer */
2675 int nwait_r; /* # of waiting readers */
2676 int nwait_w; /* # of waiting writers */
2677 pthread_cond_t cv_r; /* for signalling readers */
2678 pthread_cond_t cv_w; /* for signalling writers */
2679 pthread_mutex_t mx;
2680 int status;
2681 /* allowed range for status: >= -1. -1 means 1 writer currently
2682 active, >= 0 means N readers currently active. */
2683 }
2684 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002685
2686
2687static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2688
2689static int rw_remap_used = 0;
2690static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2691static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2692
sewardj2d8b3f02002-06-01 14:14:19 +00002693
2694static
2695void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2696{
2697 int res = 0;
2698 vg_rwl->initted = 1;
2699 vg_rwl->prefer_w = 1;
2700 vg_rwl->nwait_r = 0;
2701 vg_rwl->nwait_w = 0;
2702 vg_rwl->status = 0;
2703 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2704 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2705 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002706 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002707}
2708
2709
sewardja1ac5cb2002-05-27 13:00:05 +00002710/* Take the address of a LinuxThreads rwlock_t and return the shadow
2711 address of our version. Further, if the LinuxThreads version
2712 appears to have been statically initialised, do the same to the one
2713 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2714 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2715 uninitialised and non-zero meaning initialised.
2716*/
2717static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2718{
2719 int res, i;
2720 vg_rwlock_t* vg_rwl;
2721 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002722 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002723
2724 for (i = 0; i < rw_remap_used; i++) {
2725 if (rw_remap_orig[i] == orig)
2726 break;
2727 }
2728 if (i == rw_remap_used) {
2729 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002730 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002731 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002732 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2733 }
2734 rw_remap_used++;
2735 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002736 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002737 if (0) printf("allocated rwlock %d\n", i);
2738 }
2739 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002740 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002741 vg_rwl = &rw_remap_new[i];
2742
sewardj2d8b3f02002-06-01 14:14:19 +00002743 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002744 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002745 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002746 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002747 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002748 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002749 }
2750
2751 return vg_rwl;
2752}
2753
2754
sewardja1ac5cb2002-05-27 13:00:05 +00002755int pthread_rwlock_init ( pthread_rwlock_t* orig,
2756 const pthread_rwlockattr_t* attr )
2757{
sewardja1ac5cb2002-05-27 13:00:05 +00002758 vg_rwlock_t* rwl;
2759 if (0) printf ("pthread_rwlock_init\n");
2760 /* Force the remapper to initialise the shadow. */
2761 orig->__rw_readers = 0;
2762 /* Install the lock preference; the remapper needs to know it. */
2763 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2764 if (attr)
2765 orig->__rw_kind = attr->__lockkind;
2766 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002767 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002768}
2769
sewardj2d8b3f02002-06-01 14:14:19 +00002770
2771static
2772void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002773{
sewardj2d8b3f02002-06-01 14:14:19 +00002774 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2775 rwl->nwait_r--;
2776 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002777}
2778
sewardj2d8b3f02002-06-01 14:14:19 +00002779
sewardja1ac5cb2002-05-27 13:00:05 +00002780int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2781{
2782 int res;
2783 vg_rwlock_t* rwl;
2784 if (0) printf ("pthread_rwlock_rdlock\n");
2785 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002786 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002787 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002788 if (!rwl->initted) {
2789 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002790 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002791 return EINVAL;
2792 }
2793 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002794 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002795 rwl->nwait_r++;
2796 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2797 while (1) {
2798 if (rwl->status == 0) break;
2799 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002800 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002801 }
2802 pthread_cleanup_pop(0);
2803 rwl->nwait_r--;
2804 }
sewardj2d94c112002-06-03 01:25:54 +00002805 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002806 rwl->status++;
2807 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002808 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002809 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002810}
2811
sewardj2d8b3f02002-06-01 14:14:19 +00002812
sewardja1ac5cb2002-05-27 13:00:05 +00002813int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2814{
2815 int res;
2816 vg_rwlock_t* rwl;
2817 if (0) printf ("pthread_rwlock_tryrdlock\n");
2818 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002819 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002820 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002821 if (!rwl->initted) {
2822 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002823 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002824 return EINVAL;
2825 }
2826 if (rwl->status == -1) {
2827 /* Writer active; we have to give up. */
2828 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002829 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002830 return EBUSY;
2831 }
2832 /* Success */
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
2841static
2842void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2843{
2844 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2845 rwl->nwait_w--;
2846 pthread_mutex_unlock (&rwl->mx);
2847}
2848
2849
sewardja1ac5cb2002-05-27 13:00:05 +00002850int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2851{
2852 int res;
2853 vg_rwlock_t* rwl;
2854 if (0) printf ("pthread_rwlock_wrlock\n");
2855 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002856 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002857 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002858 if (!rwl->initted) {
2859 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002860 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002861 return EINVAL;
2862 }
2863 if (rwl->status != 0) {
2864 rwl->nwait_w++;
2865 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2866 while (1) {
2867 if (rwl->status == 0) break;
2868 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002869 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002870 }
2871 pthread_cleanup_pop(0);
2872 rwl->nwait_w--;
2873 }
sewardj2d94c112002-06-03 01:25:54 +00002874 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002875 rwl->status = -1;
2876 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002877 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002878 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002879}
2880
sewardj2d8b3f02002-06-01 14:14:19 +00002881
sewardja1ac5cb2002-05-27 13:00:05 +00002882int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2883{
2884 int res;
2885 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002886 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002887 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002888 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002889 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002890 if (!rwl->initted) {
2891 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002892 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002893 return EINVAL;
2894 }
2895 if (rwl->status != 0) {
2896 /* Reader(s) or a writer active; we have to give up. */
2897 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002898 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002899 return EBUSY;
2900 }
2901 /* Success */
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_unlock ( pthread_rwlock_t* orig )
2911{
2912 int res;
2913 vg_rwlock_t* rwl;
2914 if (0) printf ("pthread_rwlock_unlock\n");
2915 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002916 rwl = rw_remap ( orig );
2917 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002918 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002919 if (!rwl->initted) {
2920 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002921 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002922 return EINVAL;
2923 }
2924 if (rwl->status == 0) {
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 EPERM;
2928 }
sewardj2d94c112002-06-03 01:25:54 +00002929 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002930 if (rwl->status == -1) {
2931 rwl->status = 0;
2932 } else {
sewardj2d94c112002-06-03 01:25:54 +00002933 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002934 rwl->status--;
2935 }
2936
sewardj2d94c112002-06-03 01:25:54 +00002937 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002938
2939 if (rwl->prefer_w) {
2940
2941 /* Favour waiting writers, if any. */
2942 if (rwl->nwait_w > 0) {
2943 /* Writer(s) are waiting. */
2944 if (rwl->status == 0) {
2945 /* We can let a writer in. */
2946 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002947 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002948 } else {
2949 /* There are still readers active. Do nothing; eventually
2950 they will disappear, at which point a writer will be
2951 admitted. */
2952 }
2953 }
2954 else
2955 /* No waiting writers. */
2956 if (rwl->nwait_r > 0) {
2957 /* Let in a waiting reader. */
2958 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002959 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002960 }
2961
2962 } else {
2963
2964 /* Favour waiting readers, if any. */
2965 if (rwl->nwait_r > 0) {
2966 /* Reader(s) are waiting; let one in. */
2967 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002968 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002969 }
2970 else
2971 /* No waiting readers. */
2972 if (rwl->nwait_w > 0 && rwl->status == 0) {
2973 /* We have waiting writers and no active readers; let a
2974 writer in. */
2975 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002976 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002977 }
2978 }
2979
2980 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002981 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002982 return 0;
2983}
2984
2985
2986int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2987{
2988 int res;
2989 vg_rwlock_t* rwl;
2990 if (0) printf ("pthread_rwlock_destroy\n");
2991 rwl = rw_remap ( orig );
2992 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002993 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002994 if (!rwl->initted) {
2995 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002996 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002997 return EINVAL;
2998 }
2999 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
3000 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003001 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003002 return EBUSY;
3003 }
3004 rwl->initted = 0;
3005 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003006 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003007 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003008}
3009
3010
sewardj47e4e312002-06-18 09:24:34 +00003011/* Copied directly from LinuxThreads. */
3012int
3013pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
3014{
3015 attr->__lockkind = 0;
3016 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
3017
3018 return 0;
3019}
3020
sewardjfe18eb82002-07-13 12:58:44 +00003021/* Copied directly from LinuxThreads. */
3022int
3023pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
3024{
3025 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
3026 return EINVAL;
3027
3028 /* For now it is not possible to shared a conditional variable. */
3029 if (pshared != PTHREAD_PROCESS_PRIVATE)
3030 return ENOSYS;
3031
3032 attr->__pshared = pshared;
3033
3034 return 0;
3035}
3036
sewardj47e4e312002-06-18 09:24:34 +00003037
sewardja1ac5cb2002-05-27 13:00:05 +00003038/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00003039 B'stard.
3040 ------------------------------------------------------------------ */
3041
3042# define strong_alias(name, aliasname) \
3043 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
3044
sewardj5905fae2002-04-26 13:25:00 +00003045# define weak_alias(name, aliasname) \
3046 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00003047
sewardj5905fae2002-04-26 13:25:00 +00003048strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
3049strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
3050strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
3051strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
3052 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
3053strong_alias(__pthread_mutex_init, pthread_mutex_init)
3054strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
3055strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
3056strong_alias(__pthread_once, pthread_once)
3057strong_alias(__pthread_atfork, pthread_atfork)
3058strong_alias(__pthread_key_create, pthread_key_create)
3059strong_alias(__pthread_getspecific, pthread_getspecific)
3060strong_alias(__pthread_setspecific, pthread_setspecific)
3061
sewardjd529a442002-05-04 19:49:21 +00003062#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00003063strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00003064#endif
3065
sewardj5905fae2002-04-26 13:25:00 +00003066strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00003067strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00003068strong_alias(lseek, __lseek)
3069strong_alias(open, __open)
3070strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00003071strong_alias(read, __read)
3072strong_alias(wait, __wait)
3073strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00003074strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00003075strong_alias(send, __send)
sewardj3fd559e2002-10-20 16:24:04 +00003076strong_alias(poll, __poll)
3077strong_alias(select, __select)
sewardj5905fae2002-04-26 13:25:00 +00003078
sewardj726c4122002-05-16 23:39:10 +00003079weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00003080weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00003081weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00003082weak_alias(__vfork, vfork)
sewardj7f6456d2002-05-21 00:51:21 +00003083
sewardjf0b06452002-06-04 08:38:04 +00003084weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00003085
3086/*--------------------------------------------------*/
3087
sewardj5905fae2002-04-26 13:25:00 +00003088weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00003089weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00003090weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00003091
sewardja1ac5cb2002-05-27 13:00:05 +00003092weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
3093weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
3094weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
3095weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
3096
sewardj060b04f2002-04-26 21:01:13 +00003097
sewardj3b13f0e2002-04-25 20:17:29 +00003098/* I've no idea what these are, but they get called quite a lot.
3099 Anybody know? */
3100
3101#undef _IO_flockfile
3102void _IO_flockfile ( _IO_FILE * file )
3103{
sewardj853f55d2002-04-26 00:27:53 +00003104 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003105}
sewardj5905fae2002-04-26 13:25:00 +00003106weak_alias(_IO_flockfile, flockfile);
3107
sewardj3b13f0e2002-04-25 20:17:29 +00003108
3109#undef _IO_funlockfile
3110void _IO_funlockfile ( _IO_FILE * file )
3111{
sewardj853f55d2002-04-26 00:27:53 +00003112 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003113}
sewardj5905fae2002-04-26 13:25:00 +00003114weak_alias(_IO_funlockfile, funlockfile);
3115
sewardj3b13f0e2002-04-25 20:17:29 +00003116
sewardjd4f2c712002-04-30 10:20:10 +00003117/* This doesn't seem to be needed to simulate libpthread.so's external
3118 interface, but many people complain about its absence. */
3119
3120strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
3121weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00003122
3123
3124/*--------------------------------------------------------------------*/
3125/*--- end vg_libpthread.c ---*/
3126/*--------------------------------------------------------------------*/