blob: 42e289f3635f0c61325c9b8c178015baf23ccffd [file] [log] [blame]
sewardje663cb92002-04-12 10:26:32 +00001
sewardj439d45e2002-05-03 20:43:10 +00002/*--------------------------------------------------------------------*/
3/*--- A replacement for the standard libpthread.so. ---*/
4/*--- vg_libpthread.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
njnc9539842002-10-02 13:26:35 +00008 This file is part of Valgrind, an extensible x86 protected-mode
9 emulator for monitoring program execution on x86-Unixes.
sewardj439d45e2002-05-03 20:43:10 +000010
11 Copyright (C) 2000-2002 Julian Seward
12 jseward@acm.org
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
njn25e49d8e72002-09-23 09:36:25 +000029 The GNU General Public License is contained in the file COPYING.
sewardj439d45e2002-05-03 20:43:10 +000030*/
31
32/* ALL THIS CODE RUNS ON THE SIMULATED CPU.
33
34 This is a replacement for the standard libpthread.so. It is loaded
sewardje663cb92002-04-12 10:26:32 +000035 as part of the client's image (if required) and directs pthread
36 calls through to Valgrind's request mechanism.
37
38 A couple of caveats.
39
40 1. Since it's a binary-compatible replacement for an existing library,
41 we must take care to used exactly the same data layouts, etc, as
42 the standard pthread.so does.
43
44 2. Since this runs as part of the client, there are no specific
45 restrictions on what headers etc we can include, so long as
46 this libpthread.so does not end up having dependencies on .so's
47 which the real one doesn't.
48
49 Later ... it appears we cannot call file-related stuff in libc here,
50 perhaps fair enough. Be careful what you call from here. Even exit()
51 doesn't work (gives infinite recursion and then stack overflow); hence
52 myexit(). Also fprintf doesn't seem safe.
53*/
54
55#include "valgrind.h" /* For the request-passing mechanism */
56#include "vg_include.h" /* For the VG_USERREQ__* constants */
57
sewardja1ac5cb2002-05-27 13:00:05 +000058#define __USE_UNIX98
59#include <sys/types.h>
60#include <pthread.h>
61#undef __USE_UNIX98
62
sewardje663cb92002-04-12 10:26:32 +000063#include <unistd.h>
64#include <string.h>
sewardj2a1dcce2002-04-22 12:45:25 +000065#ifdef GLIBC_2_1
66#include <sys/time.h>
67#endif
sewardje663cb92002-04-12 10:26:32 +000068
sewardj2d94c112002-06-03 01:25:54 +000069#include <stdio.h>
70
sewardj705d3cb2002-05-23 13:13:12 +000071
72/* ---------------------------------------------------------------------
73 Forwardses.
74 ------------------------------------------------------------------ */
75
76static void wait_for_fd_to_be_readable_or_erring ( int fd );
77
sewardj9a2224b2002-06-19 10:17:40 +000078static
sewardj08c7f012002-10-07 23:56:55 +000079int my_do_syscall1 ( int syscallno, int arg1 );
80
81static
sewardj9a2224b2002-06-19 10:17:40 +000082int my_do_syscall2 ( int syscallno,
83 int arg1, int arg2 );
84
sewardj08c7f012002-10-07 23:56:55 +000085static
86int my_do_syscall3 ( int syscallno,
87 int arg1, int arg2, int arg3 );
88
89
90#ifdef GLIBC_2_3
91 /* kludge by JRS (not from glibc) ... */
92 typedef void* __locale_t;
93
94 /* Copied from locale/locale.h in glibc-2.2.93 sources */
95 /* This value can be passed to `uselocale' and may be returned by
96 it. Passing this value to any other function has undefined
97 behavior. */
98# define LC_GLOBAL_LOCALE ((__locale_t) -1L)
99 extern __locale_t __uselocale ( __locale_t );
100#endif
101
sewardj00a66b12002-10-12 16:42:35 +0000102static
103void init_libc_tsd_keys ( void );
104
sewardj705d3cb2002-05-23 13:13:12 +0000105
sewardje663cb92002-04-12 10:26:32 +0000106/* ---------------------------------------------------------------------
107 Helpers. We have to be pretty self-sufficient.
108 ------------------------------------------------------------------ */
109
sewardj436e0582002-04-26 14:31:40 +0000110/* Number of times any given error message is printed. */
111#define N_MOANS 3
112
sewardj45b4b372002-04-16 22:50:32 +0000113/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
114 Returns 0 (none) if not running on Valgrind. */
115static
116int get_pt_trace_level ( void )
117{
118 int res;
119 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
120 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
121 0, 0, 0, 0);
122 return res;
123}
124
sewardje663cb92002-04-12 10:26:32 +0000125static
sewardj2d94c112002-06-03 01:25:54 +0000126void my_exit ( int arg )
sewardje663cb92002-04-12 10:26:32 +0000127{
sewardj08c7f012002-10-07 23:56:55 +0000128 my_do_syscall1(__NR_exit, arg);
129 /*NOTREACHED*/
sewardje663cb92002-04-12 10:26:32 +0000130}
131
sewardj08c7f012002-10-07 23:56:55 +0000132static
133void my_write ( int fd, const void *buf, int count )
134{
135 my_do_syscall3(__NR_write, fd, (int)buf, count );
136}
sewardje663cb92002-04-12 10:26:32 +0000137
sewardj68b2dd92002-05-10 21:03:56 +0000138/* We need this guy -- it's in valgrind.so. */
139extern void VG_(startup) ( void );
140
141
142/* Just start up Valgrind if it's not already going. VG_(startup)()
143 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000144static __inline__
sewardje663cb92002-04-12 10:26:32 +0000145void ensure_valgrind ( char* caller )
146{
sewardj68b2dd92002-05-10 21:03:56 +0000147 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000148}
149
sewardjbea1caa2002-05-10 23:20:58 +0000150/* While we're at it ... hook our own startup function into this
151 game. */
152__asm__ (
153 ".section .init\n"
154 "\tcall vgPlain_startup"
155);
156
sewardje663cb92002-04-12 10:26:32 +0000157
158static
sewardj3b5d8862002-04-20 13:53:23 +0000159__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +0000160void barf ( char* str )
161{
162 char buf[100];
163 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000164 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000165 strcat(buf, str);
166 strcat(buf, "\n\n");
sewardj08c7f012002-10-07 23:56:55 +0000167 my_write(2, buf, strlen(buf));
sewardj2d94c112002-06-03 01:25:54 +0000168 my_exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000169 /* We have to persuade gcc into believing this doesn't return. */
170 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000171}
172
173
sewardj2a3d28c2002-04-14 13:27:00 +0000174static void ignored ( char* msg )
175{
sewardj436e0582002-04-26 14:31:40 +0000176 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000177 char* ig = "valgrind's libpthread.so: IGNORED call to: ";
sewardj08c7f012002-10-07 23:56:55 +0000178 my_write(2, ig, strlen(ig));
179 my_write(2, msg, strlen(msg));
sewardj45b4b372002-04-16 22:50:32 +0000180 ig = "\n";
sewardj08c7f012002-10-07 23:56:55 +0000181 my_write(2, ig, strlen(ig));
sewardj45b4b372002-04-16 22:50:32 +0000182 }
sewardj2a3d28c2002-04-14 13:27:00 +0000183}
184
sewardj30671ff2002-04-21 00:13:57 +0000185static void kludged ( char* msg )
186{
sewardj436e0582002-04-26 14:31:40 +0000187 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000188 char* ig = "valgrind's libpthread.so: KLUDGED call to: ";
sewardj08c7f012002-10-07 23:56:55 +0000189 my_write(2, ig, strlen(ig));
190 my_write(2, msg, strlen(msg));
sewardj439d45e2002-05-03 20:43:10 +0000191 ig = "\n";
sewardj08c7f012002-10-07 23:56:55 +0000192 my_write(2, ig, strlen(ig));
sewardj439d45e2002-05-03 20:43:10 +0000193 }
194}
195
196static void not_inside ( char* msg )
197{
sewardj68b2dd92002-05-10 21:03:56 +0000198 VG_(startup)();
sewardj30671ff2002-04-21 00:13:57 +0000199}
200
sewardjccef2e62002-05-29 19:26:32 +0000201__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000202void vgPlain_unimp ( char* what )
203{
sewardj439d45e2002-05-03 20:43:10 +0000204 char* ig = "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ";
sewardj08c7f012002-10-07 23:56:55 +0000205 my_write(2, ig, strlen(ig));
206 my_write(2, what, strlen(what));
sewardj3b13f0e2002-04-25 20:17:29 +0000207 ig = "\n";
sewardj08c7f012002-10-07 23:56:55 +0000208 my_write(2, ig, strlen(ig));
sewardj3b13f0e2002-04-25 20:17:29 +0000209 barf("Please report this bug to me at: jseward@acm.org");
210}
211
sewardje663cb92002-04-12 10:26:32 +0000212
sewardj457cc472002-06-03 23:13:47 +0000213static
sewardj2d94c112002-06-03 01:25:54 +0000214void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
215{
216 static Bool entered = False;
217 if (entered)
218 my_exit(2);
219 entered = True;
220 fprintf(stderr, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
221 "valgrind", file, line, fn, expr );
222 fprintf(stderr, "Please report this bug to me at: %s\n\n",
223 VG_EMAIL_ADDR);
224 my_exit(1);
225}
226
227#define MY__STRING(__str) #__str
228
229#define my_assert(expr) \
230 ((void) ((expr) ? 0 : \
231 (my_assert_fail (MY__STRING(expr), \
232 __FILE__, __LINE__, \
233 __PRETTY_FUNCTION__), 0)))
234
sewardj00a66b12002-10-12 16:42:35 +0000235static
236void my_free ( void* ptr )
237{
238 int res;
239 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
240 VG_USERREQ__FREE, ptr, 0, 0, 0);
241 my_assert(res == 0);
242}
243
244
245static
246void* my_malloc ( int nbytes )
247{
248 void* res;
249 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
250 VG_USERREQ__MALLOC, nbytes, 0, 0, 0);
251 my_assert(res != (void*)0);
252 return res;
253}
254
255
sewardj2d94c112002-06-03 01:25:54 +0000256
sewardje663cb92002-04-12 10:26:32 +0000257/* ---------------------------------------------------------------------
258 Pass pthread_ calls to Valgrind's request mechanism.
259 ------------------------------------------------------------------ */
260
sewardjf8f819e2002-04-17 23:21:37 +0000261#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000262#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000263
sewardja1ac5cb2002-05-27 13:00:05 +0000264
sewardjf8f819e2002-04-17 23:21:37 +0000265/* ---------------------------------------------------
sewardj4dced352002-06-04 22:54:20 +0000266 Ummm ..
267 ------------------------------------------------ */
268
269static
270void pthread_error ( const char* msg )
271{
272 int res;
273 VALGRIND_MAGIC_SEQUENCE(res, 0,
274 VG_USERREQ__PTHREAD_ERROR,
275 msg, 0, 0, 0);
276}
277
278
279/* ---------------------------------------------------
sewardj00a66b12002-10-12 16:42:35 +0000280 Here so it can be inlined without complaint.
281 ------------------------------------------------ */
282
283__inline__
284pthread_t pthread_self(void)
285{
286 int tid;
287 ensure_valgrind("pthread_self");
288 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
289 VG_USERREQ__PTHREAD_GET_THREADID,
290 0, 0, 0, 0);
291 if (tid < 1 || tid >= VG_N_THREADS)
292 barf("pthread_self: invalid ThreadId");
293 return tid;
294}
295
296
297/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000298 THREAD ATTRIBUTES
299 ------------------------------------------------ */
300
sewardj6af4b5d2002-04-16 04:40:49 +0000301int pthread_attr_init(pthread_attr_t *attr)
302{
sewardj7989d0c2002-05-28 11:00:01 +0000303 /* Just initialise the fields which we might look at. */
304 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj111b14c2002-10-20 16:22:57 +0000305 /* Linuxthreads sets this field to the value __getpagesize(), so I
306 guess the following is OK. */
307 attr->__guardsize = VKI_BYTES_PER_PAGE; return 0;
sewardj6af4b5d2002-04-16 04:40:49 +0000308}
309
310int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
311{
sewardj7989d0c2002-05-28 11:00:01 +0000312 if (detachstate != PTHREAD_CREATE_JOINABLE
sewardj4dced352002-06-04 22:54:20 +0000313 && detachstate != PTHREAD_CREATE_DETACHED) {
314 pthread_error("pthread_attr_setdetachstate: "
315 "detachstate is invalid");
sewardj7989d0c2002-05-28 11:00:01 +0000316 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000317 }
sewardj7989d0c2002-05-28 11:00:01 +0000318 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000319 return 0;
320}
321
njn25e49d8e72002-09-23 09:36:25 +0000322int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
323{
324 *detachstate = attr->__detachstate;
325 return 0;
326}
327
sewardj30671ff2002-04-21 00:13:57 +0000328int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
329{
sewardj436e0582002-04-26 14:31:40 +0000330 static int moans = N_MOANS;
331 if (moans-- > 0)
332 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000333 return 0;
334}
sewardj6af4b5d2002-04-16 04:40:49 +0000335
sewardj0286dd52002-05-16 20:51:15 +0000336__attribute__((weak))
337int pthread_attr_setstacksize (pthread_attr_t *__attr,
338 size_t __stacksize)
339{
sewardja18e2102002-05-18 10:43:22 +0000340 size_t limit;
sewardj3d7c8d62002-06-04 20:59:16 +0000341 char buf[1024];
sewardj0286dd52002-05-16 20:51:15 +0000342 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000343 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
344 - 1000; /* paranoia */
345 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000346 return 0;
sewardj3d7c8d62002-06-04 20:59:16 +0000347 snprintf(buf, sizeof(buf), "pthread_attr_setstacksize: "
348 "requested size %d >= VG_PTHREAD_STACK_SIZE\n "
349 "edit vg_include.h and rebuild.", __stacksize);
350 buf[sizeof(buf)-1] = '\0'; /* Make sure it is zero terminated */
351 barf(buf);
sewardj0286dd52002-05-16 20:51:15 +0000352}
353
354
sewardj30671ff2002-04-21 00:13:57 +0000355/* This is completely bogus. */
356int pthread_attr_getschedparam(const pthread_attr_t *attr,
357 struct sched_param *param)
358{
sewardj436e0582002-04-26 14:31:40 +0000359 static int moans = N_MOANS;
360 if (moans-- > 0)
361 kludged("pthread_attr_getschedparam");
sewardj3e909ce2002-06-03 13:27:15 +0000362# ifdef HAVE_SCHED_PRIORITY
sewardj72d58482002-04-24 02:20:20 +0000363 if (param) param->sched_priority = 0; /* who knows */
364# else
sewardj30671ff2002-04-21 00:13:57 +0000365 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000366# endif
sewardj30671ff2002-04-21 00:13:57 +0000367 return 0;
368}
369
370int pthread_attr_setschedparam(pthread_attr_t *attr,
371 const struct sched_param *param)
372{
sewardj436e0582002-04-26 14:31:40 +0000373 static int moans = N_MOANS;
374 if (moans-- > 0)
375 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000376 return 0;
377}
378
379int pthread_attr_destroy(pthread_attr_t *attr)
380{
sewardj436e0582002-04-26 14:31:40 +0000381 static int moans = N_MOANS;
382 if (moans-- > 0)
383 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000384 return 0;
385}
sewardjf8f819e2002-04-17 23:21:37 +0000386
sewardj0d844232002-06-02 09:29:31 +0000387/* These are no-ops, as with LinuxThreads. */
388int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
389{
390 ensure_valgrind("pthread_attr_setscope");
391 if (scope == PTHREAD_SCOPE_SYSTEM)
392 return 0;
sewardj4dced352002-06-04 22:54:20 +0000393 pthread_error("pthread_attr_setscope: "
394 "invalid or unsupported scope");
sewardj0d844232002-06-02 09:29:31 +0000395 if (scope == PTHREAD_SCOPE_PROCESS)
396 return ENOTSUP;
397 return EINVAL;
398}
399
400int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
401{
402 ensure_valgrind("pthread_attr_setscope");
403 if (scope)
404 *scope = PTHREAD_SCOPE_SYSTEM;
405 return 0;
406}
407
sewardj64039bb2002-06-03 00:58:18 +0000408
409/* Pretty bogus. Avoid if possible. */
410int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
411{
412 int detached;
413 size_t limit;
414 ensure_valgrind("pthread_getattr_np");
415 kludged("pthread_getattr_np");
416 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
417 - 1000; /* paranoia */
418 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
419 attr->__schedpolicy = SCHED_OTHER;
420 attr->__schedparam.sched_priority = 0;
421 attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
422 attr->__scope = PTHREAD_SCOPE_SYSTEM;
423 attr->__guardsize = VKI_BYTES_PER_PAGE;
424 attr->__stackaddr = NULL;
425 attr->__stackaddr_set = 0;
426 attr->__stacksize = limit;
427 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
428 VG_USERREQ__SET_OR_GET_DETACH,
429 2 /* get */, thread, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000430 my_assert(detached == 0 || detached == 1);
sewardj64039bb2002-06-03 00:58:18 +0000431 if (detached)
432 attr->__detachstate = PTHREAD_CREATE_DETACHED;
433 return 0;
434}
435
436
437/* Bogus ... */
sewardj111b14c2002-10-20 16:22:57 +0000438__attribute__((weak))
sewardj64039bb2002-06-03 00:58:18 +0000439int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
440 void ** stackaddr )
441{
442 ensure_valgrind("pthread_attr_getstackaddr");
443 kludged("pthread_attr_getstackaddr");
444 if (stackaddr)
445 *stackaddr = NULL;
446 return 0;
447}
448
449/* Not bogus (!) */
sewardj111b14c2002-10-20 16:22:57 +0000450__attribute__((weak))
sewardj64039bb2002-06-03 00:58:18 +0000451int pthread_attr_getstacksize ( const pthread_attr_t * _attr,
452 size_t * __stacksize )
453{
454 size_t limit;
455 ensure_valgrind("pthread_attr_getstacksize");
456 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
457 - 1000; /* paranoia */
458 if (__stacksize)
459 *__stacksize = limit;
460 return 0;
461}
462
sewardja3be12f2002-06-17 12:19:44 +0000463int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
464{
465 if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
466 return EINVAL;
467 attr->__schedpolicy = policy;
468 return 0;
469}
470
471int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
472{
473 *policy = attr->__schedpolicy;
474 return 0;
475}
476
477
sewardj111b14c2002-10-20 16:22:57 +0000478/* This is completely bogus. We reject all attempts to change it from
479 VKI_BYTES_PER_PAGE. I don't have a clue what it's for so it seems
480 safest to be paranoid. */
481__attribute__((weak))
482int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
483{
484 static int moans = N_MOANS;
485
486 if (guardsize == VKI_BYTES_PER_PAGE)
487 return 0;
488
489 if (moans-- > 0)
490 ignored("pthread_attr_setguardsize: ignoring guardsize != 4096");
491
492 return 0;
493}
494
495/* A straight copy of the LinuxThreads code. */
496__attribute__((weak))
497int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
498{
499 *guardsize = attr->__guardsize;
500 return 0;
501}
502
503
sewardj20917d82002-05-28 01:36:45 +0000504/* ---------------------------------------------------
505 Helper functions for running a thread
506 and for clearing up afterwards.
507 ------------------------------------------------ */
508
509/* All exiting threads eventually pass through here, bearing the
510 return value, or PTHREAD_CANCELED, in ret_val. */
511static
512__attribute__((noreturn))
513void thread_exit_wrapper ( void* ret_val )
514{
sewardj870497a2002-05-29 01:06:47 +0000515 int detached, res;
516 CleanupEntry cu;
517 pthread_key_t key;
sewardj00a66b12002-10-12 16:42:35 +0000518 void** specifics_ptr;
sewardj870497a2002-05-29 01:06:47 +0000519
sewardj20917d82002-05-28 01:36:45 +0000520 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000521 while (1) {
522 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
523 VG_USERREQ__CLEANUP_POP,
524 &cu, 0, 0, 0);
525 if (res == -1) break; /* stack empty */
sewardj2d94c112002-06-03 01:25:54 +0000526 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000527 if (0) printf("running exit cleanup handler");
528 cu.fn ( cu.arg );
529 }
530
sewardj870497a2002-05-29 01:06:47 +0000531 /* Run this thread's key finalizers. Really this should be run
532 PTHREAD_DESTRUCTOR_ITERATIONS times. */
533 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
534 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
535 VG_USERREQ__GET_KEY_D_AND_S,
536 key, &cu, 0, 0 );
537 if (res == 0) {
538 /* valid key */
539 if (cu.fn && cu.arg)
540 cu.fn /* destructor for key */
541 ( cu.arg /* specific for key for this thread */ );
542 continue;
543 }
sewardj2d94c112002-06-03 01:25:54 +0000544 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000545 }
sewardj20917d82002-05-28 01:36:45 +0000546
sewardj00a66b12002-10-12 16:42:35 +0000547 /* Free up my specifics space, if any. */
548 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
549 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
550 pthread_self(), 0, 0, 0);
551 my_assert(specifics_ptr != (void**)3);
552 my_assert(specifics_ptr != (void**)1); /* 1 means invalid thread */
553 if (specifics_ptr != NULL)
554 my_free(specifics_ptr);
555
sewardj20917d82002-05-28 01:36:45 +0000556 /* Decide on my final disposition. */
557 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
558 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000559 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000560 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000561
562 if (detached) {
563 /* Detached; I just quit right now. */
564 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
565 VG_USERREQ__QUIT, 0, 0, 0, 0);
566 } else {
567 /* Not detached; so I wait for a joiner. */
568 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
569 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
570 }
571 /* NOTREACHED */
572 barf("thread_exit_wrapper: still alive?!");
573}
574
575
576/* This function is a wrapper function for running a thread. It runs
577 the root function specified in pthread_create, and then, should the
578 root function return a value, it arranges to run the thread's
579 cleanup handlers and exit correctly. */
580
sewardj728a5272002-06-20 10:25:37 +0000581/* Struct used to convey info from pthread_create to thread_wrapper.
582 Must be careful not to pass to the child thread any pointers to
583 objects which might be on the parent's stack. */
sewardj20917d82002-05-28 01:36:45 +0000584typedef
585 struct {
sewardj728a5272002-06-20 10:25:37 +0000586 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000587 void* (*root_fn) ( void* );
588 void* arg;
589 }
590 NewThreadInfo;
591
592
593/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
594 not return. Note that this runs in the new thread, not the
595 parent. */
596static
597__attribute__((noreturn))
598void thread_wrapper ( NewThreadInfo* info )
599{
sewardj728a5272002-06-20 10:25:37 +0000600 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000601 void* (*root_fn) ( void* );
602 void* arg;
603 void* ret_val;
604
sewardj728a5272002-06-20 10:25:37 +0000605 attr__detachstate = info->attr__detachstate;
606 root_fn = info->root_fn;
607 arg = info->arg;
sewardj20917d82002-05-28 01:36:45 +0000608
sewardj20917d82002-05-28 01:36:45 +0000609 /* Free up the arg block that pthread_create malloced. */
sewardj00a66b12002-10-12 16:42:35 +0000610 my_free(info);
sewardj20917d82002-05-28 01:36:45 +0000611
sewardj7989d0c2002-05-28 11:00:01 +0000612 /* Minimally observe the attributes supplied. */
sewardj728a5272002-06-20 10:25:37 +0000613 if (attr__detachstate != PTHREAD_CREATE_DETACHED
614 && attr__detachstate != PTHREAD_CREATE_JOINABLE)
615 pthread_error("thread_wrapper: invalid attr->__detachstate");
616 if (attr__detachstate == PTHREAD_CREATE_DETACHED)
617 pthread_detach(pthread_self());
sewardj7989d0c2002-05-28 11:00:01 +0000618
sewardj00a66b12002-10-12 16:42:35 +0000619# ifdef GLIBC_2_3
620 /* Set this thread's locale to the global (default) locale. A hack
621 in support of glibc-2.3. This does the biz for the all new
622 threads; the root thread is done with a horrible hack in
623 init_libc_tsd_keys() below.
624 */
625 __uselocale(LC_GLOBAL_LOCALE);
626# endif
627
sewardj20917d82002-05-28 01:36:45 +0000628 /* The root function might not return. But if it does we simply
629 move along to thread_exit_wrapper. All other ways out for the
630 thread (cancellation, or calling pthread_exit) lead there
631 too. */
632 ret_val = root_fn(arg);
633 thread_exit_wrapper(ret_val);
634 /* NOTREACHED */
635}
636
637
sewardjf8f819e2002-04-17 23:21:37 +0000638/* ---------------------------------------------------
639 THREADs
640 ------------------------------------------------ */
641
sewardjff42d1d2002-05-22 13:17:31 +0000642__attribute__((weak))
643int pthread_yield ( void )
644{
645 int res;
646 ensure_valgrind("pthread_yield");
647 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
648 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
649 return 0;
650}
651
652
sewardj6072c362002-04-19 14:40:57 +0000653int pthread_equal(pthread_t thread1, pthread_t thread2)
654{
655 return thread1 == thread2 ? 1 : 0;
656}
657
658
sewardj20917d82002-05-28 01:36:45 +0000659/* Bundle up the args into a malloc'd block and create a new thread
660 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000661int
sewardj1462c8b2002-07-24 09:41:52 +0000662pthread_create (pthread_t *__restrict __thredd,
sewardje663cb92002-04-12 10:26:32 +0000663 __const pthread_attr_t *__restrict __attr,
664 void *(*__start_routine) (void *),
665 void *__restrict __arg)
666{
sewardj20917d82002-05-28 01:36:45 +0000667 int tid_child;
668 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000669
sewardj20917d82002-05-28 01:36:45 +0000670 ensure_valgrind("pthread_create");
671
sewardj00a66b12002-10-12 16:42:35 +0000672 /* make sure the tsd keys, and hence locale info, are initialised
673 before we get into complications making new threads. */
674 init_libc_tsd_keys();
675
sewardj20917d82002-05-28 01:36:45 +0000676 /* Allocate space for the arg block. thread_wrapper will free
677 it. */
sewardj00a66b12002-10-12 16:42:35 +0000678 info = my_malloc(sizeof(NewThreadInfo));
sewardj2d94c112002-06-03 01:25:54 +0000679 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000680
sewardj728a5272002-06-20 10:25:37 +0000681 if (__attr)
682 info->attr__detachstate = __attr->__detachstate;
683 else
684 info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
685
sewardj20917d82002-05-28 01:36:45 +0000686 info->root_fn = __start_routine;
687 info->arg = __arg;
688 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
689 VG_USERREQ__APPLY_IN_NEW_THREAD,
690 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000691 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000692
sewardj1462c8b2002-07-24 09:41:52 +0000693 if (__thredd)
694 *__thredd = tid_child;
sewardj20917d82002-05-28 01:36:45 +0000695 return 0; /* success */
696}
sewardje663cb92002-04-12 10:26:32 +0000697
698
699int
700pthread_join (pthread_t __th, void **__thread_return)
701{
702 int res;
703 ensure_valgrind("pthread_join");
704 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
705 VG_USERREQ__PTHREAD_JOIN,
706 __th, __thread_return, 0, 0);
707 return res;
708}
709
710
sewardj3b5d8862002-04-20 13:53:23 +0000711void pthread_exit(void *retval)
712{
sewardj3b5d8862002-04-20 13:53:23 +0000713 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000714 /* Simple! */
715 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000716}
717
sewardje663cb92002-04-12 10:26:32 +0000718
sewardj853f55d2002-04-26 00:27:53 +0000719int pthread_detach(pthread_t th)
720{
sewardj20917d82002-05-28 01:36:45 +0000721 int res;
722 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000723 /* First we enquire as to the current detach state. */
724 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000725 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000726 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000727 if (res == -1) {
728 /* not found */
729 pthread_error("pthread_detach: "
730 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000731 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000732 }
733 if (res == 1) {
734 /* already detached */
735 pthread_error("pthread_detach: "
736 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000737 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000738 }
sewardj7989d0c2002-05-28 11:00:01 +0000739 if (res == 0) {
740 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
741 VG_USERREQ__SET_OR_GET_DETACH,
742 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000743 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000744 return 0;
745 }
746 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000747}
748
749
sewardjf8f819e2002-04-17 23:21:37 +0000750/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000751 CLEANUP STACKS
752 ------------------------------------------------ */
753
754void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
755 void (*__routine) (void *),
756 void *__arg)
757{
758 int res;
759 CleanupEntry cu;
760 ensure_valgrind("_pthread_cleanup_push");
761 cu.fn = __routine;
762 cu.arg = __arg;
763 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
764 VG_USERREQ__CLEANUP_PUSH,
765 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000766 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000767}
768
769
770void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
771 void (*__routine) (void *),
772 void *__arg)
773{
774 /* As _pthread_cleanup_push, but first save the thread's original
775 cancellation type in __buffer and set it to Deferred. */
776 int orig_ctype;
777 ensure_valgrind("_pthread_cleanup_push_defer");
778 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000779 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
780 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
781 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000782 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
783 VG_USERREQ__SET_CANCELTYPE,
784 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000785 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000786 *((int*)(__buffer)) = orig_ctype;
787 /* Now push the cleanup. */
788 _pthread_cleanup_push(NULL, __routine, __arg);
789}
790
791
792void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
793 int __execute)
794{
795 int res;
796 CleanupEntry cu;
797 ensure_valgrind("_pthread_cleanup_push");
798 cu.fn = cu.arg = NULL; /* paranoia */
799 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
800 VG_USERREQ__CLEANUP_POP,
801 &cu, 0, 0, 0);
802 if (res == 0) {
803 /* pop succeeded */
804 if (__execute) {
805 cu.fn ( cu.arg );
806 }
807 return;
808 }
809 if (res == -1) {
810 /* stack underflow */
811 return;
812 }
813 barf("_pthread_cleanup_pop");
814}
815
816
817void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
818 int __execute)
819{
820 int orig_ctype, fake_ctype;
821 /* As _pthread_cleanup_pop, but after popping/running the handler,
822 restore the thread's original cancellation type from the first
823 word of __buffer. */
824 _pthread_cleanup_pop(NULL, __execute);
825 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000826 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000827 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000828 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
829 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
830 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000831 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
832 VG_USERREQ__SET_CANCELTYPE,
833 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000834 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000835}
836
837
838/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000839 MUTEX ATTRIBUTES
840 ------------------------------------------------ */
841
sewardj5905fae2002-04-26 13:25:00 +0000842int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000843{
sewardjf8f819e2002-04-17 23:21:37 +0000844 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000845 return 0;
sewardje663cb92002-04-12 10:26:32 +0000846}
847
sewardj5905fae2002-04-26 13:25:00 +0000848int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000849{
850 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000851# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000852 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000853 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000854# endif
sewardja1679dd2002-05-10 22:31:40 +0000855# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000856 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000857# endif
sewardjf8f819e2002-04-17 23:21:37 +0000858 case PTHREAD_MUTEX_RECURSIVE_NP:
859 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000860 attr->__mutexkind = type;
861 return 0;
862 default:
sewardj4dced352002-06-04 22:54:20 +0000863 pthread_error("pthread_mutexattr_settype: "
864 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000865 return EINVAL;
866 }
867}
868
sewardj5905fae2002-04-26 13:25:00 +0000869int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000870{
871 return 0;
872}
873
874
875/* ---------------------------------------------------
876 MUTEXes
877 ------------------------------------------------ */
878
sewardj5905fae2002-04-26 13:25:00 +0000879int __pthread_mutex_init(pthread_mutex_t *mutex,
880 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000881{
sewardj604ec3c2002-04-18 22:38:41 +0000882 mutex->__m_count = 0;
883 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
884 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
885 if (mutexattr)
886 mutex->__m_kind = mutexattr->__mutexkind;
887 return 0;
sewardje663cb92002-04-12 10:26:32 +0000888}
889
sewardj439d45e2002-05-03 20:43:10 +0000890
sewardj5905fae2002-04-26 13:25:00 +0000891int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000892{
893 int res;
sewardj436e0582002-04-26 14:31:40 +0000894 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000895 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000896 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
897 VG_USERREQ__PTHREAD_MUTEX_LOCK,
898 mutex, 0, 0, 0);
899 return res;
sewardj439d45e2002-05-03 20:43:10 +0000900 } else {
901 if (moans-- > 0)
902 not_inside("pthread_mutex_lock");
903 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000904 }
905}
906
sewardj439d45e2002-05-03 20:43:10 +0000907
sewardj5905fae2002-04-26 13:25:00 +0000908int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000909{
910 int res;
sewardj436e0582002-04-26 14:31:40 +0000911 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000912 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000913 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
914 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
915 mutex, 0, 0, 0);
916 return res;
sewardj439d45e2002-05-03 20:43:10 +0000917 } else {
918 if (moans-- > 0)
919 not_inside("pthread_mutex_trylock");
920 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000921 }
922}
923
sewardj439d45e2002-05-03 20:43:10 +0000924
sewardj5905fae2002-04-26 13:25:00 +0000925int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000926{
927 int res;
sewardj436e0582002-04-26 14:31:40 +0000928 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000929 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000930 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
931 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
932 mutex, 0, 0, 0);
933 return res;
sewardj439d45e2002-05-03 20:43:10 +0000934 } else {
935 if (moans-- > 0)
936 not_inside("pthread_mutex_unlock");
937 return 0;
sewardje663cb92002-04-12 10:26:32 +0000938 }
939}
940
sewardj439d45e2002-05-03 20:43:10 +0000941
sewardj5905fae2002-04-26 13:25:00 +0000942int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000943{
sewardj604ec3c2002-04-18 22:38:41 +0000944 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
945 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +0000946 if (mutex->__m_count > 0) {
947 pthread_error("pthread_mutex_destroy: "
948 "mutex is still in use");
sewardj604ec3c2002-04-18 22:38:41 +0000949 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +0000950 }
951 mutex->__m_count = 0;
952 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
953 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
954 return 0;
sewardje663cb92002-04-12 10:26:32 +0000955}
956
957
sewardjf8f819e2002-04-17 23:21:37 +0000958/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000959 CONDITION VARIABLES
960 ------------------------------------------------ */
961
962/* LinuxThreads supports no attributes for conditions. Hence ... */
963
964int pthread_condattr_init(pthread_condattr_t *attr)
965{
966 return 0;
967}
968
sewardj0738a592002-04-20 13:59:33 +0000969int pthread_condattr_destroy(pthread_condattr_t *attr)
970{
971 return 0;
972}
sewardj6072c362002-04-19 14:40:57 +0000973
974int pthread_cond_init( pthread_cond_t *cond,
975 const pthread_condattr_t *cond_attr)
976{
977 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
978 return 0;
979}
980
sewardjf854f472002-04-21 12:19:41 +0000981int pthread_cond_destroy(pthread_cond_t *cond)
982{
983 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000984 static int moans = N_MOANS;
985 if (moans-- > 0)
986 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000987 return 0;
988}
sewardj6072c362002-04-19 14:40:57 +0000989
990/* ---------------------------------------------------
991 SCHEDULING
992 ------------------------------------------------ */
993
994/* This is completely bogus. */
995int pthread_getschedparam(pthread_t target_thread,
996 int *policy,
997 struct sched_param *param)
998{
sewardj436e0582002-04-26 14:31:40 +0000999 static int moans = N_MOANS;
1000 if (moans-- > 0)
1001 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +00001002 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +00001003# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +00001004 if (param) param->sched_priority = 0; /* who knows */
1005# else
sewardj6072c362002-04-19 14:40:57 +00001006 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +00001007# endif
sewardj6072c362002-04-19 14:40:57 +00001008 return 0;
1009}
1010
1011int pthread_setschedparam(pthread_t target_thread,
1012 int policy,
1013 const struct sched_param *param)
1014{
sewardj436e0582002-04-26 14:31:40 +00001015 static int moans = N_MOANS;
1016 if (moans-- > 0)
1017 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +00001018 return 0;
1019}
1020
sewardj3b5d8862002-04-20 13:53:23 +00001021int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
1022{
1023 int res;
1024 ensure_valgrind("pthread_cond_wait");
1025 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1026 VG_USERREQ__PTHREAD_COND_WAIT,
1027 cond, mutex, 0, 0);
1028 return res;
1029}
1030
sewardj5f07b662002-04-23 16:52:51 +00001031int pthread_cond_timedwait ( pthread_cond_t *cond,
1032 pthread_mutex_t *mutex,
1033 const struct timespec *abstime )
1034{
1035 int res;
1036 unsigned int ms_now, ms_end;
1037 struct timeval timeval_now;
1038 unsigned long long int ull_ms_now_after_1970;
1039 unsigned long long int ull_ms_end_after_1970;
1040
1041 ensure_valgrind("pthread_cond_timedwait");
1042 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1043 VG_USERREQ__READ_MILLISECOND_TIMER,
1044 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001045 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001046 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +00001047 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001048
1049 ull_ms_now_after_1970
1050 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
1051 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
1052 ull_ms_end_after_1970
1053 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
1054 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +00001055 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
1056 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +00001057 ms_end
1058 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
1059 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1060 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
1061 cond, mutex, ms_end, 0);
1062 return res;
1063}
1064
1065
sewardj3b5d8862002-04-20 13:53:23 +00001066int pthread_cond_signal(pthread_cond_t *cond)
1067{
1068 int res;
1069 ensure_valgrind("pthread_cond_signal");
1070 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1071 VG_USERREQ__PTHREAD_COND_SIGNAL,
1072 cond, 0, 0, 0);
1073 return res;
1074}
1075
1076int pthread_cond_broadcast(pthread_cond_t *cond)
1077{
1078 int res;
1079 ensure_valgrind("pthread_cond_broadcast");
1080 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1081 VG_USERREQ__PTHREAD_COND_BROADCAST,
1082 cond, 0, 0, 0);
1083 return res;
1084}
1085
sewardj6072c362002-04-19 14:40:57 +00001086
1087/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001088 CANCELLATION
1089 ------------------------------------------------ */
1090
sewardj853f55d2002-04-26 00:27:53 +00001091int pthread_setcancelstate(int state, int *oldstate)
1092{
sewardj20917d82002-05-28 01:36:45 +00001093 int res;
1094 ensure_valgrind("pthread_setcancelstate");
1095 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +00001096 && state != PTHREAD_CANCEL_DISABLE) {
1097 pthread_error("pthread_setcancelstate: "
1098 "invalid state");
sewardj20917d82002-05-28 01:36:45 +00001099 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001100 }
sewardj2d94c112002-06-03 01:25:54 +00001101 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1102 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001103 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1104 VG_USERREQ__SET_CANCELSTATE,
1105 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001106 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001107 if (oldstate)
1108 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001109 return 0;
1110}
1111
sewardje663cb92002-04-12 10:26:32 +00001112int pthread_setcanceltype(int type, int *oldtype)
1113{
sewardj20917d82002-05-28 01:36:45 +00001114 int res;
1115 ensure_valgrind("pthread_setcanceltype");
1116 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001117 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1118 pthread_error("pthread_setcanceltype: "
1119 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001120 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001121 }
sewardj2d94c112002-06-03 01:25:54 +00001122 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1123 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001124 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1125 VG_USERREQ__SET_CANCELTYPE,
1126 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001127 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001128 if (oldtype)
1129 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001130 return 0;
1131}
1132
sewardje663cb92002-04-12 10:26:32 +00001133int pthread_cancel(pthread_t thread)
1134{
1135 int res;
1136 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001137 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1138 VG_USERREQ__SET_CANCELPEND,
1139 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001140 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001141 return res;
1142}
1143
sewardjd140e442002-05-29 01:21:19 +00001144static __inline__
1145void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001146{
sewardj20917d82002-05-28 01:36:45 +00001147 int res;
njn25e49d8e72002-09-23 09:36:25 +00001148 ensure_valgrind("__my_pthread_testcancel");
sewardj20917d82002-05-28 01:36:45 +00001149 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1150 VG_USERREQ__TESTCANCEL,
1151 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001152 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001153}
1154
sewardjd140e442002-05-29 01:21:19 +00001155void pthread_testcancel ( void )
1156{
1157 __my_pthread_testcancel();
1158}
1159
sewardj20917d82002-05-28 01:36:45 +00001160
sewardjef037c72002-05-30 00:40:03 +00001161/* Not really sure what this is for. I suspect for doing the POSIX
1162 requirements for fork() and exec(). We do this internally anyway
1163 whenever those syscalls are observed, so this could be superfluous,
1164 but hey ...
1165*/
sewardj853f55d2002-04-26 00:27:53 +00001166void __pthread_kill_other_threads_np ( void )
1167{
sewardjef037c72002-05-30 00:40:03 +00001168 int res;
1169 ensure_valgrind("__pthread_kill_other_threads_np");
1170 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1171 VG_USERREQ__NUKE_OTHER_THREADS,
1172 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001173 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001174}
1175
sewardje663cb92002-04-12 10:26:32 +00001176
sewardjf8f819e2002-04-17 23:21:37 +00001177/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001178 SIGNALS
1179 ------------------------------------------------ */
1180
1181#include <signal.h>
1182
1183int pthread_sigmask(int how, const sigset_t *newmask,
1184 sigset_t *oldmask)
1185{
1186 int res;
1187
1188 /* A bit subtle, because the scheduler expects newmask and oldmask
1189 to be vki_sigset_t* rather than sigset_t*, and the two are
1190 different. Fortunately the first 64 bits of a sigset_t are
1191 exactly a vki_sigset_t, so we just pass the pointers through
1192 unmodified. Haaaack!
1193
1194 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001195 constants to VKI_ constants, so that the former do not have to
1196 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001197
1198 ensure_valgrind("pthread_sigmask");
1199
1200 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001201 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1202 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1203 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001204 default: pthread_error("pthread_sigmask: invalid how");
1205 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001206 }
1207
1208 /* Crude check */
1209 if (newmask == NULL)
1210 return EFAULT;
1211
1212 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1213 VG_USERREQ__PTHREAD_SIGMASK,
1214 how, newmask, oldmask, 0);
1215
1216 /* The scheduler tells us of any memory violations. */
1217 return res == 0 ? 0 : EFAULT;
1218}
1219
1220
1221int sigwait ( const sigset_t* set, int* sig )
1222{
1223 int res;
1224 ensure_valgrind("sigwait");
1225 /* As with pthread_sigmask we deliberately confuse sigset_t with
1226 vki_ksigset_t. */
1227 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1228 VG_USERREQ__SIGWAIT,
1229 set, sig, 0, 0);
1230 return res;
1231}
1232
1233
sewardj018f7622002-05-15 21:13:39 +00001234int pthread_kill(pthread_t thread, int signo)
1235{
1236 int res;
1237 ensure_valgrind("pthread_kill");
1238 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1239 VG_USERREQ__PTHREAD_KILL,
1240 thread, signo, 0, 0);
1241 return res;
1242}
1243
1244
sewardj3665ded2002-05-16 16:57:25 +00001245/* Copied verbatim from Linuxthreads */
1246/* Redefine raise() to send signal to calling thread only,
1247 as per POSIX 1003.1c */
1248int raise (int sig)
1249{
1250 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001251 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001252 return 0;
sewardj4dced352002-06-04 22:54:20 +00001253 } else {
sewardj3665ded2002-05-16 16:57:25 +00001254 errno = retcode;
1255 return -1;
1256 }
1257}
1258
1259
sewardj9a2224b2002-06-19 10:17:40 +00001260int pause ( void )
1261{
1262 unsigned int n_orig, n_now;
1263 struct vki_timespec nanosleep_interval;
1264 ensure_valgrind("pause");
1265
1266 /* This is surely a cancellation point. */
1267 __my_pthread_testcancel();
1268
1269 VALGRIND_MAGIC_SEQUENCE(n_orig, 0xFFFFFFFF /* default */,
1270 VG_USERREQ__GET_N_SIGS_RETURNED,
1271 0, 0, 0, 0);
1272 my_assert(n_orig != 0xFFFFFFFF);
1273
1274 while (1) {
1275 VALGRIND_MAGIC_SEQUENCE(n_now, 0xFFFFFFFF /* default */,
1276 VG_USERREQ__GET_N_SIGS_RETURNED,
1277 0, 0, 0, 0);
1278 my_assert(n_now != 0xFFFFFFFF);
1279 my_assert(n_now >= n_orig);
1280 if (n_now != n_orig) break;
1281
1282 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001283 nanosleep_interval.tv_nsec = 12 * 1000 * 1000; /* 12 milliseconds */
sewardj9a2224b2002-06-19 10:17:40 +00001284 /* It's critical here that valgrind's nanosleep implementation
1285 is nonblocking. */
1286 (void)my_do_syscall2(__NR_nanosleep,
1287 (int)(&nanosleep_interval), (int)NULL);
1288 }
1289
1290 * (__errno_location()) = EINTR;
1291 return -1;
1292}
1293
1294
sewardjb48e5002002-05-13 00:16:03 +00001295/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001296 THREAD-SPECIFICs
1297 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001298
sewardj00a66b12002-10-12 16:42:35 +00001299static
1300int key_is_valid (pthread_key_t key)
1301{
1302 int res;
1303 VALGRIND_MAGIC_SEQUENCE(res, 2 /* default */,
1304 VG_USERREQ__PTHREAD_KEY_VALIDATE,
1305 key, 0, 0, 0);
1306 my_assert(res != 2);
1307 return res;
1308}
1309
1310
1311/* Returns NULL if thread is invalid. Otherwise, if the thread
1312 already has a specifics area, return that. Otherwise allocate it
1313 one. */
1314static
1315void** get_or_allocate_specifics_ptr ( pthread_t thread )
1316{
1317 int res, i;
1318 void** specifics_ptr;
1319 ensure_valgrind("get_or_allocate_specifics_ptr");
1320
1321 /* Returns zero if the thread has no specific_ptr. One if thread
1322 is invalid. Otherwise, the specific_ptr value. This is
1323 allocated with my_malloc and so is aligned and cannot be
1324 confused with 1 or 3. */
1325 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
1326 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
1327 thread, 0, 0, 0);
1328 my_assert(specifics_ptr != (void**)3);
1329
1330 if (specifics_ptr == (void**)1)
1331 return NULL; /* invalid thread */
1332
1333 if (specifics_ptr != NULL)
1334 return specifics_ptr; /* already has a specifics ptr. */
1335
1336 /* None yet ... allocate a new one. Should never fail. */
1337 specifics_ptr = my_malloc( VG_N_THREAD_KEYS * sizeof(void*) );
1338 my_assert(specifics_ptr != NULL);
1339
1340 VALGRIND_MAGIC_SEQUENCE(res, -1 /* default */,
1341 VG_USERREQ__PTHREAD_SETSPECIFIC_PTR,
1342 specifics_ptr, 0, 0, 0);
1343 my_assert(res == 0);
1344
1345 /* POSIX sez: "Upon thread creation, the value NULL shall be
1346 associated with all defined keys in the new thread." This
1347 allocation is in effect a delayed allocation of the specific
1348 data for a thread, at its first-use. Hence we initialise it
1349 here. */
1350 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
1351 specifics_ptr[i] = NULL;
1352 }
1353
1354 return specifics_ptr;
1355}
1356
1357
sewardj5905fae2002-04-26 13:25:00 +00001358int __pthread_key_create(pthread_key_t *key,
1359 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001360{
sewardj00a66b12002-10-12 16:42:35 +00001361 void** specifics_ptr;
1362 int res, i;
sewardj5f07b662002-04-23 16:52:51 +00001363 ensure_valgrind("pthread_key_create");
sewardj00a66b12002-10-12 16:42:35 +00001364
1365 /* This writes *key if successful. It should never fail. */
1366 VALGRIND_MAGIC_SEQUENCE(res, 1 /* default */,
sewardj5f07b662002-04-23 16:52:51 +00001367 VG_USERREQ__PTHREAD_KEY_CREATE,
1368 key, destr_function, 0, 0);
sewardj00a66b12002-10-12 16:42:35 +00001369 my_assert(res == 0);
1370
1371 /* POSIX sez: "Upon key creation, the value NULL shall be
1372 associated with the new key in all active threads." */
1373 for (i = 0; i < VG_N_THREADS; i++) {
1374 specifics_ptr = get_or_allocate_specifics_ptr(i);
1375 /* we get NULL if i is an invalid thread. */
1376 if (specifics_ptr != NULL)
1377 specifics_ptr[*key] = NULL;
1378 }
1379
sewardj5f07b662002-04-23 16:52:51 +00001380 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001381}
1382
1383int pthread_key_delete(pthread_key_t key)
1384{
sewardj00a66b12002-10-12 16:42:35 +00001385 int res;
1386 ensure_valgrind("pthread_key_create");
1387 if (!key_is_valid(key))
1388 return EINVAL;
1389 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1390 VG_USERREQ__PTHREAD_KEY_DELETE,
1391 key, 0, 0, 0);
1392 my_assert(res == 0);
sewardj5e5fa512002-04-14 13:13:05 +00001393 return 0;
1394}
1395
sewardj5905fae2002-04-26 13:25:00 +00001396int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001397{
sewardj00a66b12002-10-12 16:42:35 +00001398 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001399 ensure_valgrind("pthread_setspecific");
sewardj00a66b12002-10-12 16:42:35 +00001400
1401 if (!key_is_valid(key))
1402 return EINVAL;
1403
1404 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1405 specifics_ptr[key] = (void*)pointer;
1406 return 0;
sewardj5e5fa512002-04-14 13:13:05 +00001407}
1408
sewardj5905fae2002-04-26 13:25:00 +00001409void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001410{
sewardj00a66b12002-10-12 16:42:35 +00001411 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001412 ensure_valgrind("pthread_getspecific");
sewardj00a66b12002-10-12 16:42:35 +00001413
1414 if (!key_is_valid(key))
1415 return NULL;
1416
1417 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1418 return specifics_ptr[key];
1419}
1420
1421
sewardj9aa918d2002-10-20 16:25:55 +00001422#ifdef GLIBC_2_3
sewardj00a66b12002-10-12 16:42:35 +00001423static
1424void ** __pthread_getspecific_addr(pthread_key_t key)
1425{
1426 void** specifics_ptr;
1427 ensure_valgrind("pthread_getspecific_addr");
1428
1429 if (!key_is_valid(key))
1430 return NULL;
1431
1432 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1433 return &(specifics_ptr[key]);
sewardj5e5fa512002-04-14 13:13:05 +00001434}
sewardj9aa918d2002-10-20 16:25:55 +00001435#endif
sewardjf8f819e2002-04-17 23:21:37 +00001436
1437/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001438 ONCEry
1439 ------------------------------------------------ */
1440
1441static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1442
1443
sewardj5905fae2002-04-26 13:25:00 +00001444int __pthread_once ( pthread_once_t *once_control,
1445 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001446{
1447 int res;
1448 ensure_valgrind("pthread_once");
1449
sewardj68b2dd92002-05-10 21:03:56 +00001450 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001451
sewardj68b2dd92002-05-10 21:03:56 +00001452 if (res != 0) {
sewardj89d3d852002-04-24 19:21:39 +00001453 barf("pthread_once: Looks like your program's "
1454 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001455 }
sewardj89d3d852002-04-24 19:21:39 +00001456
1457 if (*once_control == 0) {
1458 *once_control = 1;
1459 init_routine();
1460 }
1461
sewardj68b2dd92002-05-10 21:03:56 +00001462 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001463
1464 return 0;
1465}
1466
1467
1468/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001469 MISC
1470 ------------------------------------------------ */
1471
sewardj2cb00342002-06-28 01:46:26 +00001472static pthread_mutex_t pthread_atfork_lock
1473 = PTHREAD_MUTEX_INITIALIZER;
1474
sewardj5905fae2002-04-26 13:25:00 +00001475int __pthread_atfork ( void (*prepare)(void),
1476 void (*parent)(void),
1477 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001478{
sewardj2cb00342002-06-28 01:46:26 +00001479 int n, res;
1480 ForkHandlerEntry entry;
1481
1482 ensure_valgrind("pthread_atfork");
1483 __pthread_mutex_lock(&pthread_atfork_lock);
1484
1485 /* Fetch old counter */
1486 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1487 VG_USERREQ__GET_FHSTACK_USED,
1488 0, 0, 0, 0);
1489 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1490 if (n == VG_N_FORKHANDLERSTACK-1)
1491 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1492 "increase and recompile");
1493
1494 /* Add entry */
1495 entry.prepare = *prepare;
1496 entry.parent = *parent;
1497 entry.child = *child;
1498 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1499 VG_USERREQ__SET_FHSTACK_ENTRY,
1500 n, &entry, 0, 0);
1501 my_assert(res == 0);
1502
1503 /* Bump counter */
1504 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1505 VG_USERREQ__SET_FHSTACK_USED,
1506 n+1, 0, 0, 0);
1507 my_assert(res == 0);
1508
1509 __pthread_mutex_unlock(&pthread_atfork_lock);
1510 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001511}
1512
1513
sewardjbb990782002-05-08 02:01:14 +00001514__attribute__((weak))
1515void __pthread_initialize ( void )
1516{
sewardjbea1caa2002-05-10 23:20:58 +00001517 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001518}
1519
1520
sewardj853f55d2002-04-26 00:27:53 +00001521/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001522 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001523 ------------------------------------------------ */
1524
sewardj3b13f0e2002-04-25 20:17:29 +00001525#include <resolv.h>
1526static int thread_specific_errno[VG_N_THREADS];
1527static int thread_specific_h_errno[VG_N_THREADS];
1528static struct __res_state
1529 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001530
sewardj3b13f0e2002-04-25 20:17:29 +00001531int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001532{
1533 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001534 /* ensure_valgrind("__errno_location"); */
1535 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001536 VG_USERREQ__PTHREAD_GET_THREADID,
1537 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001538 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001539 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001540 barf("__errno_location: invalid ThreadId");
1541 return & thread_specific_errno[tid];
1542}
1543
1544int* __h_errno_location ( void )
1545{
1546 int tid;
1547 /* ensure_valgrind("__h_errno_location"); */
1548 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1549 VG_USERREQ__PTHREAD_GET_THREADID,
1550 0, 0, 0, 0);
1551 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001552 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001553 barf("__h_errno_location: invalid ThreadId");
1554 return & thread_specific_h_errno[tid];
1555}
1556
sewardjb0ff1032002-08-06 09:02:53 +00001557
1558#undef _res
1559extern struct __res_state _res;
1560
sewardj3b13f0e2002-04-25 20:17:29 +00001561struct __res_state* __res_state ( void )
1562{
1563 int tid;
1564 /* ensure_valgrind("__res_state"); */
1565 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1566 VG_USERREQ__PTHREAD_GET_THREADID,
1567 0, 0, 0, 0);
1568 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001569 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001570 barf("__res_state: invalid ThreadId");
sewardjb0ff1032002-08-06 09:02:53 +00001571 if (tid == 1)
1572 return & _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001573 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001574}
1575
1576
sewardj5716dbb2002-04-26 03:28:18 +00001577/* ---------------------------------------------------
1578 LIBC-PRIVATE SPECIFIC DATA
1579 ------------------------------------------------ */
1580
1581/* Relies on assumption that initial private data is NULL. This
1582 should be fixed somehow. */
1583
njn25e49d8e72002-09-23 09:36:25 +00001584/* The allowable keys (indices) (all 3 of them).
sewardj5716dbb2002-04-26 03:28:18 +00001585 From sysdeps/pthread/bits/libc-tsd.h
1586*/
sewardjcb7f08a2002-10-02 09:41:49 +00001587/* as per glibc anoncvs HEAD of 20021001. */
sewardj5716dbb2002-04-26 03:28:18 +00001588enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1589 _LIBC_TSD_KEY_DL_ERROR,
njn25e49d8e72002-09-23 09:36:25 +00001590 _LIBC_TSD_KEY_RPC_VARS,
sewardjcb7f08a2002-10-02 09:41:49 +00001591 _LIBC_TSD_KEY_LOCALE,
1592 _LIBC_TSD_KEY_CTYPE_B,
1593 _LIBC_TSD_KEY_CTYPE_TOLOWER,
1594 _LIBC_TSD_KEY_CTYPE_TOUPPER,
sewardj5716dbb2002-04-26 03:28:18 +00001595 _LIBC_TSD_KEY_N };
1596
1597/* Auto-initialising subsystem. libc_specifics_inited is set
1598 after initialisation. libc_specifics_inited_mx guards it. */
1599static int libc_specifics_inited = 0;
1600static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1601
sewardj00a66b12002-10-12 16:42:35 +00001602
sewardj5716dbb2002-04-26 03:28:18 +00001603/* These are the keys we must initialise the first time. */
sewardjcb7f08a2002-10-02 09:41:49 +00001604static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N];
sewardj5716dbb2002-04-26 03:28:18 +00001605
sewardj00a66b12002-10-12 16:42:35 +00001606
sewardjcb7f08a2002-10-02 09:41:49 +00001607/* Initialise the keys, if they are not already initialised. */
sewardj5716dbb2002-04-26 03:28:18 +00001608static
1609void init_libc_tsd_keys ( void )
1610{
1611 int res, i;
1612 pthread_key_t k;
1613
sewardj08c7f012002-10-07 23:56:55 +00001614 /* Don't fall into deadlock if we get called again whilst we still
1615 hold the lock, via the __uselocale() call herein. */
1616 if (libc_specifics_inited != 0)
1617 return;
1618
1619 /* Take the lock. */
sewardj00a66b12002-10-12 16:42:35 +00001620 res = __pthread_mutex_lock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001621 if (res != 0) barf("init_libc_tsd_keys: lock");
1622
sewardj08c7f012002-10-07 23:56:55 +00001623 /* Now test again, to be sure there is no mistake. */
1624 if (libc_specifics_inited != 0) {
sewardj00a66b12002-10-12 16:42:35 +00001625 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj08c7f012002-10-07 23:56:55 +00001626 if (res != 0) barf("init_libc_tsd_keys: unlock(1)");
1627 return;
sewardj5716dbb2002-04-26 03:28:18 +00001628 }
1629
sewardj08c7f012002-10-07 23:56:55 +00001630 /* Actually do the initialisation. */
1631 /* printf("INIT libc specifics\n"); */
1632 for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
sewardj00a66b12002-10-12 16:42:35 +00001633 res = __pthread_key_create(&k, NULL);
sewardj08c7f012002-10-07 23:56:55 +00001634 if (res != 0) barf("init_libc_tsd_keys: create");
1635 libc_specifics_keys[i] = k;
1636 }
1637
1638 /* Signify init done. */
1639 libc_specifics_inited = 1;
1640
1641# ifdef GLIBC_2_3
1642 /* Set the initialising thread's locale to the global (default)
sewardj00a66b12002-10-12 16:42:35 +00001643 locale. A hack in support of glibc-2.3. This does the biz for
1644 the root thread. For all other threads we run this in
1645 thread_wrapper(), which does the real work of
1646 pthread_create(). */
1647 /* assert that we are the root thread. I don't know if this is
1648 really a valid assertion to make; if it breaks I'll reconsider
1649 it. */
1650 my_assert(pthread_self() == 1);
sewardj08c7f012002-10-07 23:56:55 +00001651 __uselocale(LC_GLOBAL_LOCALE);
1652# endif
1653
1654 /* Unlock and return. */
sewardj00a66b12002-10-12 16:42:35 +00001655 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001656 if (res != 0) barf("init_libc_tsd_keys: unlock");
1657}
1658
1659
1660static int
1661libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1662 const void * pointer )
1663{
sewardjcb7f08a2002-10-02 09:41:49 +00001664 int res;
sewardj5716dbb2002-04-26 03:28:18 +00001665 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardjcb7f08a2002-10-02 09:41:49 +00001666 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001667 barf("libc_internal_tsd_set: invalid key");
1668 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001669 res = __pthread_setspecific(libc_specifics_keys[key], pointer);
sewardj5716dbb2002-04-26 03:28:18 +00001670 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1671 return 0;
1672}
1673
1674static void *
1675libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1676{
sewardjcb7f08a2002-10-02 09:41:49 +00001677 void* v;
sewardj5716dbb2002-04-26 03:28:18 +00001678 /* printf("GET GET GET key %d\n", key); */
sewardjcb7f08a2002-10-02 09:41:49 +00001679 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001680 barf("libc_internal_tsd_get: invalid key");
1681 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001682 v = __pthread_getspecific(libc_specifics_keys[key]);
sewardj5716dbb2002-04-26 03:28:18 +00001683 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1684 return v;
1685}
1686
1687
sewardj70adeb22002-04-27 01:35:38 +00001688int (*__libc_internal_tsd_set)
1689 (enum __libc_tsd_key_t key, const void * pointer)
1690 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001691
sewardj70adeb22002-04-27 01:35:38 +00001692void* (*__libc_internal_tsd_get)
1693 (enum __libc_tsd_key_t key)
1694 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001695
1696
sewardj00a66b12002-10-12 16:42:35 +00001697#ifdef GLIBC_2_3
1698/* This one was first spotted be me in the glibc-2.2.93 sources. */
1699static void**
1700libc_internal_tsd_address ( enum __libc_tsd_key_t key )
1701{
1702 void** v;
1703 /* printf("ADDR ADDR ADDR key %d\n", key); */
1704 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
1705 barf("libc_internal_tsd_address: invalid key");
1706 init_libc_tsd_keys();
1707 v = __pthread_getspecific_addr(libc_specifics_keys[key]);
1708 return v;
1709}
1710
1711void ** (*__libc_internal_tsd_address)
1712 (enum __libc_tsd_key_t key)
1713 = libc_internal_tsd_address;
1714#endif
1715
1716
sewardje663cb92002-04-12 10:26:32 +00001717/* ---------------------------------------------------------------------
1718 These are here (I think) because they are deemed cancellation
1719 points by POSIX. For the moment we'll simply pass the call along
1720 to the corresponding thread-unaware (?) libc routine.
1721 ------------------------------------------------------------------ */
1722
sewardje663cb92002-04-12 10:26:32 +00001723#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001724#include <sys/types.h>
1725#include <sys/socket.h>
1726
sewardjd529a442002-05-04 19:49:21 +00001727#ifdef GLIBC_2_1
1728extern
1729int __sigaction
1730 (int signum,
1731 const struct sigaction *act,
1732 struct sigaction *oldact);
1733#else
sewardje663cb92002-04-12 10:26:32 +00001734extern
1735int __libc_sigaction
1736 (int signum,
1737 const struct sigaction *act,
1738 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001739#endif
sewardje663cb92002-04-12 10:26:32 +00001740int sigaction(int signum,
1741 const struct sigaction *act,
1742 struct sigaction *oldact)
1743{
sewardjd140e442002-05-29 01:21:19 +00001744 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001745# ifdef GLIBC_2_1
1746 return __sigaction(signum, act, oldact);
1747# else
sewardj45b4b372002-04-16 22:50:32 +00001748 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001749# endif
sewardje663cb92002-04-12 10:26:32 +00001750}
1751
1752
1753extern
1754int __libc_connect(int sockfd,
1755 const struct sockaddr *serv_addr,
1756 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001757__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001758int connect(int sockfd,
1759 const struct sockaddr *serv_addr,
1760 socklen_t addrlen)
1761{
sewardjd140e442002-05-29 01:21:19 +00001762 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001763 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001764}
1765
1766
1767extern
1768int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001769__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001770int fcntl(int fd, int cmd, long arg)
1771{
sewardjd140e442002-05-29 01:21:19 +00001772 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001773 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001774}
1775
1776
1777extern
1778ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001779__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001780ssize_t write(int fd, const void *buf, size_t count)
1781{
sewardjd140e442002-05-29 01:21:19 +00001782 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001783 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001784}
1785
1786
1787extern
1788ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001789__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001790ssize_t read(int fd, void *buf, size_t count)
1791{
sewardjd140e442002-05-29 01:21:19 +00001792 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001793 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001794}
1795
sewardjbe32e452002-04-24 20:29:58 +00001796
1797extern
sewardj853f55d2002-04-26 00:27:53 +00001798int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001799__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001800int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001801{
sewardjd140e442002-05-29 01:21:19 +00001802 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001803 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001804}
1805
sewardje663cb92002-04-12 10:26:32 +00001806
1807extern
sewardj853f55d2002-04-26 00:27:53 +00001808int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001809__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001810int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001811{
sewardjd140e442002-05-29 01:21:19 +00001812 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001813 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001814}
1815
1816
1817extern
1818int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001819__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001820int close(int fd)
1821{
sewardjd140e442002-05-29 01:21:19 +00001822 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001823 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001824}
1825
1826
1827extern
1828int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001829__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001830int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1831{
sewardjd140e442002-05-29 01:21:19 +00001832 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001833 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001834 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001835 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001836}
1837
1838
1839extern
sewardje663cb92002-04-12 10:26:32 +00001840pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001841__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001842pid_t waitpid(pid_t pid, int *status, int options)
1843{
sewardjd140e442002-05-29 01:21:19 +00001844 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001845 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001846}
1847
1848
1849extern
1850int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001851__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001852int nanosleep(const struct timespec *req, struct timespec *rem)
1853{
sewardjd140e442002-05-29 01:21:19 +00001854 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001855 return __libc_nanosleep(req, rem);
1856}
1857
sewardjbe32e452002-04-24 20:29:58 +00001858
sewardje663cb92002-04-12 10:26:32 +00001859extern
1860int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001861__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001862int fsync(int fd)
1863{
sewardjd140e442002-05-29 01:21:19 +00001864 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001865 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001866}
1867
sewardjbe32e452002-04-24 20:29:58 +00001868
sewardj70c75362002-04-13 04:18:32 +00001869extern
1870off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001871__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001872off_t lseek(int fildes, off_t offset, int whence)
1873{
sewardjd140e442002-05-29 01:21:19 +00001874 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001875 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001876}
1877
sewardjbe32e452002-04-24 20:29:58 +00001878
1879extern
1880__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001881__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001882__off64_t lseek64(int fildes, __off64_t offset, int whence)
1883{
sewardjd140e442002-05-29 01:21:19 +00001884 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001885 return __libc_lseek64(fildes, offset, whence);
1886}
1887
1888
sewardj726c4122002-05-16 23:39:10 +00001889extern
1890ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1891 __off64_t __offset);
1892ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1893 __off64_t __offset)
1894{
sewardjd140e442002-05-29 01:21:19 +00001895 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001896 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1897}
1898
1899
sewardja18e2102002-05-18 10:43:22 +00001900extern
1901ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1902 __off64_t __offset);
1903ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1904 __off64_t __offset)
1905{
sewardjd140e442002-05-29 01:21:19 +00001906 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001907 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1908}
1909
sewardj726c4122002-05-16 23:39:10 +00001910
sewardj39b93b12002-05-18 10:56:27 +00001911extern
1912ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1913__attribute__((weak))
1914ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1915{
sewardjd140e442002-05-29 01:21:19 +00001916 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001917 return __libc_pwrite(fd, buf, count, offset);
1918}
1919
1920
1921extern
1922ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1923__attribute__((weak))
1924ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1925{
sewardjd140e442002-05-29 01:21:19 +00001926 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001927 return __libc_pread(fd, buf, count, offset);
1928}
1929
1930
sewardj6af4b5d2002-04-16 04:40:49 +00001931extern
1932void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001933/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001934void longjmp(jmp_buf env, int val)
1935{
1936 __libc_longjmp(env, val);
1937}
1938
sewardjbe32e452002-04-24 20:29:58 +00001939
sewardj436c2db2002-06-18 09:07:54 +00001940extern void __libc_siglongjmp (sigjmp_buf env, int val)
1941 __attribute__ ((noreturn));
1942void siglongjmp(sigjmp_buf env, int val)
1943{
1944 kludged("siglongjmp (cleanup handlers are ignored)");
1945 __libc_siglongjmp(env, val);
1946}
1947
1948
sewardj6af4b5d2002-04-16 04:40:49 +00001949extern
1950int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001951__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001952int send(int s, const void *msg, size_t len, int flags)
1953{
sewardjd140e442002-05-29 01:21:19 +00001954 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001955 return __libc_send(s, msg, len, flags);
1956}
1957
sewardjbe32e452002-04-24 20:29:58 +00001958
sewardj1e8cdc92002-04-18 11:37:52 +00001959extern
1960int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001961__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001962int recv(int s, void *buf, size_t len, int flags)
1963{
sewardjd140e442002-05-29 01:21:19 +00001964 __my_pthread_testcancel();
sewardj1d6b3a22002-06-20 07:58:33 +00001965 wait_for_fd_to_be_readable_or_erring(s);
1966 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001967 return __libc_recv(s, buf, len, flags);
1968}
1969
sewardjbe32e452002-04-24 20:29:58 +00001970
sewardj3665ded2002-05-16 16:57:25 +00001971extern
1972int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1973__attribute__((weak))
1974int sendmsg(int s, const struct msghdr *msg, int flags)
1975{
sewardjd140e442002-05-29 01:21:19 +00001976 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001977 return __libc_sendmsg(s, msg, flags);
1978}
1979
1980
sewardj796d6a22002-04-24 02:28:34 +00001981extern
sewardj59da27a2002-06-06 08:33:54 +00001982int __libc_recvmsg(int s, struct msghdr *msg, int flags);
1983__attribute__((weak))
1984int recvmsg(int s, struct msghdr *msg, int flags)
1985{
1986 __my_pthread_testcancel();
1987 return __libc_recvmsg(s, msg, flags);
1988}
1989
1990
1991extern
sewardj436e0582002-04-26 14:31:40 +00001992int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1993 struct sockaddr *from, socklen_t *fromlen);
1994__attribute__((weak))
1995int recvfrom(int s, void *buf, size_t len, int flags,
1996 struct sockaddr *from, socklen_t *fromlen)
1997{
sewardjd140e442002-05-29 01:21:19 +00001998 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00001999 wait_for_fd_to_be_readable_or_erring(s);
2000 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00002001 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
2002}
2003
2004
2005extern
sewardj796d6a22002-04-24 02:28:34 +00002006int __libc_sendto(int s, const void *msg, size_t len, int flags,
2007 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00002008__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00002009int sendto(int s, const void *msg, size_t len, int flags,
2010 const struct sockaddr *to, socklen_t tolen)
2011{
sewardjd140e442002-05-29 01:21:19 +00002012 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00002013 return __libc_sendto(s, msg, len, flags, to, tolen);
2014}
2015
sewardjbe32e452002-04-24 20:29:58 +00002016
sewardj369b1702002-04-24 13:28:15 +00002017extern
2018int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00002019__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00002020int system(const char* str)
2021{
sewardjd140e442002-05-29 01:21:19 +00002022 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00002023 return __libc_system(str);
2024}
2025
sewardjbe32e452002-04-24 20:29:58 +00002026
sewardjab0b1c32002-04-24 19:26:47 +00002027extern
2028pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00002029__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00002030pid_t wait(int *status)
2031{
sewardjd140e442002-05-29 01:21:19 +00002032 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00002033 return __libc_wait(status);
2034}
2035
sewardj45b4b372002-04-16 22:50:32 +00002036
sewardj67f1d582002-05-24 02:11:32 +00002037extern
2038int __libc_msync(const void *start, size_t length, int flags);
2039__attribute__((weak))
2040int msync(const void *start, size_t length, int flags)
2041{
sewardjd140e442002-05-29 01:21:19 +00002042 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00002043 return __libc_msync(start, length, flags);
2044}
2045
sewardj5905fae2002-04-26 13:25:00 +00002046
sewardj2cb00342002-06-28 01:46:26 +00002047/*--- fork and its helper ---*/
2048
2049static
2050void run_fork_handlers ( int what )
2051{
2052 ForkHandlerEntry entry;
2053 int n_h, n_handlers, i, res;
2054
2055 my_assert(what == 0 || what == 1 || what == 2);
2056
2057 /* Fetch old counter */
2058 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2059 VG_USERREQ__GET_FHSTACK_USED,
2060 0, 0, 0, 0);
2061 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2062
2063 /* Prepare handlers (what == 0) are called in opposite order of
2064 calls to pthread_atfork. Parent and child handlers are called
2065 in the same order as calls to pthread_atfork. */
2066 if (what == 0)
2067 n_h = n_handlers - 1;
2068 else
2069 n_h = 0;
2070
2071 for (i = 0; i < n_handlers; i++) {
2072 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2073 VG_USERREQ__GET_FHSTACK_ENTRY,
2074 n_h, &entry, 0, 0);
2075 my_assert(res == 0);
2076 switch (what) {
2077 case 0: if (entry.prepare) entry.prepare();
2078 n_h--; break;
2079 case 1: if (entry.parent) entry.parent();
2080 n_h++; break;
2081 case 2: if (entry.child) entry.child();
2082 n_h++; break;
2083 default: barf("run_fork_handlers: invalid what");
2084 }
2085 }
2086
2087 if (what != 0 /* prepare */) {
2088 /* Empty out the stack. */
2089 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2090 VG_USERREQ__SET_FHSTACK_USED,
2091 0, 0, 0, 0);
2092 my_assert(res == 0);
2093 }
2094}
2095
2096extern
2097pid_t __libc_fork(void);
2098pid_t __fork(void)
2099{
2100 pid_t pid;
2101 __my_pthread_testcancel();
2102 __pthread_mutex_lock(&pthread_atfork_lock);
2103
2104 run_fork_handlers(0 /* prepare */);
2105 pid = __libc_fork();
2106 if (pid == 0) {
2107 /* I am the child */
2108 run_fork_handlers(2 /* child */);
2109 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2110 } else {
2111 /* I am the parent */
2112 run_fork_handlers(1 /* parent */);
2113 __pthread_mutex_unlock(&pthread_atfork_lock);
2114 }
2115 return pid;
2116}
2117
2118
njn25e49d8e72002-09-23 09:36:25 +00002119pid_t __vfork(void)
2120{
2121 return __fork();
2122}
sewardj2cb00342002-06-28 01:46:26 +00002123
2124
sewardj3b13f0e2002-04-25 20:17:29 +00002125/* ---------------------------------------------------------------------
2126 Nonblocking implementations of select() and poll(). This stuff will
2127 surely rot your mind.
2128 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00002129
sewardj08a4c3f2002-04-13 03:45:44 +00002130/*--------------------------------------------------*/
2131
2132#include "vg_kerneliface.h"
2133
2134static
2135__inline__
2136int is_kerror ( int res )
2137{
2138 if (res >= -4095 && res <= -1)
2139 return 1;
2140 else
2141 return 0;
2142}
2143
2144
2145static
2146int my_do_syscall1 ( int syscallno, int arg1 )
2147{
2148 int __res;
2149 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2150 : "=a" (__res)
2151 : "0" (syscallno),
2152 "d" (arg1) );
2153 return __res;
2154}
2155
2156static
2157int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00002158 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00002159{
2160 int __res;
2161 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2162 : "=a" (__res)
2163 : "0" (syscallno),
2164 "d" (arg1),
2165 "c" (arg2) );
2166 return __res;
2167}
2168
2169static
sewardjf854f472002-04-21 12:19:41 +00002170int my_do_syscall3 ( int syscallno,
2171 int arg1, int arg2, int arg3 )
2172{
2173 int __res;
2174 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
2175 : "=a" (__res)
2176 : "0" (syscallno),
2177 "S" (arg1),
2178 "c" (arg2),
2179 "d" (arg3) );
2180 return __res;
2181}
2182
2183static
sewardj08a4c3f2002-04-13 03:45:44 +00002184int do_syscall_select( int n,
2185 vki_fd_set* readfds,
2186 vki_fd_set* writefds,
2187 vki_fd_set* exceptfds,
2188 struct vki_timeval * timeout )
2189{
2190 int res;
2191 int args[5];
2192 args[0] = n;
2193 args[1] = (int)readfds;
2194 args[2] = (int)writefds;
2195 args[3] = (int)exceptfds;
2196 args[4] = (int)timeout;
2197 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00002198 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00002199}
2200
2201
2202/* This is a wrapper round select(), which makes it thread-safe,
2203 meaning that only this thread will block, rather than the entire
2204 process. This wrapper in turn depends on nanosleep() not to block
2205 the entire process, but I think (hope? suspect?) that POSIX
2206 pthreads guarantees that to be the case.
2207
2208 Basic idea is: modify the timeout parameter to select so that it
2209 returns immediately. Poll like this until select returns non-zero,
2210 indicating something interesting happened, or until our time is up.
njn25e49d8e72002-09-23 09:36:25 +00002211 Space out the polls with nanosleeps of say 11 milliseconds, which
sewardj08a4c3f2002-04-13 03:45:44 +00002212 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00002213
2214 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00002215 * (checked via my_assert) types fd_set and vki_fd_set are identical.
2216 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00002217 * (unchecked) libc error numbers (EINTR etc) are the negation of the
2218 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00002219*/
sewardj08a4c3f2002-04-13 03:45:44 +00002220
sewardj5905fae2002-04-26 13:25:00 +00002221/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00002222int select ( int n,
2223 fd_set *rfds,
2224 fd_set *wfds,
2225 fd_set *xfds,
2226 struct timeval *timeout )
2227{
sewardj5f07b662002-04-23 16:52:51 +00002228 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00002229 int res;
2230 fd_set rfds_copy;
2231 fd_set wfds_copy;
2232 fd_set xfds_copy;
2233 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00002234 struct vki_timeval zero_timeout;
2235 struct vki_timespec nanosleep_interval;
2236
sewardjd140e442002-05-29 01:21:19 +00002237 __my_pthread_testcancel();
2238
sewardj5f07b662002-04-23 16:52:51 +00002239 /* gcc's complains about ms_end being used uninitialised -- classic
2240 case it can't understand, where ms_end is both defined and used
2241 only if timeout != NULL. Hence ... */
2242 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00002243
2244 /* We assume that the kernel and libc data layouts are identical
2245 for the following types. These asserts provide a crude
2246 check. */
2247 if (sizeof(fd_set) != sizeof(vki_fd_set)
2248 || sizeof(struct timeval) != sizeof(struct vki_timeval))
2249 barf("valgrind's hacky non-blocking select(): data sizes error");
2250
sewardj5f07b662002-04-23 16:52:51 +00002251 /* Detect the current time and simultaneously find out if we are
2252 running on Valgrind. */
2253 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2254 VG_USERREQ__READ_MILLISECOND_TIMER,
2255 0, 0, 0, 0);
2256
2257 /* If a zero timeout specified, this call is harmless. Also go
2258 this route if we're not running on Valgrind, for whatever
2259 reason. */
2260 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
2261 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00002262 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00002263 (vki_fd_set*)wfds,
2264 (vki_fd_set*)xfds,
2265 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00002266 if (is_kerror(res)) {
2267 * (__errno_location()) = -res;
2268 return -1;
2269 } else {
2270 return res;
2271 }
2272 }
sewardj08a4c3f2002-04-13 03:45:44 +00002273
sewardj5f07b662002-04-23 16:52:51 +00002274 /* If a timeout was specified, set ms_end to be the end millisecond
2275 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00002276 if (timeout) {
2277 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00002278 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00002279 ms_end = ms_now;
2280 ms_end += (timeout->tv_usec / 1000);
2281 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00002282 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00002283 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00002284 }
2285
2286 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
2287
2288 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00002289 NULL, in which case ms_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002290
sewardj08a4c3f2002-04-13 03:45:44 +00002291 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002292
2293 /* First, do a return-immediately select(). */
sewardj08a4c3f2002-04-13 03:45:44 +00002294
2295 /* These could be trashed each time round the loop, so restore
2296 them each time. */
2297 if (rfds) rfds_copy = *rfds;
2298 if (wfds) wfds_copy = *wfds;
2299 if (xfds) xfds_copy = *xfds;
2300
2301 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
2302
2303 res = do_syscall_select( n,
2304 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
2305 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
2306 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
2307 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00002308 if (is_kerror(res)) {
2309 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00002310 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00002311 * (__errno_location()) = -res;
2312 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00002313 }
2314 if (res > 0) {
2315 /* one or more fds is ready. Copy out resulting sets and
2316 return. */
2317 if (rfds) *rfds = rfds_copy;
2318 if (wfds) *wfds = wfds_copy;
2319 if (xfds) *xfds = xfds_copy;
2320 return res;
2321 }
sewardj05bb2c92002-06-26 00:47:17 +00002322
2323 /* Nothing interesting happened, so we go to sleep for a
2324 while. */
2325
sewardj08a4c3f2002-04-13 03:45:44 +00002326 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
2327 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00002328 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002329 nanosleep_interval.tv_nsec = 11 * 1000 * 1000; /* 11 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00002330 /* It's critical here that valgrind's nanosleep implementation
2331 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00002332 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00002333 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00002334 if (res == -VKI_EINTR) {
2335 /* The nanosleep was interrupted by a signal. So we do the
2336 same. */
2337 * (__errno_location()) = EINTR;
2338 return -1;
2339 }
sewardj05bb2c92002-06-26 00:47:17 +00002340
2341 /* Sleeping finished. If a finite timeout, check to see if it
2342 has expired yet. */
2343 if (timeout) {
2344 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2345 VG_USERREQ__READ_MILLISECOND_TIMER,
2346 0, 0, 0, 0);
2347 my_assert(ms_now != 0xFFFFFFFF);
2348 if (ms_now >= ms_end) {
2349 /* timeout; nothing interesting happened. */
2350 if (rfds) FD_ZERO(rfds);
2351 if (wfds) FD_ZERO(wfds);
2352 if (xfds) FD_ZERO(xfds);
2353 return 0;
2354 }
2355 }
2356
sewardjf854f472002-04-21 12:19:41 +00002357 }
2358}
2359
2360
2361
2362
2363#include <sys/poll.h>
2364
sewardj3e909ce2002-06-03 13:27:15 +00002365#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00002366typedef unsigned long int nfds_t;
2367#endif
2368
sewardj705d3cb2002-05-23 13:13:12 +00002369
sewardj5905fae2002-04-26 13:25:00 +00002370/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00002371int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2372{
sewardj5f07b662002-04-23 16:52:51 +00002373 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00002374 int res, i;
sewardjf854f472002-04-21 12:19:41 +00002375 struct vki_timespec nanosleep_interval;
2376
sewardjd140e442002-05-29 01:21:19 +00002377 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00002378 ensure_valgrind("poll");
2379
sewardj5f07b662002-04-23 16:52:51 +00002380 /* Detect the current time and simultaneously find out if we are
2381 running on Valgrind. */
2382 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2383 VG_USERREQ__READ_MILLISECOND_TIMER,
2384 0, 0, 0, 0);
2385
sewardjf854f472002-04-21 12:19:41 +00002386 if (/* CHECK SIZES FOR struct pollfd */
2387 sizeof(struct timeval) != sizeof(struct vki_timeval))
2388 barf("valgrind's hacky non-blocking poll(): data sizes error");
2389
sewardj5f07b662002-04-23 16:52:51 +00002390 /* dummy initialisation to keep gcc -Wall happy */
2391 ms_end = 0;
2392
2393 /* If a zero timeout specified, this call is harmless. Also do
2394 this if not running on Valgrind. */
2395 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00002396 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
2397 if (is_kerror(res)) {
2398 * (__errno_location()) = -res;
2399 return -1;
2400 } else {
2401 return res;
2402 }
2403 }
2404
sewardj5f07b662002-04-23 16:52:51 +00002405 /* If a timeout was specified, set ms_end to be the end wallclock
2406 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002407 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002408 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002409 }
2410
2411 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2412
2413 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2414 in which case t_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002415
sewardj2d94c112002-06-03 01:25:54 +00002416 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002417
sewardjf854f472002-04-21 12:19:41 +00002418 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002419
2420 /* Do a return-immediately poll. */
2421
2422 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2423 if (is_kerror(res)) {
2424 /* Some kind of error. Set errno and return. */
2425 * (__errno_location()) = -res;
2426 return -1;
2427 }
2428 if (res > 0) {
2429 /* One or more fds is ready. Return now. */
2430 return res;
2431 }
2432
2433 /* Nothing interesting happened, so we go to sleep for a
2434 while. */
2435
2436 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2437 /* nanosleep and go round again */
2438 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002439 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
sewardj05bb2c92002-06-26 00:47:17 +00002440 /* It's critical here that valgrind's nanosleep implementation
2441 is nonblocking. */
2442 (void)my_do_syscall2(__NR_nanosleep,
2443 (int)(&nanosleep_interval), (int)NULL);
2444
2445 /* Sleeping finished. If a finite timeout, check to see if it
2446 has expired yet. */
sewardjf854f472002-04-21 12:19:41 +00002447 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002448 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2449 VG_USERREQ__READ_MILLISECOND_TIMER,
2450 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002451 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002452 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002453 /* timeout; nothing interesting happened. */
2454 for (i = 0; i < __nfds; i++)
2455 __fds[i].revents = 0;
2456 return 0;
2457 }
2458 }
2459
sewardj08a4c3f2002-04-13 03:45:44 +00002460 }
2461}
sewardj3b13f0e2002-04-25 20:17:29 +00002462
2463
sewardj705d3cb2002-05-23 13:13:12 +00002464/* Helper function used to make accept() non-blocking. Idea is to use
2465 the above nonblocking poll() to make this thread ONLY wait for the
2466 specified fd to become ready, and then return. */
sewardjd1c1cf22002-06-26 00:13:36 +00002467
2468/* Sigh -- a hack. We're not supposed to include this file directly;
2469 should do it via /usr/include/fcntl.h, but that introduces a
2470 varargs prototype for fcntl itself, which we can't mimic. */
2471#define _FCNTL_H
2472#include <bits/fcntl.h>
2473
sewardj705d3cb2002-05-23 13:13:12 +00002474static void wait_for_fd_to_be_readable_or_erring ( int fd )
2475{
2476 struct pollfd pfd;
sewardjd1c1cf22002-06-26 00:13:36 +00002477 int res;
2478
sewardj6e6cbaa2002-05-24 02:12:52 +00002479 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardjd1c1cf22002-06-26 00:13:36 +00002480
2481 /* First check to see if the fd is nonblocking, and/or invalid. In
2482 either case return immediately. */
2483 res = __libc_fcntl(fd, F_GETFL, 0);
2484 if (res == -1) return; /* fd is invalid somehow */
2485 if (res & O_NONBLOCK) return; /* fd is nonblocking */
2486
2487 /* Ok, we'd better wait with poll. */
sewardj705d3cb2002-05-23 13:13:12 +00002488 pfd.fd = fd;
2489 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2490 /* ... but not POLLOUT, you may notice. */
2491 pfd.revents = 0;
2492 (void)poll(&pfd, 1, -1 /* forever */);
2493}
2494
2495
sewardj3b13f0e2002-04-25 20:17:29 +00002496/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002497 Hacky implementation of semaphores.
2498 ------------------------------------------------------------------ */
2499
2500#include <semaphore.h>
2501
2502/* This is a terrible way to do the remapping. Plan is to import an
2503 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002504
2505typedef
2506 struct {
2507 pthread_mutex_t se_mx;
2508 pthread_cond_t se_cv;
2509 int count;
2510 }
2511 vg_sem_t;
2512
2513static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2514
2515static int se_remap_used = 0;
2516static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2517static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2518
2519static vg_sem_t* se_remap ( sem_t* orig )
2520{
2521 int res, i;
2522 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002523 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002524
2525 for (i = 0; i < se_remap_used; i++) {
2526 if (se_remap_orig[i] == orig)
2527 break;
2528 }
2529 if (i == se_remap_used) {
2530 if (se_remap_used == VG_N_SEMAPHORES) {
2531 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002532 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002533 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002534 }
2535 se_remap_used++;
2536 se_remap_orig[i] = orig;
2537 /* printf("allocated semaphore %d\n", i); */
2538 }
2539 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002540 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002541 return &se_remap_new[i];
2542}
2543
2544
2545int sem_init(sem_t *sem, int pshared, unsigned int value)
2546{
2547 int res;
2548 vg_sem_t* vg_sem;
2549 ensure_valgrind("sem_init");
2550 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002551 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002552 errno = ENOSYS;
2553 return -1;
2554 }
2555 vg_sem = se_remap(sem);
2556 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002557 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002558 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002559 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002560 vg_sem->count = value;
2561 return 0;
2562}
2563
2564
2565int sem_wait ( sem_t* sem )
2566{
2567 int res;
2568 vg_sem_t* vg_sem;
2569 ensure_valgrind("sem_wait");
2570 vg_sem = se_remap(sem);
2571 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002572 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002573 while (vg_sem->count == 0) {
2574 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002575 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002576 }
2577 vg_sem->count--;
2578 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002579 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002580 return 0;
2581}
2582
2583int sem_post ( sem_t* sem )
2584{
2585 int res;
2586 vg_sem_t* vg_sem;
2587 ensure_valgrind("sem_post");
2588 vg_sem = se_remap(sem);
2589 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002590 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002591 if (vg_sem->count == 0) {
2592 vg_sem->count++;
2593 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002594 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002595 } else {
2596 vg_sem->count++;
2597 }
2598 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002599 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002600 return 0;
2601}
2602
2603
2604int sem_trywait ( sem_t* sem )
2605{
2606 int ret, res;
2607 vg_sem_t* vg_sem;
2608 ensure_valgrind("sem_trywait");
2609 vg_sem = se_remap(sem);
2610 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002611 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002612 if (vg_sem->count > 0) {
2613 vg_sem->count--;
2614 ret = 0;
2615 } else {
2616 ret = -1;
2617 errno = EAGAIN;
2618 }
2619 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002620 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002621 return ret;
2622}
2623
2624
2625int sem_getvalue(sem_t* sem, int * sval)
2626{
2627 vg_sem_t* vg_sem;
2628 ensure_valgrind("sem_trywait");
2629 vg_sem = se_remap(sem);
2630 *sval = vg_sem->count;
2631 return 0;
2632}
2633
2634
2635int sem_destroy(sem_t * sem)
2636{
2637 kludged("sem_destroy");
2638 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2639 return 0;
2640}
2641
sewardj9ad92d92002-10-16 19:45:06 +00002642
2643int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2644{
2645 int res;
2646 vg_sem_t* vg_sem;
2647 ensure_valgrind("sem_timedwait");
2648 vg_sem = se_remap(sem);
2649 res = __pthread_mutex_lock(&vg_sem->se_mx);
2650 my_assert(res == 0);
2651 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
2652 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
2653 }
2654 if ( vg_sem->count > 0 ) {
2655 vg_sem->count--;
2656 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2657 my_assert(res == 0 );
2658 return 0;
2659 } else {
2660 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2661 my_assert(res == 0 );
2662 *(__errno_location()) = ETIMEDOUT;
2663 return -1;
2664 }
2665}
2666
sewardj8f253ff2002-05-19 00:13:34 +00002667
2668/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002669 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002670 ------------------------------------------------------------------ */
2671
sewardj2d8b3f02002-06-01 14:14:19 +00002672typedef
2673 struct {
2674 int initted; /* != 0 --> in use; sanity check only */
2675 int prefer_w; /* != 0 --> prefer writer */
2676 int nwait_r; /* # of waiting readers */
2677 int nwait_w; /* # of waiting writers */
2678 pthread_cond_t cv_r; /* for signalling readers */
2679 pthread_cond_t cv_w; /* for signalling writers */
2680 pthread_mutex_t mx;
2681 int status;
2682 /* allowed range for status: >= -1. -1 means 1 writer currently
2683 active, >= 0 means N readers currently active. */
2684 }
2685 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002686
2687
2688static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2689
2690static int rw_remap_used = 0;
2691static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2692static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2693
sewardj2d8b3f02002-06-01 14:14:19 +00002694
2695static
2696void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2697{
2698 int res = 0;
2699 vg_rwl->initted = 1;
2700 vg_rwl->prefer_w = 1;
2701 vg_rwl->nwait_r = 0;
2702 vg_rwl->nwait_w = 0;
2703 vg_rwl->status = 0;
2704 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2705 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2706 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002707 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002708}
2709
2710
sewardja1ac5cb2002-05-27 13:00:05 +00002711/* Take the address of a LinuxThreads rwlock_t and return the shadow
2712 address of our version. Further, if the LinuxThreads version
2713 appears to have been statically initialised, do the same to the one
2714 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2715 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2716 uninitialised and non-zero meaning initialised.
2717*/
2718static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2719{
2720 int res, i;
2721 vg_rwlock_t* vg_rwl;
2722 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002723 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002724
2725 for (i = 0; i < rw_remap_used; i++) {
2726 if (rw_remap_orig[i] == orig)
2727 break;
2728 }
2729 if (i == rw_remap_used) {
2730 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002731 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002732 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002733 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2734 }
2735 rw_remap_used++;
2736 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002737 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002738 if (0) printf("allocated rwlock %d\n", i);
2739 }
2740 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002741 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002742 vg_rwl = &rw_remap_new[i];
2743
sewardj2d8b3f02002-06-01 14:14:19 +00002744 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002745 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002746 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002747 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002748 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002749 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002750 }
2751
2752 return vg_rwl;
2753}
2754
2755
sewardja1ac5cb2002-05-27 13:00:05 +00002756int pthread_rwlock_init ( pthread_rwlock_t* orig,
2757 const pthread_rwlockattr_t* attr )
2758{
sewardja1ac5cb2002-05-27 13:00:05 +00002759 vg_rwlock_t* rwl;
2760 if (0) printf ("pthread_rwlock_init\n");
2761 /* Force the remapper to initialise the shadow. */
2762 orig->__rw_readers = 0;
2763 /* Install the lock preference; the remapper needs to know it. */
2764 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2765 if (attr)
2766 orig->__rw_kind = attr->__lockkind;
2767 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002768 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002769}
2770
sewardj2d8b3f02002-06-01 14:14:19 +00002771
2772static
2773void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002774{
sewardj2d8b3f02002-06-01 14:14:19 +00002775 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2776 rwl->nwait_r--;
2777 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002778}
2779
sewardj2d8b3f02002-06-01 14:14:19 +00002780
sewardja1ac5cb2002-05-27 13:00:05 +00002781int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2782{
2783 int res;
2784 vg_rwlock_t* rwl;
2785 if (0) printf ("pthread_rwlock_rdlock\n");
2786 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002787 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002788 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002789 if (!rwl->initted) {
2790 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002791 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002792 return EINVAL;
2793 }
2794 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002795 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002796 rwl->nwait_r++;
2797 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2798 while (1) {
2799 if (rwl->status == 0) break;
2800 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002801 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002802 }
2803 pthread_cleanup_pop(0);
2804 rwl->nwait_r--;
2805 }
sewardj2d94c112002-06-03 01:25:54 +00002806 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002807 rwl->status++;
2808 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002809 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002810 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002811}
2812
sewardj2d8b3f02002-06-01 14:14:19 +00002813
sewardja1ac5cb2002-05-27 13:00:05 +00002814int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2815{
2816 int res;
2817 vg_rwlock_t* rwl;
2818 if (0) printf ("pthread_rwlock_tryrdlock\n");
2819 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002820 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002821 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002822 if (!rwl->initted) {
2823 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002824 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002825 return EINVAL;
2826 }
2827 if (rwl->status == -1) {
2828 /* Writer active; we have to give up. */
2829 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002830 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002831 return EBUSY;
2832 }
2833 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002834 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002835 rwl->status++;
2836 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002837 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002838 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002839}
2840
sewardj2d8b3f02002-06-01 14:14:19 +00002841
2842static
2843void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2844{
2845 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2846 rwl->nwait_w--;
2847 pthread_mutex_unlock (&rwl->mx);
2848}
2849
2850
sewardja1ac5cb2002-05-27 13:00:05 +00002851int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2852{
2853 int res;
2854 vg_rwlock_t* rwl;
2855 if (0) printf ("pthread_rwlock_wrlock\n");
2856 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002857 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002858 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002859 if (!rwl->initted) {
2860 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002861 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002862 return EINVAL;
2863 }
2864 if (rwl->status != 0) {
2865 rwl->nwait_w++;
2866 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2867 while (1) {
2868 if (rwl->status == 0) break;
2869 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002870 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002871 }
2872 pthread_cleanup_pop(0);
2873 rwl->nwait_w--;
2874 }
sewardj2d94c112002-06-03 01:25:54 +00002875 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002876 rwl->status = -1;
2877 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002878 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002879 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002880}
2881
sewardj2d8b3f02002-06-01 14:14:19 +00002882
sewardja1ac5cb2002-05-27 13:00:05 +00002883int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2884{
2885 int res;
2886 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002887 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002888 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002889 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002890 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002891 if (!rwl->initted) {
2892 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002893 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002894 return EINVAL;
2895 }
2896 if (rwl->status != 0) {
2897 /* Reader(s) or a writer active; we have to give up. */
2898 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002899 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002900 return EBUSY;
2901 }
2902 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002903 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002904 rwl->status = -1;
2905 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002906 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002907 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002908}
2909
sewardj2d8b3f02002-06-01 14:14:19 +00002910
sewardja1ac5cb2002-05-27 13:00:05 +00002911int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2912{
2913 int res;
2914 vg_rwlock_t* rwl;
2915 if (0) printf ("pthread_rwlock_unlock\n");
2916 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002917 rwl = rw_remap ( orig );
2918 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002919 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002920 if (!rwl->initted) {
2921 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002922 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002923 return EINVAL;
2924 }
2925 if (rwl->status == 0) {
2926 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002927 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002928 return EPERM;
2929 }
sewardj2d94c112002-06-03 01:25:54 +00002930 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002931 if (rwl->status == -1) {
2932 rwl->status = 0;
2933 } else {
sewardj2d94c112002-06-03 01:25:54 +00002934 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002935 rwl->status--;
2936 }
2937
sewardj2d94c112002-06-03 01:25:54 +00002938 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002939
2940 if (rwl->prefer_w) {
2941
2942 /* Favour waiting writers, if any. */
2943 if (rwl->nwait_w > 0) {
2944 /* Writer(s) are waiting. */
2945 if (rwl->status == 0) {
2946 /* We can let a writer in. */
2947 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002948 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002949 } else {
2950 /* There are still readers active. Do nothing; eventually
2951 they will disappear, at which point a writer will be
2952 admitted. */
2953 }
2954 }
2955 else
2956 /* No waiting writers. */
2957 if (rwl->nwait_r > 0) {
2958 /* Let in a waiting reader. */
2959 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002960 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002961 }
2962
2963 } else {
2964
2965 /* Favour waiting readers, if any. */
2966 if (rwl->nwait_r > 0) {
2967 /* Reader(s) are waiting; let one in. */
2968 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002969 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002970 }
2971 else
2972 /* No waiting readers. */
2973 if (rwl->nwait_w > 0 && rwl->status == 0) {
2974 /* We have waiting writers and no active readers; let a
2975 writer in. */
2976 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002977 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002978 }
2979 }
2980
2981 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002982 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002983 return 0;
2984}
2985
2986
2987int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2988{
2989 int res;
2990 vg_rwlock_t* rwl;
2991 if (0) printf ("pthread_rwlock_destroy\n");
2992 rwl = rw_remap ( orig );
2993 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002994 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002995 if (!rwl->initted) {
2996 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002997 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002998 return EINVAL;
2999 }
3000 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
3001 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003002 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003003 return EBUSY;
3004 }
3005 rwl->initted = 0;
3006 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003007 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003008 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003009}
3010
3011
sewardj47e4e312002-06-18 09:24:34 +00003012/* Copied directly from LinuxThreads. */
3013int
3014pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
3015{
3016 attr->__lockkind = 0;
3017 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
3018
3019 return 0;
3020}
3021
sewardjfe18eb82002-07-13 12:58:44 +00003022/* Copied directly from LinuxThreads. */
3023int
3024pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
3025{
3026 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
3027 return EINVAL;
3028
3029 /* For now it is not possible to shared a conditional variable. */
3030 if (pshared != PTHREAD_PROCESS_PRIVATE)
3031 return ENOSYS;
3032
3033 attr->__pshared = pshared;
3034
3035 return 0;
3036}
3037
sewardj47e4e312002-06-18 09:24:34 +00003038
sewardja1ac5cb2002-05-27 13:00:05 +00003039/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00003040 B'stard.
3041 ------------------------------------------------------------------ */
3042
3043# define strong_alias(name, aliasname) \
3044 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
3045
sewardj5905fae2002-04-26 13:25:00 +00003046# define weak_alias(name, aliasname) \
3047 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00003048
sewardj5905fae2002-04-26 13:25:00 +00003049strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
3050strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
3051strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
3052strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
3053 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
3054strong_alias(__pthread_mutex_init, pthread_mutex_init)
3055strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
3056strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
3057strong_alias(__pthread_once, pthread_once)
3058strong_alias(__pthread_atfork, pthread_atfork)
3059strong_alias(__pthread_key_create, pthread_key_create)
3060strong_alias(__pthread_getspecific, pthread_getspecific)
3061strong_alias(__pthread_setspecific, pthread_setspecific)
3062
sewardjd529a442002-05-04 19:49:21 +00003063#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00003064strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00003065#endif
3066
sewardj5905fae2002-04-26 13:25:00 +00003067strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00003068strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00003069strong_alias(lseek, __lseek)
3070strong_alias(open, __open)
3071strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00003072strong_alias(read, __read)
3073strong_alias(wait, __wait)
3074strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00003075strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00003076strong_alias(send, __send)
sewardj3fd559e2002-10-20 16:24:04 +00003077strong_alias(poll, __poll)
3078strong_alias(select, __select)
sewardj5905fae2002-04-26 13:25:00 +00003079
sewardj726c4122002-05-16 23:39:10 +00003080weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00003081weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00003082weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00003083weak_alias(__vfork, vfork)
sewardj7f6456d2002-05-21 00:51:21 +00003084
sewardjf0b06452002-06-04 08:38:04 +00003085weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00003086
3087/*--------------------------------------------------*/
3088
sewardj5905fae2002-04-26 13:25:00 +00003089weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00003090weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00003091weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00003092
sewardja1ac5cb2002-05-27 13:00:05 +00003093weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
3094weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
3095weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
3096weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
3097
sewardj060b04f2002-04-26 21:01:13 +00003098
sewardj3b13f0e2002-04-25 20:17:29 +00003099/* I've no idea what these are, but they get called quite a lot.
3100 Anybody know? */
3101
3102#undef _IO_flockfile
3103void _IO_flockfile ( _IO_FILE * file )
3104{
sewardj853f55d2002-04-26 00:27:53 +00003105 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003106}
sewardj5905fae2002-04-26 13:25:00 +00003107weak_alias(_IO_flockfile, flockfile);
3108
sewardj3b13f0e2002-04-25 20:17:29 +00003109
3110#undef _IO_funlockfile
3111void _IO_funlockfile ( _IO_FILE * file )
3112{
sewardj853f55d2002-04-26 00:27:53 +00003113 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003114}
sewardj5905fae2002-04-26 13:25:00 +00003115weak_alias(_IO_funlockfile, funlockfile);
3116
sewardj3b13f0e2002-04-25 20:17:29 +00003117
sewardjd4f2c712002-04-30 10:20:10 +00003118/* This doesn't seem to be needed to simulate libpthread.so's external
3119 interface, but many people complain about its absence. */
3120
3121strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
3122weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00003123
3124
3125/*--------------------------------------------------------------------*/
3126/*--- end vg_libpthread.c ---*/
3127/*--------------------------------------------------------------------*/