blob: 517aec11451db4dde04cb0b223170b5a964683aa [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{
sewardj69a72a52002-11-03 13:41:41 +0000162 int res;
163 char buf[1000];
sewardje663cb92002-04-12 10:26:32 +0000164 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000165 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000166 strcat(buf, str);
167 strcat(buf, "\n\n");
sewardj69a72a52002-11-03 13:41:41 +0000168 VALGRIND_MAGIC_SEQUENCE(res, 0, /* irrelevant default */
169 VG_USERREQ__LOGMESSAGE, buf, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000170 my_exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000171 /* We have to persuade gcc into believing this doesn't return. */
172 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000173}
174
175
sewardj69a72a52002-11-03 13:41:41 +0000176static void cat_n_send ( char* pre, char* msg )
sewardj2a3d28c2002-04-14 13:27:00 +0000177{
sewardj69a72a52002-11-03 13:41:41 +0000178 char buf[1000];
179 int res;
sewardj436e0582002-04-26 14:31:40 +0000180 if (get_pt_trace_level() >= 0) {
sewardj69a72a52002-11-03 13:41:41 +0000181 snprintf(buf, sizeof(buf), "%s%s", pre, msg );
182 buf[sizeof(buf)-1] = '\0';
183 VALGRIND_MAGIC_SEQUENCE(res, 0, /* irrelevant default */
184 VG_USERREQ__LOGMESSAGE, buf, 0, 0, 0);
sewardj45b4b372002-04-16 22:50:32 +0000185 }
sewardj2a3d28c2002-04-14 13:27:00 +0000186}
187
sewardj69a72a52002-11-03 13:41:41 +0000188static void ignored ( char* msg )
189{
190 cat_n_send ( "valgrind's libpthread.so: IGNORED call to: ", msg );
191}
192
193
sewardj30671ff2002-04-21 00:13:57 +0000194static void kludged ( char* msg )
195{
sewardj69a72a52002-11-03 13:41:41 +0000196 cat_n_send ( "valgrind's libpthread.so: KLUDGED call to: ", msg );
sewardj439d45e2002-05-03 20:43:10 +0000197}
198
sewardj69a72a52002-11-03 13:41:41 +0000199
sewardj439d45e2002-05-03 20:43:10 +0000200static void not_inside ( char* msg )
201{
sewardj68b2dd92002-05-10 21:03:56 +0000202 VG_(startup)();
sewardj30671ff2002-04-21 00:13:57 +0000203}
204
sewardjccef2e62002-05-29 19:26:32 +0000205__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000206void vgPlain_unimp ( char* what )
207{
sewardj69a72a52002-11-03 13:41:41 +0000208 cat_n_send (
209 "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ", what );
sewardj3b13f0e2002-04-25 20:17:29 +0000210 barf("Please report this bug to me at: jseward@acm.org");
211}
212
sewardje663cb92002-04-12 10:26:32 +0000213
sewardj457cc472002-06-03 23:13:47 +0000214static
sewardj2d94c112002-06-03 01:25:54 +0000215void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
216{
sewardj69a72a52002-11-03 13:41:41 +0000217 char buf[1000];
sewardj2d94c112002-06-03 01:25:54 +0000218 static Bool entered = False;
219 if (entered)
220 my_exit(2);
221 entered = True;
sewardj69a72a52002-11-03 13:41:41 +0000222 sprintf(buf, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
223 "valgrind", file, line, fn, expr );
224 cat_n_send ( "", buf );
225 sprintf(buf, "Please report this bug to me at: %s\n\n",
226 VG_EMAIL_ADDR);
227 cat_n_send ( "", buf );
sewardj2d94c112002-06-03 01:25:54 +0000228 my_exit(1);
229}
230
231#define MY__STRING(__str) #__str
232
233#define my_assert(expr) \
234 ((void) ((expr) ? 0 : \
235 (my_assert_fail (MY__STRING(expr), \
236 __FILE__, __LINE__, \
237 __PRETTY_FUNCTION__), 0)))
238
sewardj00a66b12002-10-12 16:42:35 +0000239static
240void my_free ( void* ptr )
241{
242 int res;
243 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
244 VG_USERREQ__FREE, ptr, 0, 0, 0);
245 my_assert(res == 0);
246}
247
248
249static
250void* my_malloc ( int nbytes )
251{
252 void* res;
253 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
254 VG_USERREQ__MALLOC, nbytes, 0, 0, 0);
255 my_assert(res != (void*)0);
256 return res;
257}
258
259
sewardj2d94c112002-06-03 01:25:54 +0000260
sewardje663cb92002-04-12 10:26:32 +0000261/* ---------------------------------------------------------------------
262 Pass pthread_ calls to Valgrind's request mechanism.
263 ------------------------------------------------------------------ */
264
sewardjf8f819e2002-04-17 23:21:37 +0000265#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000266#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000267
sewardja1ac5cb2002-05-27 13:00:05 +0000268
sewardjf8f819e2002-04-17 23:21:37 +0000269/* ---------------------------------------------------
sewardj4dced352002-06-04 22:54:20 +0000270 Ummm ..
271 ------------------------------------------------ */
272
273static
274void pthread_error ( const char* msg )
275{
276 int res;
277 VALGRIND_MAGIC_SEQUENCE(res, 0,
278 VG_USERREQ__PTHREAD_ERROR,
279 msg, 0, 0, 0);
280}
281
282
283/* ---------------------------------------------------
sewardj00a66b12002-10-12 16:42:35 +0000284 Here so it can be inlined without complaint.
285 ------------------------------------------------ */
286
287__inline__
288pthread_t pthread_self(void)
289{
290 int tid;
291 ensure_valgrind("pthread_self");
292 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
293 VG_USERREQ__PTHREAD_GET_THREADID,
294 0, 0, 0, 0);
295 if (tid < 1 || tid >= VG_N_THREADS)
296 barf("pthread_self: invalid ThreadId");
297 return tid;
298}
299
300
301/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000302 THREAD ATTRIBUTES
303 ------------------------------------------------ */
304
sewardj6af4b5d2002-04-16 04:40:49 +0000305int pthread_attr_init(pthread_attr_t *attr)
306{
sewardj7989d0c2002-05-28 11:00:01 +0000307 /* Just initialise the fields which we might look at. */
308 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj111b14c2002-10-20 16:22:57 +0000309 /* Linuxthreads sets this field to the value __getpagesize(), so I
310 guess the following is OK. */
311 attr->__guardsize = VKI_BYTES_PER_PAGE; return 0;
sewardj6af4b5d2002-04-16 04:40:49 +0000312}
313
314int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
315{
sewardj7989d0c2002-05-28 11:00:01 +0000316 if (detachstate != PTHREAD_CREATE_JOINABLE
sewardj4dced352002-06-04 22:54:20 +0000317 && detachstate != PTHREAD_CREATE_DETACHED) {
318 pthread_error("pthread_attr_setdetachstate: "
319 "detachstate is invalid");
sewardj7989d0c2002-05-28 11:00:01 +0000320 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000321 }
sewardj7989d0c2002-05-28 11:00:01 +0000322 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000323 return 0;
324}
325
njn25e49d8e72002-09-23 09:36:25 +0000326int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
327{
328 *detachstate = attr->__detachstate;
329 return 0;
330}
331
sewardj30671ff2002-04-21 00:13:57 +0000332int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
333{
sewardj436e0582002-04-26 14:31:40 +0000334 static int moans = N_MOANS;
335 if (moans-- > 0)
336 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000337 return 0;
338}
sewardj6af4b5d2002-04-16 04:40:49 +0000339
sewardj0286dd52002-05-16 20:51:15 +0000340__attribute__((weak))
341int pthread_attr_setstacksize (pthread_attr_t *__attr,
342 size_t __stacksize)
343{
sewardja18e2102002-05-18 10:43:22 +0000344 size_t limit;
sewardj3d7c8d62002-06-04 20:59:16 +0000345 char buf[1024];
sewardj0286dd52002-05-16 20:51:15 +0000346 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000347 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
348 - 1000; /* paranoia */
349 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000350 return 0;
sewardj3d7c8d62002-06-04 20:59:16 +0000351 snprintf(buf, sizeof(buf), "pthread_attr_setstacksize: "
352 "requested size %d >= VG_PTHREAD_STACK_SIZE\n "
353 "edit vg_include.h and rebuild.", __stacksize);
354 buf[sizeof(buf)-1] = '\0'; /* Make sure it is zero terminated */
355 barf(buf);
sewardj0286dd52002-05-16 20:51:15 +0000356}
357
358
sewardj30671ff2002-04-21 00:13:57 +0000359/* This is completely bogus. */
360int pthread_attr_getschedparam(const pthread_attr_t *attr,
361 struct sched_param *param)
362{
sewardj436e0582002-04-26 14:31:40 +0000363 static int moans = N_MOANS;
364 if (moans-- > 0)
365 kludged("pthread_attr_getschedparam");
sewardj3e909ce2002-06-03 13:27:15 +0000366# ifdef HAVE_SCHED_PRIORITY
sewardj72d58482002-04-24 02:20:20 +0000367 if (param) param->sched_priority = 0; /* who knows */
368# else
sewardj30671ff2002-04-21 00:13:57 +0000369 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000370# endif
sewardj30671ff2002-04-21 00:13:57 +0000371 return 0;
372}
373
374int pthread_attr_setschedparam(pthread_attr_t *attr,
375 const struct sched_param *param)
376{
sewardj436e0582002-04-26 14:31:40 +0000377 static int moans = N_MOANS;
378 if (moans-- > 0)
379 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000380 return 0;
381}
382
383int pthread_attr_destroy(pthread_attr_t *attr)
384{
sewardj436e0582002-04-26 14:31:40 +0000385 static int moans = N_MOANS;
386 if (moans-- > 0)
387 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000388 return 0;
389}
sewardjf8f819e2002-04-17 23:21:37 +0000390
sewardj0d844232002-06-02 09:29:31 +0000391/* These are no-ops, as with LinuxThreads. */
392int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
393{
394 ensure_valgrind("pthread_attr_setscope");
395 if (scope == PTHREAD_SCOPE_SYSTEM)
396 return 0;
sewardj4dced352002-06-04 22:54:20 +0000397 pthread_error("pthread_attr_setscope: "
398 "invalid or unsupported scope");
sewardj0d844232002-06-02 09:29:31 +0000399 if (scope == PTHREAD_SCOPE_PROCESS)
400 return ENOTSUP;
401 return EINVAL;
402}
403
404int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
405{
406 ensure_valgrind("pthread_attr_setscope");
407 if (scope)
408 *scope = PTHREAD_SCOPE_SYSTEM;
409 return 0;
410}
411
sewardj64039bb2002-06-03 00:58:18 +0000412
413/* Pretty bogus. Avoid if possible. */
414int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
415{
416 int detached;
417 size_t limit;
418 ensure_valgrind("pthread_getattr_np");
419 kludged("pthread_getattr_np");
420 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
421 - 1000; /* paranoia */
422 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
423 attr->__schedpolicy = SCHED_OTHER;
424 attr->__schedparam.sched_priority = 0;
425 attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
426 attr->__scope = PTHREAD_SCOPE_SYSTEM;
427 attr->__guardsize = VKI_BYTES_PER_PAGE;
428 attr->__stackaddr = NULL;
429 attr->__stackaddr_set = 0;
430 attr->__stacksize = limit;
431 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
432 VG_USERREQ__SET_OR_GET_DETACH,
433 2 /* get */, thread, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000434 my_assert(detached == 0 || detached == 1);
sewardj64039bb2002-06-03 00:58:18 +0000435 if (detached)
436 attr->__detachstate = PTHREAD_CREATE_DETACHED;
437 return 0;
438}
439
440
441/* Bogus ... */
sewardj111b14c2002-10-20 16:22:57 +0000442__attribute__((weak))
sewardj64039bb2002-06-03 00:58:18 +0000443int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
444 void ** stackaddr )
445{
446 ensure_valgrind("pthread_attr_getstackaddr");
447 kludged("pthread_attr_getstackaddr");
448 if (stackaddr)
449 *stackaddr = NULL;
450 return 0;
451}
452
453/* Not bogus (!) */
sewardj111b14c2002-10-20 16:22:57 +0000454__attribute__((weak))
sewardj64039bb2002-06-03 00:58:18 +0000455int pthread_attr_getstacksize ( const pthread_attr_t * _attr,
456 size_t * __stacksize )
457{
458 size_t limit;
459 ensure_valgrind("pthread_attr_getstacksize");
460 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
461 - 1000; /* paranoia */
462 if (__stacksize)
463 *__stacksize = limit;
464 return 0;
465}
466
sewardja3be12f2002-06-17 12:19:44 +0000467int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
468{
469 if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
470 return EINVAL;
471 attr->__schedpolicy = policy;
472 return 0;
473}
474
475int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
476{
477 *policy = attr->__schedpolicy;
478 return 0;
479}
480
481
sewardj111b14c2002-10-20 16:22:57 +0000482/* This is completely bogus. We reject all attempts to change it from
483 VKI_BYTES_PER_PAGE. I don't have a clue what it's for so it seems
484 safest to be paranoid. */
485__attribute__((weak))
486int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
487{
488 static int moans = N_MOANS;
489
490 if (guardsize == VKI_BYTES_PER_PAGE)
491 return 0;
492
493 if (moans-- > 0)
494 ignored("pthread_attr_setguardsize: ignoring guardsize != 4096");
495
496 return 0;
497}
498
499/* A straight copy of the LinuxThreads code. */
500__attribute__((weak))
501int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
502{
503 *guardsize = attr->__guardsize;
504 return 0;
505}
506
507
sewardj20917d82002-05-28 01:36:45 +0000508/* ---------------------------------------------------
509 Helper functions for running a thread
510 and for clearing up afterwards.
511 ------------------------------------------------ */
512
513/* All exiting threads eventually pass through here, bearing the
514 return value, or PTHREAD_CANCELED, in ret_val. */
515static
516__attribute__((noreturn))
517void thread_exit_wrapper ( void* ret_val )
518{
sewardj870497a2002-05-29 01:06:47 +0000519 int detached, res;
520 CleanupEntry cu;
521 pthread_key_t key;
sewardj00a66b12002-10-12 16:42:35 +0000522 void** specifics_ptr;
sewardj870497a2002-05-29 01:06:47 +0000523
sewardj20917d82002-05-28 01:36:45 +0000524 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000525 while (1) {
526 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
527 VG_USERREQ__CLEANUP_POP,
528 &cu, 0, 0, 0);
529 if (res == -1) break; /* stack empty */
sewardj2d94c112002-06-03 01:25:54 +0000530 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000531 if (0) printf("running exit cleanup handler");
532 cu.fn ( cu.arg );
533 }
534
sewardj870497a2002-05-29 01:06:47 +0000535 /* Run this thread's key finalizers. Really this should be run
536 PTHREAD_DESTRUCTOR_ITERATIONS times. */
537 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
538 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
539 VG_USERREQ__GET_KEY_D_AND_S,
540 key, &cu, 0, 0 );
541 if (res == 0) {
542 /* valid key */
543 if (cu.fn && cu.arg)
544 cu.fn /* destructor for key */
545 ( cu.arg /* specific for key for this thread */ );
546 continue;
547 }
sewardj2d94c112002-06-03 01:25:54 +0000548 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000549 }
sewardj20917d82002-05-28 01:36:45 +0000550
sewardj00a66b12002-10-12 16:42:35 +0000551 /* Free up my specifics space, if any. */
552 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
553 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
554 pthread_self(), 0, 0, 0);
555 my_assert(specifics_ptr != (void**)3);
556 my_assert(specifics_ptr != (void**)1); /* 1 means invalid thread */
557 if (specifics_ptr != NULL)
558 my_free(specifics_ptr);
559
sewardj20917d82002-05-28 01:36:45 +0000560 /* Decide on my final disposition. */
561 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
562 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000563 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000564 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000565
566 if (detached) {
567 /* Detached; I just quit right now. */
568 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
569 VG_USERREQ__QUIT, 0, 0, 0, 0);
570 } else {
571 /* Not detached; so I wait for a joiner. */
572 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
573 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
574 }
575 /* NOTREACHED */
576 barf("thread_exit_wrapper: still alive?!");
577}
578
579
580/* This function is a wrapper function for running a thread. It runs
581 the root function specified in pthread_create, and then, should the
582 root function return a value, it arranges to run the thread's
583 cleanup handlers and exit correctly. */
584
sewardj728a5272002-06-20 10:25:37 +0000585/* Struct used to convey info from pthread_create to thread_wrapper.
586 Must be careful not to pass to the child thread any pointers to
587 objects which might be on the parent's stack. */
sewardj20917d82002-05-28 01:36:45 +0000588typedef
589 struct {
sewardj728a5272002-06-20 10:25:37 +0000590 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000591 void* (*root_fn) ( void* );
592 void* arg;
593 }
594 NewThreadInfo;
595
596
597/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
598 not return. Note that this runs in the new thread, not the
599 parent. */
600static
601__attribute__((noreturn))
602void thread_wrapper ( NewThreadInfo* info )
603{
sewardj728a5272002-06-20 10:25:37 +0000604 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000605 void* (*root_fn) ( void* );
606 void* arg;
607 void* ret_val;
608
sewardj728a5272002-06-20 10:25:37 +0000609 attr__detachstate = info->attr__detachstate;
610 root_fn = info->root_fn;
611 arg = info->arg;
sewardj20917d82002-05-28 01:36:45 +0000612
sewardj20917d82002-05-28 01:36:45 +0000613 /* Free up the arg block that pthread_create malloced. */
sewardj00a66b12002-10-12 16:42:35 +0000614 my_free(info);
sewardj20917d82002-05-28 01:36:45 +0000615
sewardj7989d0c2002-05-28 11:00:01 +0000616 /* Minimally observe the attributes supplied. */
sewardj728a5272002-06-20 10:25:37 +0000617 if (attr__detachstate != PTHREAD_CREATE_DETACHED
618 && attr__detachstate != PTHREAD_CREATE_JOINABLE)
619 pthread_error("thread_wrapper: invalid attr->__detachstate");
620 if (attr__detachstate == PTHREAD_CREATE_DETACHED)
621 pthread_detach(pthread_self());
sewardj7989d0c2002-05-28 11:00:01 +0000622
sewardj00a66b12002-10-12 16:42:35 +0000623# ifdef GLIBC_2_3
624 /* Set this thread's locale to the global (default) locale. A hack
625 in support of glibc-2.3. This does the biz for the all new
626 threads; the root thread is done with a horrible hack in
627 init_libc_tsd_keys() below.
628 */
629 __uselocale(LC_GLOBAL_LOCALE);
630# endif
631
sewardj20917d82002-05-28 01:36:45 +0000632 /* The root function might not return. But if it does we simply
633 move along to thread_exit_wrapper. All other ways out for the
634 thread (cancellation, or calling pthread_exit) lead there
635 too. */
636 ret_val = root_fn(arg);
637 thread_exit_wrapper(ret_val);
638 /* NOTREACHED */
639}
640
641
sewardjf8f819e2002-04-17 23:21:37 +0000642/* ---------------------------------------------------
643 THREADs
644 ------------------------------------------------ */
645
sewardjff42d1d2002-05-22 13:17:31 +0000646__attribute__((weak))
647int pthread_yield ( void )
648{
649 int res;
650 ensure_valgrind("pthread_yield");
651 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
652 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
653 return 0;
654}
655
656
sewardj6072c362002-04-19 14:40:57 +0000657int pthread_equal(pthread_t thread1, pthread_t thread2)
658{
659 return thread1 == thread2 ? 1 : 0;
660}
661
662
sewardj20917d82002-05-28 01:36:45 +0000663/* Bundle up the args into a malloc'd block and create a new thread
664 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000665int
sewardj1462c8b2002-07-24 09:41:52 +0000666pthread_create (pthread_t *__restrict __thredd,
sewardje663cb92002-04-12 10:26:32 +0000667 __const pthread_attr_t *__restrict __attr,
668 void *(*__start_routine) (void *),
669 void *__restrict __arg)
670{
sewardj20917d82002-05-28 01:36:45 +0000671 int tid_child;
672 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000673
sewardj20917d82002-05-28 01:36:45 +0000674 ensure_valgrind("pthread_create");
675
sewardj00a66b12002-10-12 16:42:35 +0000676 /* make sure the tsd keys, and hence locale info, are initialised
677 before we get into complications making new threads. */
678 init_libc_tsd_keys();
679
sewardj20917d82002-05-28 01:36:45 +0000680 /* Allocate space for the arg block. thread_wrapper will free
681 it. */
sewardj00a66b12002-10-12 16:42:35 +0000682 info = my_malloc(sizeof(NewThreadInfo));
sewardj2d94c112002-06-03 01:25:54 +0000683 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000684
sewardj728a5272002-06-20 10:25:37 +0000685 if (__attr)
686 info->attr__detachstate = __attr->__detachstate;
687 else
688 info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
689
sewardj20917d82002-05-28 01:36:45 +0000690 info->root_fn = __start_routine;
691 info->arg = __arg;
692 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
693 VG_USERREQ__APPLY_IN_NEW_THREAD,
694 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000695 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000696
sewardj1462c8b2002-07-24 09:41:52 +0000697 if (__thredd)
698 *__thredd = tid_child;
sewardj20917d82002-05-28 01:36:45 +0000699 return 0; /* success */
700}
sewardje663cb92002-04-12 10:26:32 +0000701
702
703int
704pthread_join (pthread_t __th, void **__thread_return)
705{
706 int res;
707 ensure_valgrind("pthread_join");
708 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
709 VG_USERREQ__PTHREAD_JOIN,
710 __th, __thread_return, 0, 0);
711 return res;
712}
713
714
sewardj3b5d8862002-04-20 13:53:23 +0000715void pthread_exit(void *retval)
716{
sewardj3b5d8862002-04-20 13:53:23 +0000717 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000718 /* Simple! */
719 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000720}
721
sewardje663cb92002-04-12 10:26:32 +0000722
sewardj853f55d2002-04-26 00:27:53 +0000723int pthread_detach(pthread_t th)
724{
sewardj20917d82002-05-28 01:36:45 +0000725 int res;
726 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000727 /* First we enquire as to the current detach state. */
728 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000729 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000730 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000731 if (res == -1) {
732 /* not found */
733 pthread_error("pthread_detach: "
734 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000735 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000736 }
737 if (res == 1) {
738 /* already detached */
739 pthread_error("pthread_detach: "
740 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000741 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000742 }
sewardj7989d0c2002-05-28 11:00:01 +0000743 if (res == 0) {
744 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
745 VG_USERREQ__SET_OR_GET_DETACH,
746 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000747 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000748 return 0;
749 }
750 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000751}
752
753
sewardjf8f819e2002-04-17 23:21:37 +0000754/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000755 CLEANUP STACKS
756 ------------------------------------------------ */
757
758void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
759 void (*__routine) (void *),
760 void *__arg)
761{
762 int res;
763 CleanupEntry cu;
764 ensure_valgrind("_pthread_cleanup_push");
765 cu.fn = __routine;
766 cu.arg = __arg;
767 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
768 VG_USERREQ__CLEANUP_PUSH,
769 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000770 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000771}
772
773
774void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
775 void (*__routine) (void *),
776 void *__arg)
777{
778 /* As _pthread_cleanup_push, but first save the thread's original
779 cancellation type in __buffer and set it to Deferred. */
780 int orig_ctype;
781 ensure_valgrind("_pthread_cleanup_push_defer");
782 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000783 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
784 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
785 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000786 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
787 VG_USERREQ__SET_CANCELTYPE,
788 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000789 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000790 *((int*)(__buffer)) = orig_ctype;
791 /* Now push the cleanup. */
792 _pthread_cleanup_push(NULL, __routine, __arg);
793}
794
795
796void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
797 int __execute)
798{
799 int res;
800 CleanupEntry cu;
801 ensure_valgrind("_pthread_cleanup_push");
802 cu.fn = cu.arg = NULL; /* paranoia */
803 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
804 VG_USERREQ__CLEANUP_POP,
805 &cu, 0, 0, 0);
806 if (res == 0) {
807 /* pop succeeded */
808 if (__execute) {
809 cu.fn ( cu.arg );
810 }
811 return;
812 }
813 if (res == -1) {
814 /* stack underflow */
815 return;
816 }
817 barf("_pthread_cleanup_pop");
818}
819
820
821void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
822 int __execute)
823{
824 int orig_ctype, fake_ctype;
825 /* As _pthread_cleanup_pop, but after popping/running the handler,
826 restore the thread's original cancellation type from the first
827 word of __buffer. */
828 _pthread_cleanup_pop(NULL, __execute);
829 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000830 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000831 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000832 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
833 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
834 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000835 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
836 VG_USERREQ__SET_CANCELTYPE,
837 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000838 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000839}
840
841
842/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000843 MUTEX ATTRIBUTES
844 ------------------------------------------------ */
845
sewardj5905fae2002-04-26 13:25:00 +0000846int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000847{
sewardjf8f819e2002-04-17 23:21:37 +0000848 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000849 return 0;
sewardje663cb92002-04-12 10:26:32 +0000850}
851
sewardj5905fae2002-04-26 13:25:00 +0000852int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000853{
854 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000855# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000856 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000857 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000858# endif
sewardja1679dd2002-05-10 22:31:40 +0000859# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000860 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000861# endif
sewardjf8f819e2002-04-17 23:21:37 +0000862 case PTHREAD_MUTEX_RECURSIVE_NP:
863 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000864 attr->__mutexkind = type;
865 return 0;
866 default:
sewardj4dced352002-06-04 22:54:20 +0000867 pthread_error("pthread_mutexattr_settype: "
868 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000869 return EINVAL;
870 }
871}
872
sewardj5905fae2002-04-26 13:25:00 +0000873int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000874{
875 return 0;
876}
877
878
879/* ---------------------------------------------------
880 MUTEXes
881 ------------------------------------------------ */
882
sewardj5905fae2002-04-26 13:25:00 +0000883int __pthread_mutex_init(pthread_mutex_t *mutex,
884 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000885{
sewardj604ec3c2002-04-18 22:38:41 +0000886 mutex->__m_count = 0;
887 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
888 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
889 if (mutexattr)
890 mutex->__m_kind = mutexattr->__mutexkind;
891 return 0;
sewardje663cb92002-04-12 10:26:32 +0000892}
893
sewardj439d45e2002-05-03 20:43:10 +0000894
sewardj5905fae2002-04-26 13:25:00 +0000895int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000896{
897 int res;
sewardj436e0582002-04-26 14:31:40 +0000898 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000899 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000900 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
901 VG_USERREQ__PTHREAD_MUTEX_LOCK,
902 mutex, 0, 0, 0);
903 return res;
sewardj439d45e2002-05-03 20:43:10 +0000904 } else {
905 if (moans-- > 0)
906 not_inside("pthread_mutex_lock");
907 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000908 }
909}
910
sewardj439d45e2002-05-03 20:43:10 +0000911
sewardj5905fae2002-04-26 13:25:00 +0000912int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000913{
914 int res;
sewardj436e0582002-04-26 14:31:40 +0000915 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000916 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000917 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
918 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
919 mutex, 0, 0, 0);
920 return res;
sewardj439d45e2002-05-03 20:43:10 +0000921 } else {
922 if (moans-- > 0)
923 not_inside("pthread_mutex_trylock");
924 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000925 }
926}
927
sewardj439d45e2002-05-03 20:43:10 +0000928
sewardj5905fae2002-04-26 13:25:00 +0000929int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000930{
931 int res;
sewardj436e0582002-04-26 14:31:40 +0000932 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000933 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000934 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
935 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
936 mutex, 0, 0, 0);
937 return res;
sewardj439d45e2002-05-03 20:43:10 +0000938 } else {
939 if (moans-- > 0)
940 not_inside("pthread_mutex_unlock");
941 return 0;
sewardje663cb92002-04-12 10:26:32 +0000942 }
943}
944
sewardj439d45e2002-05-03 20:43:10 +0000945
sewardj5905fae2002-04-26 13:25:00 +0000946int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000947{
sewardj604ec3c2002-04-18 22:38:41 +0000948 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
949 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +0000950 if (mutex->__m_count > 0) {
951 pthread_error("pthread_mutex_destroy: "
952 "mutex is still in use");
sewardj604ec3c2002-04-18 22:38:41 +0000953 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +0000954 }
955 mutex->__m_count = 0;
956 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
957 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
958 return 0;
sewardje663cb92002-04-12 10:26:32 +0000959}
960
961
sewardjf8f819e2002-04-17 23:21:37 +0000962/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000963 CONDITION VARIABLES
964 ------------------------------------------------ */
965
966/* LinuxThreads supports no attributes for conditions. Hence ... */
967
968int pthread_condattr_init(pthread_condattr_t *attr)
969{
970 return 0;
971}
972
sewardj0738a592002-04-20 13:59:33 +0000973int pthread_condattr_destroy(pthread_condattr_t *attr)
974{
975 return 0;
976}
sewardj6072c362002-04-19 14:40:57 +0000977
978int pthread_cond_init( pthread_cond_t *cond,
979 const pthread_condattr_t *cond_attr)
980{
981 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
982 return 0;
983}
984
sewardjf854f472002-04-21 12:19:41 +0000985int pthread_cond_destroy(pthread_cond_t *cond)
986{
987 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000988 static int moans = N_MOANS;
989 if (moans-- > 0)
990 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000991 return 0;
992}
sewardj6072c362002-04-19 14:40:57 +0000993
994/* ---------------------------------------------------
995 SCHEDULING
996 ------------------------------------------------ */
997
998/* This is completely bogus. */
999int pthread_getschedparam(pthread_t target_thread,
1000 int *policy,
1001 struct sched_param *param)
1002{
sewardj436e0582002-04-26 14:31:40 +00001003 static int moans = N_MOANS;
1004 if (moans-- > 0)
1005 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +00001006 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +00001007# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +00001008 if (param) param->sched_priority = 0; /* who knows */
1009# else
sewardj6072c362002-04-19 14:40:57 +00001010 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +00001011# endif
sewardj6072c362002-04-19 14:40:57 +00001012 return 0;
1013}
1014
1015int pthread_setschedparam(pthread_t target_thread,
1016 int policy,
1017 const struct sched_param *param)
1018{
sewardj436e0582002-04-26 14:31:40 +00001019 static int moans = N_MOANS;
1020 if (moans-- > 0)
1021 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +00001022 return 0;
1023}
1024
sewardj3b5d8862002-04-20 13:53:23 +00001025int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
1026{
1027 int res;
1028 ensure_valgrind("pthread_cond_wait");
1029 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1030 VG_USERREQ__PTHREAD_COND_WAIT,
1031 cond, mutex, 0, 0);
1032 return res;
1033}
1034
sewardj5f07b662002-04-23 16:52:51 +00001035int pthread_cond_timedwait ( pthread_cond_t *cond,
1036 pthread_mutex_t *mutex,
1037 const struct timespec *abstime )
1038{
1039 int res;
1040 unsigned int ms_now, ms_end;
1041 struct timeval timeval_now;
1042 unsigned long long int ull_ms_now_after_1970;
1043 unsigned long long int ull_ms_end_after_1970;
1044
1045 ensure_valgrind("pthread_cond_timedwait");
1046 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1047 VG_USERREQ__READ_MILLISECOND_TIMER,
1048 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001049 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001050 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +00001051 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001052
1053 ull_ms_now_after_1970
1054 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
1055 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
1056 ull_ms_end_after_1970
1057 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
1058 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +00001059 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
1060 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +00001061 ms_end
1062 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
1063 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1064 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
1065 cond, mutex, ms_end, 0);
1066 return res;
1067}
1068
1069
sewardj3b5d8862002-04-20 13:53:23 +00001070int pthread_cond_signal(pthread_cond_t *cond)
1071{
1072 int res;
1073 ensure_valgrind("pthread_cond_signal");
1074 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1075 VG_USERREQ__PTHREAD_COND_SIGNAL,
1076 cond, 0, 0, 0);
1077 return res;
1078}
1079
1080int pthread_cond_broadcast(pthread_cond_t *cond)
1081{
1082 int res;
1083 ensure_valgrind("pthread_cond_broadcast");
1084 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1085 VG_USERREQ__PTHREAD_COND_BROADCAST,
1086 cond, 0, 0, 0);
1087 return res;
1088}
1089
sewardj6072c362002-04-19 14:40:57 +00001090
1091/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001092 CANCELLATION
1093 ------------------------------------------------ */
1094
sewardj853f55d2002-04-26 00:27:53 +00001095int pthread_setcancelstate(int state, int *oldstate)
1096{
sewardj20917d82002-05-28 01:36:45 +00001097 int res;
1098 ensure_valgrind("pthread_setcancelstate");
1099 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +00001100 && state != PTHREAD_CANCEL_DISABLE) {
1101 pthread_error("pthread_setcancelstate: "
1102 "invalid state");
sewardj20917d82002-05-28 01:36:45 +00001103 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001104 }
sewardj2d94c112002-06-03 01:25:54 +00001105 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1106 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001107 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1108 VG_USERREQ__SET_CANCELSTATE,
1109 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001110 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001111 if (oldstate)
1112 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001113 return 0;
1114}
1115
sewardje663cb92002-04-12 10:26:32 +00001116int pthread_setcanceltype(int type, int *oldtype)
1117{
sewardj20917d82002-05-28 01:36:45 +00001118 int res;
1119 ensure_valgrind("pthread_setcanceltype");
1120 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001121 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1122 pthread_error("pthread_setcanceltype: "
1123 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001124 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001125 }
sewardj2d94c112002-06-03 01:25:54 +00001126 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1127 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001128 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1129 VG_USERREQ__SET_CANCELTYPE,
1130 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001131 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001132 if (oldtype)
1133 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001134 return 0;
1135}
1136
sewardje663cb92002-04-12 10:26:32 +00001137int pthread_cancel(pthread_t thread)
1138{
1139 int res;
1140 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001141 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1142 VG_USERREQ__SET_CANCELPEND,
1143 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001144 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001145 return res;
1146}
1147
sewardjd140e442002-05-29 01:21:19 +00001148static __inline__
1149void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001150{
sewardj20917d82002-05-28 01:36:45 +00001151 int res;
njn25e49d8e72002-09-23 09:36:25 +00001152 ensure_valgrind("__my_pthread_testcancel");
sewardj20917d82002-05-28 01:36:45 +00001153 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1154 VG_USERREQ__TESTCANCEL,
1155 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001156 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001157}
1158
sewardjd140e442002-05-29 01:21:19 +00001159void pthread_testcancel ( void )
1160{
1161 __my_pthread_testcancel();
1162}
1163
sewardj20917d82002-05-28 01:36:45 +00001164
sewardjef037c72002-05-30 00:40:03 +00001165/* Not really sure what this is for. I suspect for doing the POSIX
1166 requirements for fork() and exec(). We do this internally anyway
1167 whenever those syscalls are observed, so this could be superfluous,
1168 but hey ...
1169*/
sewardj853f55d2002-04-26 00:27:53 +00001170void __pthread_kill_other_threads_np ( void )
1171{
sewardjef037c72002-05-30 00:40:03 +00001172 int res;
1173 ensure_valgrind("__pthread_kill_other_threads_np");
1174 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1175 VG_USERREQ__NUKE_OTHER_THREADS,
1176 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001177 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001178}
1179
sewardje663cb92002-04-12 10:26:32 +00001180
sewardjf8f819e2002-04-17 23:21:37 +00001181/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001182 SIGNALS
1183 ------------------------------------------------ */
1184
1185#include <signal.h>
1186
1187int pthread_sigmask(int how, const sigset_t *newmask,
1188 sigset_t *oldmask)
1189{
1190 int res;
1191
1192 /* A bit subtle, because the scheduler expects newmask and oldmask
1193 to be vki_sigset_t* rather than sigset_t*, and the two are
1194 different. Fortunately the first 64 bits of a sigset_t are
1195 exactly a vki_sigset_t, so we just pass the pointers through
1196 unmodified. Haaaack!
1197
1198 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001199 constants to VKI_ constants, so that the former do not have to
1200 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001201
1202 ensure_valgrind("pthread_sigmask");
1203
1204 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001205 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1206 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1207 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001208 default: pthread_error("pthread_sigmask: invalid how");
1209 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001210 }
1211
1212 /* Crude check */
1213 if (newmask == NULL)
1214 return EFAULT;
1215
1216 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1217 VG_USERREQ__PTHREAD_SIGMASK,
1218 how, newmask, oldmask, 0);
1219
1220 /* The scheduler tells us of any memory violations. */
1221 return res == 0 ? 0 : EFAULT;
1222}
1223
1224
1225int sigwait ( const sigset_t* set, int* sig )
1226{
1227 int res;
1228 ensure_valgrind("sigwait");
1229 /* As with pthread_sigmask we deliberately confuse sigset_t with
1230 vki_ksigset_t. */
1231 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1232 VG_USERREQ__SIGWAIT,
1233 set, sig, 0, 0);
1234 return res;
1235}
1236
1237
sewardj018f7622002-05-15 21:13:39 +00001238int pthread_kill(pthread_t thread, int signo)
1239{
1240 int res;
1241 ensure_valgrind("pthread_kill");
1242 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1243 VG_USERREQ__PTHREAD_KILL,
1244 thread, signo, 0, 0);
1245 return res;
1246}
1247
1248
sewardj3665ded2002-05-16 16:57:25 +00001249/* Copied verbatim from Linuxthreads */
1250/* Redefine raise() to send signal to calling thread only,
1251 as per POSIX 1003.1c */
1252int raise (int sig)
1253{
1254 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001255 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001256 return 0;
sewardj4dced352002-06-04 22:54:20 +00001257 } else {
sewardj3665ded2002-05-16 16:57:25 +00001258 errno = retcode;
1259 return -1;
1260 }
1261}
1262
1263
sewardj9a2224b2002-06-19 10:17:40 +00001264int pause ( void )
1265{
1266 unsigned int n_orig, n_now;
1267 struct vki_timespec nanosleep_interval;
1268 ensure_valgrind("pause");
1269
1270 /* This is surely a cancellation point. */
1271 __my_pthread_testcancel();
1272
1273 VALGRIND_MAGIC_SEQUENCE(n_orig, 0xFFFFFFFF /* default */,
1274 VG_USERREQ__GET_N_SIGS_RETURNED,
1275 0, 0, 0, 0);
1276 my_assert(n_orig != 0xFFFFFFFF);
1277
1278 while (1) {
1279 VALGRIND_MAGIC_SEQUENCE(n_now, 0xFFFFFFFF /* default */,
1280 VG_USERREQ__GET_N_SIGS_RETURNED,
1281 0, 0, 0, 0);
1282 my_assert(n_now != 0xFFFFFFFF);
1283 my_assert(n_now >= n_orig);
1284 if (n_now != n_orig) break;
1285
1286 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00001287 nanosleep_interval.tv_nsec = 12 * 1000 * 1000; /* 12 milliseconds */
sewardj9a2224b2002-06-19 10:17:40 +00001288 /* It's critical here that valgrind's nanosleep implementation
1289 is nonblocking. */
1290 (void)my_do_syscall2(__NR_nanosleep,
1291 (int)(&nanosleep_interval), (int)NULL);
1292 }
1293
1294 * (__errno_location()) = EINTR;
1295 return -1;
1296}
1297
1298
sewardjb48e5002002-05-13 00:16:03 +00001299/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001300 THREAD-SPECIFICs
1301 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001302
sewardj00a66b12002-10-12 16:42:35 +00001303static
1304int key_is_valid (pthread_key_t key)
1305{
1306 int res;
1307 VALGRIND_MAGIC_SEQUENCE(res, 2 /* default */,
1308 VG_USERREQ__PTHREAD_KEY_VALIDATE,
1309 key, 0, 0, 0);
1310 my_assert(res != 2);
1311 return res;
1312}
1313
1314
1315/* Returns NULL if thread is invalid. Otherwise, if the thread
1316 already has a specifics area, return that. Otherwise allocate it
1317 one. */
1318static
1319void** get_or_allocate_specifics_ptr ( pthread_t thread )
1320{
1321 int res, i;
1322 void** specifics_ptr;
1323 ensure_valgrind("get_or_allocate_specifics_ptr");
1324
1325 /* Returns zero if the thread has no specific_ptr. One if thread
1326 is invalid. Otherwise, the specific_ptr value. This is
1327 allocated with my_malloc and so is aligned and cannot be
1328 confused with 1 or 3. */
1329 VALGRIND_MAGIC_SEQUENCE(specifics_ptr, 3 /* default */,
1330 VG_USERREQ__PTHREAD_GETSPECIFIC_PTR,
1331 thread, 0, 0, 0);
1332 my_assert(specifics_ptr != (void**)3);
1333
1334 if (specifics_ptr == (void**)1)
1335 return NULL; /* invalid thread */
1336
1337 if (specifics_ptr != NULL)
1338 return specifics_ptr; /* already has a specifics ptr. */
1339
1340 /* None yet ... allocate a new one. Should never fail. */
1341 specifics_ptr = my_malloc( VG_N_THREAD_KEYS * sizeof(void*) );
1342 my_assert(specifics_ptr != NULL);
1343
1344 VALGRIND_MAGIC_SEQUENCE(res, -1 /* default */,
1345 VG_USERREQ__PTHREAD_SETSPECIFIC_PTR,
1346 specifics_ptr, 0, 0, 0);
1347 my_assert(res == 0);
1348
1349 /* POSIX sez: "Upon thread creation, the value NULL shall be
1350 associated with all defined keys in the new thread." This
1351 allocation is in effect a delayed allocation of the specific
1352 data for a thread, at its first-use. Hence we initialise it
1353 here. */
1354 for (i = 0; i < VG_N_THREAD_KEYS; i++) {
1355 specifics_ptr[i] = NULL;
1356 }
1357
1358 return specifics_ptr;
1359}
1360
1361
sewardj5905fae2002-04-26 13:25:00 +00001362int __pthread_key_create(pthread_key_t *key,
1363 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001364{
sewardj00a66b12002-10-12 16:42:35 +00001365 void** specifics_ptr;
1366 int res, i;
sewardj5f07b662002-04-23 16:52:51 +00001367 ensure_valgrind("pthread_key_create");
sewardj00a66b12002-10-12 16:42:35 +00001368
1369 /* This writes *key if successful. It should never fail. */
1370 VALGRIND_MAGIC_SEQUENCE(res, 1 /* default */,
sewardj5f07b662002-04-23 16:52:51 +00001371 VG_USERREQ__PTHREAD_KEY_CREATE,
1372 key, destr_function, 0, 0);
sewardj00a66b12002-10-12 16:42:35 +00001373 my_assert(res == 0);
1374
1375 /* POSIX sez: "Upon key creation, the value NULL shall be
1376 associated with the new key in all active threads." */
1377 for (i = 0; i < VG_N_THREADS; i++) {
1378 specifics_ptr = get_or_allocate_specifics_ptr(i);
1379 /* we get NULL if i is an invalid thread. */
1380 if (specifics_ptr != NULL)
1381 specifics_ptr[*key] = NULL;
1382 }
1383
sewardj5f07b662002-04-23 16:52:51 +00001384 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001385}
1386
1387int pthread_key_delete(pthread_key_t key)
1388{
sewardj00a66b12002-10-12 16:42:35 +00001389 int res;
1390 ensure_valgrind("pthread_key_create");
1391 if (!key_is_valid(key))
1392 return EINVAL;
1393 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1394 VG_USERREQ__PTHREAD_KEY_DELETE,
1395 key, 0, 0, 0);
1396 my_assert(res == 0);
sewardj5e5fa512002-04-14 13:13:05 +00001397 return 0;
1398}
1399
sewardj5905fae2002-04-26 13:25:00 +00001400int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001401{
sewardj00a66b12002-10-12 16:42:35 +00001402 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001403 ensure_valgrind("pthread_setspecific");
sewardj00a66b12002-10-12 16:42:35 +00001404
1405 if (!key_is_valid(key))
1406 return EINVAL;
1407
1408 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1409 specifics_ptr[key] = (void*)pointer;
1410 return 0;
sewardj5e5fa512002-04-14 13:13:05 +00001411}
1412
sewardj5905fae2002-04-26 13:25:00 +00001413void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001414{
sewardj00a66b12002-10-12 16:42:35 +00001415 void** specifics_ptr;
sewardj5f07b662002-04-23 16:52:51 +00001416 ensure_valgrind("pthread_getspecific");
sewardj00a66b12002-10-12 16:42:35 +00001417
1418 if (!key_is_valid(key))
1419 return NULL;
1420
1421 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1422 return specifics_ptr[key];
1423}
1424
1425
sewardj9aa918d2002-10-20 16:25:55 +00001426#ifdef GLIBC_2_3
sewardj00a66b12002-10-12 16:42:35 +00001427static
1428void ** __pthread_getspecific_addr(pthread_key_t key)
1429{
1430 void** specifics_ptr;
1431 ensure_valgrind("pthread_getspecific_addr");
1432
1433 if (!key_is_valid(key))
1434 return NULL;
1435
1436 specifics_ptr = get_or_allocate_specifics_ptr(pthread_self());
1437 return &(specifics_ptr[key]);
sewardj5e5fa512002-04-14 13:13:05 +00001438}
sewardj9aa918d2002-10-20 16:25:55 +00001439#endif
sewardjf8f819e2002-04-17 23:21:37 +00001440
1441/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001442 ONCEry
1443 ------------------------------------------------ */
1444
1445static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1446
1447
sewardj5905fae2002-04-26 13:25:00 +00001448int __pthread_once ( pthread_once_t *once_control,
1449 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001450{
1451 int res;
1452 ensure_valgrind("pthread_once");
1453
sewardj68b2dd92002-05-10 21:03:56 +00001454 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001455
sewardj68b2dd92002-05-10 21:03:56 +00001456 if (res != 0) {
sewardj89d3d852002-04-24 19:21:39 +00001457 barf("pthread_once: Looks like your program's "
1458 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001459 }
sewardj89d3d852002-04-24 19:21:39 +00001460
1461 if (*once_control == 0) {
1462 *once_control = 1;
1463 init_routine();
1464 }
1465
sewardj68b2dd92002-05-10 21:03:56 +00001466 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001467
1468 return 0;
1469}
1470
1471
1472/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001473 MISC
1474 ------------------------------------------------ */
1475
sewardj2cb00342002-06-28 01:46:26 +00001476static pthread_mutex_t pthread_atfork_lock
1477 = PTHREAD_MUTEX_INITIALIZER;
1478
sewardj5905fae2002-04-26 13:25:00 +00001479int __pthread_atfork ( void (*prepare)(void),
1480 void (*parent)(void),
1481 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001482{
sewardj2cb00342002-06-28 01:46:26 +00001483 int n, res;
1484 ForkHandlerEntry entry;
1485
1486 ensure_valgrind("pthread_atfork");
1487 __pthread_mutex_lock(&pthread_atfork_lock);
1488
1489 /* Fetch old counter */
1490 VALGRIND_MAGIC_SEQUENCE(n, -2 /* default */,
1491 VG_USERREQ__GET_FHSTACK_USED,
1492 0, 0, 0, 0);
1493 my_assert(n >= 0 && n < VG_N_FORKHANDLERSTACK);
1494 if (n == VG_N_FORKHANDLERSTACK-1)
1495 barf("pthread_atfork: VG_N_FORKHANDLERSTACK is too low; "
1496 "increase and recompile");
1497
1498 /* Add entry */
1499 entry.prepare = *prepare;
1500 entry.parent = *parent;
1501 entry.child = *child;
1502 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1503 VG_USERREQ__SET_FHSTACK_ENTRY,
1504 n, &entry, 0, 0);
1505 my_assert(res == 0);
1506
1507 /* Bump counter */
1508 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
1509 VG_USERREQ__SET_FHSTACK_USED,
1510 n+1, 0, 0, 0);
1511 my_assert(res == 0);
1512
1513 __pthread_mutex_unlock(&pthread_atfork_lock);
1514 return 0;
sewardj853f55d2002-04-26 00:27:53 +00001515}
1516
1517
sewardjbb990782002-05-08 02:01:14 +00001518__attribute__((weak))
1519void __pthread_initialize ( void )
1520{
sewardjbea1caa2002-05-10 23:20:58 +00001521 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001522}
1523
1524
sewardj853f55d2002-04-26 00:27:53 +00001525/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001526 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001527 ------------------------------------------------ */
1528
sewardj3b13f0e2002-04-25 20:17:29 +00001529#include <resolv.h>
1530static int thread_specific_errno[VG_N_THREADS];
1531static int thread_specific_h_errno[VG_N_THREADS];
1532static struct __res_state
1533 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001534
sewardj3b13f0e2002-04-25 20:17:29 +00001535int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001536{
1537 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001538 /* ensure_valgrind("__errno_location"); */
1539 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001540 VG_USERREQ__PTHREAD_GET_THREADID,
1541 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001542 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001543 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001544 barf("__errno_location: invalid ThreadId");
1545 return & thread_specific_errno[tid];
1546}
1547
1548int* __h_errno_location ( void )
1549{
1550 int tid;
1551 /* ensure_valgrind("__h_errno_location"); */
1552 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1553 VG_USERREQ__PTHREAD_GET_THREADID,
1554 0, 0, 0, 0);
1555 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001556 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001557 barf("__h_errno_location: invalid ThreadId");
1558 return & thread_specific_h_errno[tid];
1559}
1560
sewardjb0ff1032002-08-06 09:02:53 +00001561
1562#undef _res
1563extern struct __res_state _res;
1564
sewardj3b13f0e2002-04-25 20:17:29 +00001565struct __res_state* __res_state ( void )
1566{
1567 int tid;
1568 /* ensure_valgrind("__res_state"); */
1569 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1570 VG_USERREQ__PTHREAD_GET_THREADID,
1571 0, 0, 0, 0);
1572 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001573 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001574 barf("__res_state: invalid ThreadId");
sewardjb0ff1032002-08-06 09:02:53 +00001575 if (tid == 1)
1576 return & _res;
sewardj3b13f0e2002-04-25 20:17:29 +00001577 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001578}
1579
1580
sewardj5716dbb2002-04-26 03:28:18 +00001581/* ---------------------------------------------------
1582 LIBC-PRIVATE SPECIFIC DATA
1583 ------------------------------------------------ */
1584
1585/* Relies on assumption that initial private data is NULL. This
1586 should be fixed somehow. */
1587
njn25e49d8e72002-09-23 09:36:25 +00001588/* The allowable keys (indices) (all 3 of them).
sewardj5716dbb2002-04-26 03:28:18 +00001589 From sysdeps/pthread/bits/libc-tsd.h
1590*/
sewardjcb7f08a2002-10-02 09:41:49 +00001591/* as per glibc anoncvs HEAD of 20021001. */
sewardj5716dbb2002-04-26 03:28:18 +00001592enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1593 _LIBC_TSD_KEY_DL_ERROR,
njn25e49d8e72002-09-23 09:36:25 +00001594 _LIBC_TSD_KEY_RPC_VARS,
sewardjcb7f08a2002-10-02 09:41:49 +00001595 _LIBC_TSD_KEY_LOCALE,
1596 _LIBC_TSD_KEY_CTYPE_B,
1597 _LIBC_TSD_KEY_CTYPE_TOLOWER,
1598 _LIBC_TSD_KEY_CTYPE_TOUPPER,
sewardj5716dbb2002-04-26 03:28:18 +00001599 _LIBC_TSD_KEY_N };
1600
1601/* Auto-initialising subsystem. libc_specifics_inited is set
1602 after initialisation. libc_specifics_inited_mx guards it. */
1603static int libc_specifics_inited = 0;
1604static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1605
sewardj00a66b12002-10-12 16:42:35 +00001606
sewardj5716dbb2002-04-26 03:28:18 +00001607/* These are the keys we must initialise the first time. */
sewardjcb7f08a2002-10-02 09:41:49 +00001608static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N];
sewardj5716dbb2002-04-26 03:28:18 +00001609
sewardj00a66b12002-10-12 16:42:35 +00001610
sewardjcb7f08a2002-10-02 09:41:49 +00001611/* Initialise the keys, if they are not already initialised. */
sewardj5716dbb2002-04-26 03:28:18 +00001612static
1613void init_libc_tsd_keys ( void )
1614{
1615 int res, i;
1616 pthread_key_t k;
1617
sewardj08c7f012002-10-07 23:56:55 +00001618 /* Don't fall into deadlock if we get called again whilst we still
1619 hold the lock, via the __uselocale() call herein. */
1620 if (libc_specifics_inited != 0)
1621 return;
1622
1623 /* Take the lock. */
sewardj00a66b12002-10-12 16:42:35 +00001624 res = __pthread_mutex_lock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001625 if (res != 0) barf("init_libc_tsd_keys: lock");
1626
sewardj08c7f012002-10-07 23:56:55 +00001627 /* Now test again, to be sure there is no mistake. */
1628 if (libc_specifics_inited != 0) {
sewardj00a66b12002-10-12 16:42:35 +00001629 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj08c7f012002-10-07 23:56:55 +00001630 if (res != 0) barf("init_libc_tsd_keys: unlock(1)");
1631 return;
sewardj5716dbb2002-04-26 03:28:18 +00001632 }
1633
sewardj08c7f012002-10-07 23:56:55 +00001634 /* Actually do the initialisation. */
1635 /* printf("INIT libc specifics\n"); */
1636 for (i = 0; i < _LIBC_TSD_KEY_N; i++) {
sewardj00a66b12002-10-12 16:42:35 +00001637 res = __pthread_key_create(&k, NULL);
sewardj08c7f012002-10-07 23:56:55 +00001638 if (res != 0) barf("init_libc_tsd_keys: create");
1639 libc_specifics_keys[i] = k;
1640 }
1641
1642 /* Signify init done. */
1643 libc_specifics_inited = 1;
1644
1645# ifdef GLIBC_2_3
1646 /* Set the initialising thread's locale to the global (default)
sewardj00a66b12002-10-12 16:42:35 +00001647 locale. A hack in support of glibc-2.3. This does the biz for
1648 the root thread. For all other threads we run this in
1649 thread_wrapper(), which does the real work of
1650 pthread_create(). */
1651 /* assert that we are the root thread. I don't know if this is
1652 really a valid assertion to make; if it breaks I'll reconsider
1653 it. */
1654 my_assert(pthread_self() == 1);
sewardj08c7f012002-10-07 23:56:55 +00001655 __uselocale(LC_GLOBAL_LOCALE);
1656# endif
1657
1658 /* Unlock and return. */
sewardj00a66b12002-10-12 16:42:35 +00001659 res = __pthread_mutex_unlock(&libc_specifics_inited_mx);
sewardj5716dbb2002-04-26 03:28:18 +00001660 if (res != 0) barf("init_libc_tsd_keys: unlock");
1661}
1662
1663
1664static int
1665libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1666 const void * pointer )
1667{
sewardjcb7f08a2002-10-02 09:41:49 +00001668 int res;
sewardj5716dbb2002-04-26 03:28:18 +00001669 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardjcb7f08a2002-10-02 09:41:49 +00001670 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001671 barf("libc_internal_tsd_set: invalid key");
1672 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001673 res = __pthread_setspecific(libc_specifics_keys[key], pointer);
sewardj5716dbb2002-04-26 03:28:18 +00001674 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1675 return 0;
1676}
1677
1678static void *
1679libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1680{
sewardjcb7f08a2002-10-02 09:41:49 +00001681 void* v;
sewardj5716dbb2002-04-26 03:28:18 +00001682 /* printf("GET GET GET key %d\n", key); */
sewardjcb7f08a2002-10-02 09:41:49 +00001683 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
sewardj5716dbb2002-04-26 03:28:18 +00001684 barf("libc_internal_tsd_get: invalid key");
1685 init_libc_tsd_keys();
sewardj00a66b12002-10-12 16:42:35 +00001686 v = __pthread_getspecific(libc_specifics_keys[key]);
sewardj5716dbb2002-04-26 03:28:18 +00001687 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1688 return v;
1689}
1690
1691
sewardj70adeb22002-04-27 01:35:38 +00001692int (*__libc_internal_tsd_set)
1693 (enum __libc_tsd_key_t key, const void * pointer)
1694 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001695
sewardj70adeb22002-04-27 01:35:38 +00001696void* (*__libc_internal_tsd_get)
1697 (enum __libc_tsd_key_t key)
1698 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001699
1700
sewardj00a66b12002-10-12 16:42:35 +00001701#ifdef GLIBC_2_3
1702/* This one was first spotted be me in the glibc-2.2.93 sources. */
1703static void**
1704libc_internal_tsd_address ( enum __libc_tsd_key_t key )
1705{
1706 void** v;
1707 /* printf("ADDR ADDR ADDR key %d\n", key); */
1708 if (key < _LIBC_TSD_KEY_MALLOC || key >= _LIBC_TSD_KEY_N)
1709 barf("libc_internal_tsd_address: invalid key");
1710 init_libc_tsd_keys();
1711 v = __pthread_getspecific_addr(libc_specifics_keys[key]);
1712 return v;
1713}
1714
1715void ** (*__libc_internal_tsd_address)
1716 (enum __libc_tsd_key_t key)
1717 = libc_internal_tsd_address;
1718#endif
1719
1720
sewardje663cb92002-04-12 10:26:32 +00001721/* ---------------------------------------------------------------------
1722 These are here (I think) because they are deemed cancellation
1723 points by POSIX. For the moment we'll simply pass the call along
1724 to the corresponding thread-unaware (?) libc routine.
1725 ------------------------------------------------------------------ */
1726
sewardje663cb92002-04-12 10:26:32 +00001727#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001728#include <sys/types.h>
1729#include <sys/socket.h>
1730
sewardjd529a442002-05-04 19:49:21 +00001731#ifdef GLIBC_2_1
1732extern
1733int __sigaction
1734 (int signum,
1735 const struct sigaction *act,
1736 struct sigaction *oldact);
1737#else
sewardje663cb92002-04-12 10:26:32 +00001738extern
1739int __libc_sigaction
1740 (int signum,
1741 const struct sigaction *act,
1742 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001743#endif
sewardje663cb92002-04-12 10:26:32 +00001744int sigaction(int signum,
1745 const struct sigaction *act,
1746 struct sigaction *oldact)
1747{
sewardjd140e442002-05-29 01:21:19 +00001748 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001749# ifdef GLIBC_2_1
1750 return __sigaction(signum, act, oldact);
1751# else
sewardj45b4b372002-04-16 22:50:32 +00001752 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001753# endif
sewardje663cb92002-04-12 10:26:32 +00001754}
1755
1756
1757extern
1758int __libc_connect(int sockfd,
1759 const struct sockaddr *serv_addr,
1760 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001761__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001762int connect(int sockfd,
1763 const struct sockaddr *serv_addr,
1764 socklen_t addrlen)
1765{
sewardjd140e442002-05-29 01:21:19 +00001766 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001767 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001768}
1769
1770
1771extern
1772int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001773__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001774int fcntl(int fd, int cmd, long arg)
1775{
sewardjd140e442002-05-29 01:21:19 +00001776 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001777 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001778}
1779
1780
1781extern
1782ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001783__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001784ssize_t write(int fd, const void *buf, size_t count)
1785{
sewardjd140e442002-05-29 01:21:19 +00001786 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001787 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001788}
1789
1790
1791extern
1792ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001793__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001794ssize_t read(int fd, void *buf, size_t count)
1795{
sewardjd140e442002-05-29 01:21:19 +00001796 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001797 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001798}
1799
sewardjbe32e452002-04-24 20:29:58 +00001800
1801extern
sewardj853f55d2002-04-26 00:27:53 +00001802int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001803__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001804int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001805{
sewardjd140e442002-05-29 01:21:19 +00001806 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001807 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001808}
1809
sewardje663cb92002-04-12 10:26:32 +00001810
1811extern
sewardj853f55d2002-04-26 00:27:53 +00001812int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001813__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001814int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001815{
sewardjd140e442002-05-29 01:21:19 +00001816 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001817 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001818}
1819
1820
1821extern
1822int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001823__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001824int close(int fd)
1825{
sewardjd140e442002-05-29 01:21:19 +00001826 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001827 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001828}
1829
1830
1831extern
1832int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardjf220ccc2002-10-23 21:53:49 +00001833
1834int VGL_(accept)(int s, struct sockaddr *addr, socklen_t *addrlen)
sewardje663cb92002-04-12 10:26:32 +00001835{
sewardjd140e442002-05-29 01:21:19 +00001836 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001837 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001838 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001839 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001840}
1841
sewardj0c573af92002-10-23 21:55:01 +00001842extern
1843int __libc_recv(int s, void *buf, size_t len, int flags);
1844
1845int VGL_(recv)(int s, void *buf, size_t len, int flags)
1846{
1847 __my_pthread_testcancel();
1848 wait_for_fd_to_be_readable_or_erring(s);
1849 __my_pthread_testcancel();
1850 return __libc_recv(s, buf, len, flags);
1851}
1852
sewardje663cb92002-04-12 10:26:32 +00001853
1854extern
sewardje663cb92002-04-12 10:26:32 +00001855pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001856__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001857pid_t waitpid(pid_t pid, int *status, int options)
1858{
sewardjd140e442002-05-29 01:21:19 +00001859 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001860 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001861}
1862
1863
1864extern
1865int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001866__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001867int nanosleep(const struct timespec *req, struct timespec *rem)
1868{
sewardjd140e442002-05-29 01:21:19 +00001869 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001870 return __libc_nanosleep(req, rem);
1871}
1872
sewardjbe32e452002-04-24 20:29:58 +00001873
sewardje663cb92002-04-12 10:26:32 +00001874extern
1875int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001876__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001877int fsync(int fd)
1878{
sewardjd140e442002-05-29 01:21:19 +00001879 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001880 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001881}
1882
sewardjbe32e452002-04-24 20:29:58 +00001883
sewardj70c75362002-04-13 04:18:32 +00001884extern
1885off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001886__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001887off_t lseek(int fildes, off_t offset, int whence)
1888{
sewardjd140e442002-05-29 01:21:19 +00001889 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001890 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001891}
1892
sewardjbe32e452002-04-24 20:29:58 +00001893
1894extern
1895__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001896__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001897__off64_t lseek64(int fildes, __off64_t offset, int whence)
1898{
sewardjd140e442002-05-29 01:21:19 +00001899 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001900 return __libc_lseek64(fildes, offset, whence);
1901}
1902
1903
sewardj726c4122002-05-16 23:39:10 +00001904extern
1905ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1906 __off64_t __offset);
1907ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1908 __off64_t __offset)
1909{
sewardjd140e442002-05-29 01:21:19 +00001910 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001911 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1912}
1913
1914
sewardja18e2102002-05-18 10:43:22 +00001915extern
1916ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1917 __off64_t __offset);
1918ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1919 __off64_t __offset)
1920{
sewardjd140e442002-05-29 01:21:19 +00001921 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001922 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1923}
1924
sewardj726c4122002-05-16 23:39:10 +00001925
sewardj39b93b12002-05-18 10:56:27 +00001926extern
1927ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1928__attribute__((weak))
1929ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1930{
sewardjd140e442002-05-29 01:21:19 +00001931 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001932 return __libc_pwrite(fd, buf, count, offset);
1933}
1934
1935
1936extern
1937ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1938__attribute__((weak))
1939ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1940{
sewardjd140e442002-05-29 01:21:19 +00001941 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001942 return __libc_pread(fd, buf, count, offset);
1943}
1944
1945
sewardj6af4b5d2002-04-16 04:40:49 +00001946extern
1947void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001948/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001949void longjmp(jmp_buf env, int val)
1950{
1951 __libc_longjmp(env, val);
1952}
1953
sewardjbe32e452002-04-24 20:29:58 +00001954
sewardj436c2db2002-06-18 09:07:54 +00001955extern void __libc_siglongjmp (sigjmp_buf env, int val)
1956 __attribute__ ((noreturn));
1957void siglongjmp(sigjmp_buf env, int val)
1958{
1959 kludged("siglongjmp (cleanup handlers are ignored)");
1960 __libc_siglongjmp(env, val);
1961}
1962
1963
sewardj6af4b5d2002-04-16 04:40:49 +00001964extern
1965int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001966__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001967int send(int s, const void *msg, size_t len, int flags)
1968{
sewardjd140e442002-05-29 01:21:19 +00001969 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001970 return __libc_send(s, msg, len, flags);
1971}
1972
sewardjbe32e452002-04-24 20:29:58 +00001973
sewardj1e8cdc92002-04-18 11:37:52 +00001974extern
1975int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001976__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001977int recv(int s, void *buf, size_t len, int flags)
1978{
sewardjd140e442002-05-29 01:21:19 +00001979 __my_pthread_testcancel();
sewardj1d6b3a22002-06-20 07:58:33 +00001980 wait_for_fd_to_be_readable_or_erring(s);
1981 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001982 return __libc_recv(s, buf, len, flags);
1983}
1984
sewardjbe32e452002-04-24 20:29:58 +00001985
sewardj3665ded2002-05-16 16:57:25 +00001986extern
1987int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1988__attribute__((weak))
1989int sendmsg(int s, const struct msghdr *msg, int flags)
1990{
sewardjd140e442002-05-29 01:21:19 +00001991 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001992 return __libc_sendmsg(s, msg, flags);
1993}
1994
1995
sewardj796d6a22002-04-24 02:28:34 +00001996extern
sewardj59da27a2002-06-06 08:33:54 +00001997int __libc_recvmsg(int s, struct msghdr *msg, int flags);
1998__attribute__((weak))
1999int recvmsg(int s, struct msghdr *msg, int flags)
2000{
2001 __my_pthread_testcancel();
2002 return __libc_recvmsg(s, msg, flags);
2003}
2004
2005
2006extern
sewardj436e0582002-04-26 14:31:40 +00002007int __libc_recvfrom(int s, void *buf, size_t len, int flags,
2008 struct sockaddr *from, socklen_t *fromlen);
2009__attribute__((weak))
2010int recvfrom(int s, void *buf, size_t len, int flags,
2011 struct sockaddr *from, socklen_t *fromlen)
2012{
sewardjd140e442002-05-29 01:21:19 +00002013 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00002014 wait_for_fd_to_be_readable_or_erring(s);
2015 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00002016 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
2017}
2018
2019
2020extern
sewardj796d6a22002-04-24 02:28:34 +00002021int __libc_sendto(int s, const void *msg, size_t len, int flags,
2022 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00002023__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00002024int sendto(int s, const void *msg, size_t len, int flags,
2025 const struct sockaddr *to, socklen_t tolen)
2026{
sewardjd140e442002-05-29 01:21:19 +00002027 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00002028 return __libc_sendto(s, msg, len, flags, to, tolen);
2029}
2030
sewardjbe32e452002-04-24 20:29:58 +00002031
sewardj369b1702002-04-24 13:28:15 +00002032extern
2033int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00002034__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00002035int system(const char* str)
2036{
sewardjd140e442002-05-29 01:21:19 +00002037 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00002038 return __libc_system(str);
2039}
2040
sewardjbe32e452002-04-24 20:29:58 +00002041
sewardjab0b1c32002-04-24 19:26:47 +00002042extern
2043pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00002044__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00002045pid_t wait(int *status)
2046{
sewardjd140e442002-05-29 01:21:19 +00002047 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00002048 return __libc_wait(status);
2049}
2050
sewardj45b4b372002-04-16 22:50:32 +00002051
sewardj67f1d582002-05-24 02:11:32 +00002052extern
2053int __libc_msync(const void *start, size_t length, int flags);
2054__attribute__((weak))
2055int msync(const void *start, size_t length, int flags)
2056{
sewardjd140e442002-05-29 01:21:19 +00002057 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00002058 return __libc_msync(start, length, flags);
2059}
2060
sewardj5905fae2002-04-26 13:25:00 +00002061
sewardj2cb00342002-06-28 01:46:26 +00002062/*--- fork and its helper ---*/
2063
2064static
2065void run_fork_handlers ( int what )
2066{
2067 ForkHandlerEntry entry;
2068 int n_h, n_handlers, i, res;
2069
2070 my_assert(what == 0 || what == 1 || what == 2);
2071
2072 /* Fetch old counter */
2073 VALGRIND_MAGIC_SEQUENCE(n_handlers, -2 /* default */,
2074 VG_USERREQ__GET_FHSTACK_USED,
2075 0, 0, 0, 0);
2076 my_assert(n_handlers >= 0 && n_handlers < VG_N_FORKHANDLERSTACK);
2077
2078 /* Prepare handlers (what == 0) are called in opposite order of
2079 calls to pthread_atfork. Parent and child handlers are called
2080 in the same order as calls to pthread_atfork. */
2081 if (what == 0)
2082 n_h = n_handlers - 1;
2083 else
2084 n_h = 0;
2085
2086 for (i = 0; i < n_handlers; i++) {
2087 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2088 VG_USERREQ__GET_FHSTACK_ENTRY,
2089 n_h, &entry, 0, 0);
2090 my_assert(res == 0);
2091 switch (what) {
2092 case 0: if (entry.prepare) entry.prepare();
2093 n_h--; break;
2094 case 1: if (entry.parent) entry.parent();
2095 n_h++; break;
2096 case 2: if (entry.child) entry.child();
2097 n_h++; break;
2098 default: barf("run_fork_handlers: invalid what");
2099 }
2100 }
2101
2102 if (what != 0 /* prepare */) {
2103 /* Empty out the stack. */
2104 VALGRIND_MAGIC_SEQUENCE(res, -2 /* default */,
2105 VG_USERREQ__SET_FHSTACK_USED,
2106 0, 0, 0, 0);
2107 my_assert(res == 0);
2108 }
2109}
2110
2111extern
2112pid_t __libc_fork(void);
2113pid_t __fork(void)
2114{
2115 pid_t pid;
2116 __my_pthread_testcancel();
2117 __pthread_mutex_lock(&pthread_atfork_lock);
2118
2119 run_fork_handlers(0 /* prepare */);
2120 pid = __libc_fork();
2121 if (pid == 0) {
2122 /* I am the child */
2123 run_fork_handlers(2 /* child */);
2124 __pthread_mutex_init(&pthread_atfork_lock, NULL);
2125 } else {
2126 /* I am the parent */
2127 run_fork_handlers(1 /* parent */);
2128 __pthread_mutex_unlock(&pthread_atfork_lock);
2129 }
2130 return pid;
2131}
2132
2133
njn25e49d8e72002-09-23 09:36:25 +00002134pid_t __vfork(void)
2135{
2136 return __fork();
2137}
sewardj2cb00342002-06-28 01:46:26 +00002138
2139
sewardj3b13f0e2002-04-25 20:17:29 +00002140/* ---------------------------------------------------------------------
2141 Nonblocking implementations of select() and poll(). This stuff will
2142 surely rot your mind.
2143 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00002144
sewardj08a4c3f2002-04-13 03:45:44 +00002145/*--------------------------------------------------*/
2146
2147#include "vg_kerneliface.h"
2148
2149static
2150__inline__
2151int is_kerror ( int res )
2152{
2153 if (res >= -4095 && res <= -1)
2154 return 1;
2155 else
2156 return 0;
2157}
2158
2159
2160static
2161int my_do_syscall1 ( int syscallno, int arg1 )
2162{
2163 int __res;
2164 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2165 : "=a" (__res)
2166 : "0" (syscallno),
2167 "d" (arg1) );
2168 return __res;
2169}
2170
2171static
2172int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00002173 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00002174{
2175 int __res;
2176 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
2177 : "=a" (__res)
2178 : "0" (syscallno),
2179 "d" (arg1),
2180 "c" (arg2) );
2181 return __res;
2182}
2183
2184static
sewardjf854f472002-04-21 12:19:41 +00002185int my_do_syscall3 ( int syscallno,
2186 int arg1, int arg2, int arg3 )
2187{
2188 int __res;
2189 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
2190 : "=a" (__res)
2191 : "0" (syscallno),
2192 "S" (arg1),
2193 "c" (arg2),
2194 "d" (arg3) );
2195 return __res;
2196}
2197
sewardjd5bef572002-10-23 21:49:33 +00002198static inline
2199int my_do_syscall5 ( int syscallno,
2200 int arg1, int arg2, int arg3, int arg4, int arg5 )
2201{
2202 int __res;
2203 __asm__ volatile ("int $0x80"
2204 : "=a" (__res)
2205 : "0" (syscallno),
2206 "b" (arg1),
2207 "c" (arg2),
2208 "d" (arg3),
2209 "S" (arg4),
2210 "D" (arg5));
2211 return __res;
2212}
2213
sewardjf854f472002-04-21 12:19:41 +00002214static
sewardj08a4c3f2002-04-13 03:45:44 +00002215int do_syscall_select( int n,
2216 vki_fd_set* readfds,
2217 vki_fd_set* writefds,
2218 vki_fd_set* exceptfds,
2219 struct vki_timeval * timeout )
2220{
2221 int res;
2222 int args[5];
2223 args[0] = n;
2224 args[1] = (int)readfds;
2225 args[2] = (int)writefds;
2226 args[3] = (int)exceptfds;
2227 args[4] = (int)timeout;
2228 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00002229 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00002230}
2231
2232
2233/* This is a wrapper round select(), which makes it thread-safe,
2234 meaning that only this thread will block, rather than the entire
2235 process. This wrapper in turn depends on nanosleep() not to block
2236 the entire process, but I think (hope? suspect?) that POSIX
2237 pthreads guarantees that to be the case.
2238
2239 Basic idea is: modify the timeout parameter to select so that it
2240 returns immediately. Poll like this until select returns non-zero,
2241 indicating something interesting happened, or until our time is up.
njn25e49d8e72002-09-23 09:36:25 +00002242 Space out the polls with nanosleeps of say 11 milliseconds, which
sewardj08a4c3f2002-04-13 03:45:44 +00002243 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00002244
2245 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00002246 * (checked via my_assert) types fd_set and vki_fd_set are identical.
2247 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00002248 * (unchecked) libc error numbers (EINTR etc) are the negation of the
2249 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00002250*/
sewardj08a4c3f2002-04-13 03:45:44 +00002251
sewardj5905fae2002-04-26 13:25:00 +00002252/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00002253int select ( int n,
2254 fd_set *rfds,
2255 fd_set *wfds,
2256 fd_set *xfds,
2257 struct timeval *timeout )
2258{
sewardj5f07b662002-04-23 16:52:51 +00002259 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00002260 int res;
2261 fd_set rfds_copy;
2262 fd_set wfds_copy;
2263 fd_set xfds_copy;
2264 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00002265 struct vki_timeval zero_timeout;
2266 struct vki_timespec nanosleep_interval;
2267
sewardjd140e442002-05-29 01:21:19 +00002268 __my_pthread_testcancel();
2269
sewardj5f07b662002-04-23 16:52:51 +00002270 /* gcc's complains about ms_end being used uninitialised -- classic
2271 case it can't understand, where ms_end is both defined and used
2272 only if timeout != NULL. Hence ... */
2273 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00002274
2275 /* We assume that the kernel and libc data layouts are identical
2276 for the following types. These asserts provide a crude
2277 check. */
2278 if (sizeof(fd_set) != sizeof(vki_fd_set)
2279 || sizeof(struct timeval) != sizeof(struct vki_timeval))
2280 barf("valgrind's hacky non-blocking select(): data sizes error");
2281
sewardj5f07b662002-04-23 16:52:51 +00002282 /* Detect the current time and simultaneously find out if we are
2283 running on Valgrind. */
2284 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2285 VG_USERREQ__READ_MILLISECOND_TIMER,
2286 0, 0, 0, 0);
2287
2288 /* If a zero timeout specified, this call is harmless. Also go
2289 this route if we're not running on Valgrind, for whatever
2290 reason. */
2291 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
2292 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00002293 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00002294 (vki_fd_set*)wfds,
2295 (vki_fd_set*)xfds,
2296 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00002297 if (is_kerror(res)) {
2298 * (__errno_location()) = -res;
2299 return -1;
2300 } else {
2301 return res;
2302 }
2303 }
sewardj08a4c3f2002-04-13 03:45:44 +00002304
sewardj5f07b662002-04-23 16:52:51 +00002305 /* If a timeout was specified, set ms_end to be the end millisecond
2306 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00002307 if (timeout) {
2308 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00002309 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00002310 ms_end = ms_now;
2311 ms_end += (timeout->tv_usec / 1000);
2312 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00002313 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00002314 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00002315 }
2316
2317 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
2318
2319 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00002320 NULL, in which case ms_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002321
sewardj08a4c3f2002-04-13 03:45:44 +00002322 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002323
2324 /* First, do a return-immediately select(). */
sewardj08a4c3f2002-04-13 03:45:44 +00002325
2326 /* These could be trashed each time round the loop, so restore
2327 them each time. */
2328 if (rfds) rfds_copy = *rfds;
2329 if (wfds) wfds_copy = *wfds;
2330 if (xfds) xfds_copy = *xfds;
2331
2332 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
2333
2334 res = do_syscall_select( n,
2335 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
2336 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
2337 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
2338 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00002339 if (is_kerror(res)) {
2340 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00002341 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00002342 * (__errno_location()) = -res;
2343 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00002344 }
2345 if (res > 0) {
2346 /* one or more fds is ready. Copy out resulting sets and
2347 return. */
2348 if (rfds) *rfds = rfds_copy;
2349 if (wfds) *wfds = wfds_copy;
2350 if (xfds) *xfds = xfds_copy;
2351 return res;
2352 }
sewardj05bb2c92002-06-26 00:47:17 +00002353
2354 /* Nothing interesting happened, so we go to sleep for a
2355 while. */
2356
sewardj08a4c3f2002-04-13 03:45:44 +00002357 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
2358 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00002359 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002360 nanosleep_interval.tv_nsec = 11 * 1000 * 1000; /* 11 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00002361 /* It's critical here that valgrind's nanosleep implementation
2362 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00002363 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00002364 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00002365 if (res == -VKI_EINTR) {
2366 /* The nanosleep was interrupted by a signal. So we do the
2367 same. */
2368 * (__errno_location()) = EINTR;
2369 return -1;
2370 }
sewardj05bb2c92002-06-26 00:47:17 +00002371
2372 /* Sleeping finished. If a finite timeout, check to see if it
2373 has expired yet. */
2374 if (timeout) {
2375 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2376 VG_USERREQ__READ_MILLISECOND_TIMER,
2377 0, 0, 0, 0);
2378 my_assert(ms_now != 0xFFFFFFFF);
2379 if (ms_now >= ms_end) {
2380 /* timeout; nothing interesting happened. */
2381 if (rfds) FD_ZERO(rfds);
2382 if (wfds) FD_ZERO(wfds);
2383 if (xfds) FD_ZERO(xfds);
2384 return 0;
2385 }
2386 }
2387
sewardjf854f472002-04-21 12:19:41 +00002388 }
2389}
2390
2391
2392
2393
2394#include <sys/poll.h>
2395
sewardj3e909ce2002-06-03 13:27:15 +00002396#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00002397typedef unsigned long int nfds_t;
2398#endif
2399
sewardj705d3cb2002-05-23 13:13:12 +00002400
sewardj5905fae2002-04-26 13:25:00 +00002401/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00002402int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2403{
sewardj5f07b662002-04-23 16:52:51 +00002404 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00002405 int res, i;
sewardjf854f472002-04-21 12:19:41 +00002406 struct vki_timespec nanosleep_interval;
2407
sewardjd140e442002-05-29 01:21:19 +00002408 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00002409 ensure_valgrind("poll");
2410
sewardj5f07b662002-04-23 16:52:51 +00002411 /* Detect the current time and simultaneously find out if we are
2412 running on Valgrind. */
2413 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2414 VG_USERREQ__READ_MILLISECOND_TIMER,
2415 0, 0, 0, 0);
2416
sewardjf854f472002-04-21 12:19:41 +00002417 if (/* CHECK SIZES FOR struct pollfd */
2418 sizeof(struct timeval) != sizeof(struct vki_timeval))
2419 barf("valgrind's hacky non-blocking poll(): data sizes error");
2420
sewardj5f07b662002-04-23 16:52:51 +00002421 /* dummy initialisation to keep gcc -Wall happy */
2422 ms_end = 0;
2423
2424 /* If a zero timeout specified, this call is harmless. Also do
2425 this if not running on Valgrind. */
2426 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00002427 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
2428 if (is_kerror(res)) {
2429 * (__errno_location()) = -res;
2430 return -1;
2431 } else {
2432 return res;
2433 }
2434 }
2435
sewardj5f07b662002-04-23 16:52:51 +00002436 /* If a timeout was specified, set ms_end to be the end wallclock
2437 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002438 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002439 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002440 }
2441
2442 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2443
2444 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2445 in which case t_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002446
sewardj2d94c112002-06-03 01:25:54 +00002447 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002448
sewardjf854f472002-04-21 12:19:41 +00002449 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002450
2451 /* Do a return-immediately poll. */
2452
2453 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2454 if (is_kerror(res)) {
2455 /* Some kind of error. Set errno and return. */
2456 * (__errno_location()) = -res;
2457 return -1;
2458 }
2459 if (res > 0) {
2460 /* One or more fds is ready. Return now. */
2461 return res;
2462 }
2463
2464 /* Nothing interesting happened, so we go to sleep for a
2465 while. */
2466
2467 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2468 /* nanosleep and go round again */
2469 nanosleep_interval.tv_sec = 0;
njn25e49d8e72002-09-23 09:36:25 +00002470 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
sewardj05bb2c92002-06-26 00:47:17 +00002471 /* It's critical here that valgrind's nanosleep implementation
2472 is nonblocking. */
2473 (void)my_do_syscall2(__NR_nanosleep,
2474 (int)(&nanosleep_interval), (int)NULL);
2475
2476 /* Sleeping finished. If a finite timeout, check to see if it
2477 has expired yet. */
sewardjf854f472002-04-21 12:19:41 +00002478 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002479 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2480 VG_USERREQ__READ_MILLISECOND_TIMER,
2481 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002482 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002483 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002484 /* timeout; nothing interesting happened. */
2485 for (i = 0; i < __nfds; i++)
2486 __fds[i].revents = 0;
2487 return 0;
2488 }
2489 }
2490
sewardj08a4c3f2002-04-13 03:45:44 +00002491 }
2492}
sewardj3b13f0e2002-04-25 20:17:29 +00002493
2494
sewardj705d3cb2002-05-23 13:13:12 +00002495/* Helper function used to make accept() non-blocking. Idea is to use
2496 the above nonblocking poll() to make this thread ONLY wait for the
2497 specified fd to become ready, and then return. */
sewardjd1c1cf22002-06-26 00:13:36 +00002498
2499/* Sigh -- a hack. We're not supposed to include this file directly;
2500 should do it via /usr/include/fcntl.h, but that introduces a
2501 varargs prototype for fcntl itself, which we can't mimic. */
2502#define _FCNTL_H
2503#include <bits/fcntl.h>
2504
sewardj705d3cb2002-05-23 13:13:12 +00002505static void wait_for_fd_to_be_readable_or_erring ( int fd )
2506{
2507 struct pollfd pfd;
sewardjd1c1cf22002-06-26 00:13:36 +00002508 int res;
2509
sewardj6e6cbaa2002-05-24 02:12:52 +00002510 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardjd1c1cf22002-06-26 00:13:36 +00002511
2512 /* First check to see if the fd is nonblocking, and/or invalid. In
2513 either case return immediately. */
2514 res = __libc_fcntl(fd, F_GETFL, 0);
2515 if (res == -1) return; /* fd is invalid somehow */
2516 if (res & O_NONBLOCK) return; /* fd is nonblocking */
2517
2518 /* Ok, we'd better wait with poll. */
sewardj705d3cb2002-05-23 13:13:12 +00002519 pfd.fd = fd;
2520 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2521 /* ... but not POLLOUT, you may notice. */
2522 pfd.revents = 0;
2523 (void)poll(&pfd, 1, -1 /* forever */);
2524}
2525
2526
sewardj3b13f0e2002-04-25 20:17:29 +00002527/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002528 Hacky implementation of semaphores.
2529 ------------------------------------------------------------------ */
2530
2531#include <semaphore.h>
2532
2533/* This is a terrible way to do the remapping. Plan is to import an
2534 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002535
2536typedef
2537 struct {
2538 pthread_mutex_t se_mx;
2539 pthread_cond_t se_cv;
2540 int count;
2541 }
2542 vg_sem_t;
2543
2544static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2545
2546static int se_remap_used = 0;
2547static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2548static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2549
2550static vg_sem_t* se_remap ( sem_t* orig )
2551{
2552 int res, i;
2553 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002554 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002555
2556 for (i = 0; i < se_remap_used; i++) {
2557 if (se_remap_orig[i] == orig)
2558 break;
2559 }
2560 if (i == se_remap_used) {
2561 if (se_remap_used == VG_N_SEMAPHORES) {
2562 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002563 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002564 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002565 }
2566 se_remap_used++;
2567 se_remap_orig[i] = orig;
2568 /* printf("allocated semaphore %d\n", i); */
2569 }
2570 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002571 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002572 return &se_remap_new[i];
2573}
2574
2575
2576int sem_init(sem_t *sem, int pshared, unsigned int value)
2577{
2578 int res;
2579 vg_sem_t* vg_sem;
2580 ensure_valgrind("sem_init");
2581 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002582 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002583 errno = ENOSYS;
2584 return -1;
2585 }
2586 vg_sem = se_remap(sem);
2587 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002588 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002589 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002590 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002591 vg_sem->count = value;
2592 return 0;
2593}
2594
2595
2596int sem_wait ( sem_t* sem )
2597{
2598 int res;
2599 vg_sem_t* vg_sem;
2600 ensure_valgrind("sem_wait");
2601 vg_sem = se_remap(sem);
2602 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002603 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002604 while (vg_sem->count == 0) {
2605 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002606 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002607 }
2608 vg_sem->count--;
2609 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002610 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002611 return 0;
2612}
2613
2614int sem_post ( sem_t* sem )
2615{
2616 int res;
2617 vg_sem_t* vg_sem;
2618 ensure_valgrind("sem_post");
2619 vg_sem = se_remap(sem);
2620 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002621 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002622 if (vg_sem->count == 0) {
2623 vg_sem->count++;
2624 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002625 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002626 } else {
2627 vg_sem->count++;
2628 }
2629 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002630 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002631 return 0;
2632}
2633
2634
2635int sem_trywait ( sem_t* sem )
2636{
2637 int ret, res;
2638 vg_sem_t* vg_sem;
2639 ensure_valgrind("sem_trywait");
2640 vg_sem = se_remap(sem);
2641 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002642 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002643 if (vg_sem->count > 0) {
2644 vg_sem->count--;
2645 ret = 0;
2646 } else {
2647 ret = -1;
2648 errno = EAGAIN;
2649 }
2650 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002651 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002652 return ret;
2653}
2654
2655
2656int sem_getvalue(sem_t* sem, int * sval)
2657{
2658 vg_sem_t* vg_sem;
2659 ensure_valgrind("sem_trywait");
2660 vg_sem = se_remap(sem);
2661 *sval = vg_sem->count;
2662 return 0;
2663}
2664
2665
2666int sem_destroy(sem_t * sem)
2667{
2668 kludged("sem_destroy");
2669 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2670 return 0;
2671}
2672
sewardj9ad92d92002-10-16 19:45:06 +00002673
2674int sem_timedwait(sem_t* sem, const struct timespec *abstime)
2675{
2676 int res;
2677 vg_sem_t* vg_sem;
2678 ensure_valgrind("sem_timedwait");
2679 vg_sem = se_remap(sem);
2680 res = __pthread_mutex_lock(&vg_sem->se_mx);
2681 my_assert(res == 0);
2682 while ( vg_sem->count == 0 && res != ETIMEDOUT ) {
2683 res = pthread_cond_timedwait(&vg_sem->se_cv, &vg_sem->se_mx, abstime);
2684 }
2685 if ( vg_sem->count > 0 ) {
2686 vg_sem->count--;
2687 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2688 my_assert(res == 0 );
2689 return 0;
2690 } else {
2691 res = __pthread_mutex_unlock(&vg_sem->se_mx);
2692 my_assert(res == 0 );
2693 *(__errno_location()) = ETIMEDOUT;
2694 return -1;
2695 }
2696}
2697
sewardj8f253ff2002-05-19 00:13:34 +00002698
2699/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002700 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002701 ------------------------------------------------------------------ */
2702
sewardj2d8b3f02002-06-01 14:14:19 +00002703typedef
2704 struct {
2705 int initted; /* != 0 --> in use; sanity check only */
2706 int prefer_w; /* != 0 --> prefer writer */
2707 int nwait_r; /* # of waiting readers */
2708 int nwait_w; /* # of waiting writers */
2709 pthread_cond_t cv_r; /* for signalling readers */
2710 pthread_cond_t cv_w; /* for signalling writers */
2711 pthread_mutex_t mx;
2712 int status;
2713 /* allowed range for status: >= -1. -1 means 1 writer currently
2714 active, >= 0 means N readers currently active. */
2715 }
2716 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002717
2718
2719static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2720
2721static int rw_remap_used = 0;
2722static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2723static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2724
sewardj2d8b3f02002-06-01 14:14:19 +00002725
2726static
2727void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2728{
2729 int res = 0;
2730 vg_rwl->initted = 1;
2731 vg_rwl->prefer_w = 1;
2732 vg_rwl->nwait_r = 0;
2733 vg_rwl->nwait_w = 0;
2734 vg_rwl->status = 0;
2735 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2736 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2737 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002738 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002739}
2740
2741
sewardja1ac5cb2002-05-27 13:00:05 +00002742/* Take the address of a LinuxThreads rwlock_t and return the shadow
2743 address of our version. Further, if the LinuxThreads version
2744 appears to have been statically initialised, do the same to the one
2745 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2746 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2747 uninitialised and non-zero meaning initialised.
2748*/
2749static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2750{
2751 int res, i;
2752 vg_rwlock_t* vg_rwl;
2753 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002754 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002755
2756 for (i = 0; i < rw_remap_used; i++) {
2757 if (rw_remap_orig[i] == orig)
2758 break;
2759 }
2760 if (i == rw_remap_used) {
2761 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002762 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002763 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002764 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2765 }
2766 rw_remap_used++;
2767 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002768 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002769 if (0) printf("allocated rwlock %d\n", i);
2770 }
2771 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002772 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002773 vg_rwl = &rw_remap_new[i];
2774
sewardj2d8b3f02002-06-01 14:14:19 +00002775 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002776 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002777 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002778 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002779 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002780 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002781 }
2782
2783 return vg_rwl;
2784}
2785
2786
sewardja1ac5cb2002-05-27 13:00:05 +00002787int pthread_rwlock_init ( pthread_rwlock_t* orig,
2788 const pthread_rwlockattr_t* attr )
2789{
sewardja1ac5cb2002-05-27 13:00:05 +00002790 vg_rwlock_t* rwl;
2791 if (0) printf ("pthread_rwlock_init\n");
2792 /* Force the remapper to initialise the shadow. */
2793 orig->__rw_readers = 0;
2794 /* Install the lock preference; the remapper needs to know it. */
2795 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2796 if (attr)
2797 orig->__rw_kind = attr->__lockkind;
2798 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002799 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002800}
2801
sewardj2d8b3f02002-06-01 14:14:19 +00002802
2803static
2804void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002805{
sewardj2d8b3f02002-06-01 14:14:19 +00002806 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2807 rwl->nwait_r--;
2808 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002809}
2810
sewardj2d8b3f02002-06-01 14:14:19 +00002811
sewardja1ac5cb2002-05-27 13:00:05 +00002812int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2813{
2814 int res;
2815 vg_rwlock_t* rwl;
2816 if (0) printf ("pthread_rwlock_rdlock\n");
2817 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002818 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002819 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002820 if (!rwl->initted) {
2821 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002822 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002823 return EINVAL;
2824 }
2825 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002826 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002827 rwl->nwait_r++;
2828 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2829 while (1) {
2830 if (rwl->status == 0) break;
2831 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002832 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002833 }
2834 pthread_cleanup_pop(0);
2835 rwl->nwait_r--;
2836 }
sewardj2d94c112002-06-03 01:25:54 +00002837 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002838 rwl->status++;
2839 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002840 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002841 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002842}
2843
sewardj2d8b3f02002-06-01 14:14:19 +00002844
sewardja1ac5cb2002-05-27 13:00:05 +00002845int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2846{
2847 int res;
2848 vg_rwlock_t* rwl;
2849 if (0) printf ("pthread_rwlock_tryrdlock\n");
2850 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002851 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002852 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002853 if (!rwl->initted) {
2854 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002855 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002856 return EINVAL;
2857 }
2858 if (rwl->status == -1) {
2859 /* Writer active; we have to give up. */
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 EBUSY;
2863 }
2864 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002865 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002866 rwl->status++;
2867 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002868 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002869 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002870}
2871
sewardj2d8b3f02002-06-01 14:14:19 +00002872
2873static
2874void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2875{
2876 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2877 rwl->nwait_w--;
2878 pthread_mutex_unlock (&rwl->mx);
2879}
2880
2881
sewardja1ac5cb2002-05-27 13:00:05 +00002882int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2883{
2884 int res;
2885 vg_rwlock_t* rwl;
2886 if (0) printf ("pthread_rwlock_wrlock\n");
2887 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002888 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002889 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002890 if (!rwl->initted) {
2891 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002892 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002893 return EINVAL;
2894 }
2895 if (rwl->status != 0) {
2896 rwl->nwait_w++;
2897 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2898 while (1) {
2899 if (rwl->status == 0) break;
2900 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002901 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002902 }
2903 pthread_cleanup_pop(0);
2904 rwl->nwait_w--;
2905 }
sewardj2d94c112002-06-03 01:25:54 +00002906 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002907 rwl->status = -1;
2908 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002909 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002910 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002911}
2912
sewardj2d8b3f02002-06-01 14:14:19 +00002913
sewardja1ac5cb2002-05-27 13:00:05 +00002914int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2915{
2916 int res;
2917 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002918 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002919 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002920 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002921 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002922 if (!rwl->initted) {
2923 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002924 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002925 return EINVAL;
2926 }
2927 if (rwl->status != 0) {
2928 /* Reader(s) or a writer active; we have to give up. */
2929 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002930 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002931 return EBUSY;
2932 }
2933 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002934 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002935 rwl->status = -1;
2936 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002937 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002938 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002939}
2940
sewardj2d8b3f02002-06-01 14:14:19 +00002941
sewardja1ac5cb2002-05-27 13:00:05 +00002942int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2943{
2944 int res;
2945 vg_rwlock_t* rwl;
2946 if (0) printf ("pthread_rwlock_unlock\n");
2947 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002948 rwl = rw_remap ( orig );
2949 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002950 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002951 if (!rwl->initted) {
2952 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002953 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002954 return EINVAL;
2955 }
2956 if (rwl->status == 0) {
2957 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002958 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002959 return EPERM;
2960 }
sewardj2d94c112002-06-03 01:25:54 +00002961 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002962 if (rwl->status == -1) {
2963 rwl->status = 0;
2964 } else {
sewardj2d94c112002-06-03 01:25:54 +00002965 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002966 rwl->status--;
2967 }
2968
sewardj2d94c112002-06-03 01:25:54 +00002969 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002970
2971 if (rwl->prefer_w) {
2972
2973 /* Favour waiting writers, if any. */
2974 if (rwl->nwait_w > 0) {
2975 /* Writer(s) are waiting. */
2976 if (rwl->status == 0) {
2977 /* We can let a writer in. */
2978 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002979 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002980 } else {
2981 /* There are still readers active. Do nothing; eventually
2982 they will disappear, at which point a writer will be
2983 admitted. */
2984 }
2985 }
2986 else
2987 /* No waiting writers. */
2988 if (rwl->nwait_r > 0) {
2989 /* Let in a waiting reader. */
2990 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002991 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002992 }
2993
2994 } else {
2995
2996 /* Favour waiting readers, if any. */
2997 if (rwl->nwait_r > 0) {
2998 /* Reader(s) are waiting; let one in. */
2999 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00003000 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003001 }
3002 else
3003 /* No waiting readers. */
3004 if (rwl->nwait_w > 0 && rwl->status == 0) {
3005 /* We have waiting writers and no active readers; let a
3006 writer in. */
3007 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00003008 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003009 }
3010 }
3011
3012 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003013 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003014 return 0;
3015}
3016
3017
3018int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
3019{
3020 int res;
3021 vg_rwlock_t* rwl;
3022 if (0) printf ("pthread_rwlock_destroy\n");
3023 rwl = rw_remap ( orig );
3024 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003025 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003026 if (!rwl->initted) {
3027 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003028 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003029 return EINVAL;
3030 }
3031 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
3032 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003033 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003034 return EBUSY;
3035 }
3036 rwl->initted = 0;
3037 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00003038 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00003039 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00003040}
3041
3042
sewardj47e4e312002-06-18 09:24:34 +00003043/* Copied directly from LinuxThreads. */
3044int
3045pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
3046{
3047 attr->__lockkind = 0;
3048 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
3049
3050 return 0;
3051}
3052
sewardjfe18eb82002-07-13 12:58:44 +00003053/* Copied directly from LinuxThreads. */
3054int
3055pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
3056{
3057 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
3058 return EINVAL;
3059
3060 /* For now it is not possible to shared a conditional variable. */
3061 if (pshared != PTHREAD_PROCESS_PRIVATE)
3062 return ENOSYS;
3063
3064 attr->__pshared = pshared;
3065
3066 return 0;
3067}
3068
sewardj47e4e312002-06-18 09:24:34 +00003069
sewardja1ac5cb2002-05-27 13:00:05 +00003070/* ---------------------------------------------------------------------
sewardjd5bef572002-10-23 21:49:33 +00003071 Make SYSV IPC not block everything
3072 ------------------------------------------------------------------ */
3073
3074#include <sys/ipc.h>
3075#include <sys/msg.h>
3076#include <asm/ipc.h> /* for ipc_kludge */
3077
3078static inline int sys_ipc(unsigned call, int first, int second, int third, void *ptr)
3079{
3080 return my_do_syscall5(__NR_ipc, call, first, second, third, (int)ptr);
3081}
3082
3083/* Turn a blocking msgsnd() into a polling non-blocking one, so that
3084 other threads make progress */
sewardjf220ccc2002-10-23 21:53:49 +00003085int VGL_(msgsnd)(int msgid, const void *msgp, size_t msgsz, int msgflg)
sewardjd5bef572002-10-23 21:49:33 +00003086{
3087 struct vki_timespec nanosleep_interval;
3088 int err;
3089
3090 ensure_valgrind("msgsnd");
3091
3092 nanosleep_interval.tv_sec = 0;
3093 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
3094
3095 if (msgflg & IPC_NOWAIT) {
3096 /* If we aren't blocking anyway, just do it */
3097 err = sys_ipc(11, msgid, msgsz, msgflg, (void *)msgp);
3098 } else {
3099 /* Otherwise poll on the queue to let other things run */
3100 for(;;) {
3101 err = sys_ipc(11, msgid, msgsz, msgflg | IPC_NOWAIT, (void *)msgp);
3102
3103 if (err != -EAGAIN)
3104 break;
3105
3106 (void)my_do_syscall2(__NR_nanosleep,
3107 (int)(&nanosleep_interval), (int)NULL);
3108 }
3109 }
3110
3111 if (is_kerror(err)) {
3112 *(__errno_location()) = -err;
3113 return -1;
3114 }
3115 return 0;
3116}
3117
3118/* Turn a blocking msgrcv() into a polling non-blocking one, so that
3119 other threads make progress */
sewardjf220ccc2002-10-23 21:53:49 +00003120int VGL_(msgrcv)( int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg )
sewardjd5bef572002-10-23 21:49:33 +00003121{
3122 struct vki_timespec nanosleep_interval;
3123 int err;
3124 struct ipc_kludge tmp;
3125
3126 ensure_valgrind("msgrcv");
3127
3128 nanosleep_interval.tv_sec = 0;
3129 nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
3130
3131 tmp.msgp = msgp;
3132 tmp.msgtyp = msgtyp;
3133
3134 if (msgflg & IPC_NOWAIT) {
3135 /* If we aren't blocking anyway, just do it */
3136 err = sys_ipc(12, msqid, msgsz, msgflg, &tmp );
3137 } else {
3138 /* Otherwise poll on the queue to let other things run */
3139 for(;;) {
3140 err = sys_ipc(12, msqid, msgsz, msgflg | IPC_NOWAIT, &tmp );
3141
3142 if (err != -ENOMSG)
3143 break;
3144
3145 (void)my_do_syscall2(__NR_nanosleep,
3146 (int)(&nanosleep_interval), (int)NULL);
3147 }
3148 }
3149
3150 if (is_kerror(err)) {
3151 *(__errno_location()) = -err;
3152 return -1;
3153 }
3154
3155 return 0;
3156}
3157
3158
3159
3160/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00003161 B'stard.
3162 ------------------------------------------------------------------ */
3163
3164# define strong_alias(name, aliasname) \
3165 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
3166
sewardj5905fae2002-04-26 13:25:00 +00003167# define weak_alias(name, aliasname) \
3168 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00003169
sewardj5905fae2002-04-26 13:25:00 +00003170strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
3171strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
3172strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
3173strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
3174 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
3175strong_alias(__pthread_mutex_init, pthread_mutex_init)
3176strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
3177strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
3178strong_alias(__pthread_once, pthread_once)
3179strong_alias(__pthread_atfork, pthread_atfork)
3180strong_alias(__pthread_key_create, pthread_key_create)
3181strong_alias(__pthread_getspecific, pthread_getspecific)
3182strong_alias(__pthread_setspecific, pthread_setspecific)
3183
sewardjd529a442002-05-04 19:49:21 +00003184#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00003185strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00003186#endif
3187
sewardj5905fae2002-04-26 13:25:00 +00003188strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00003189strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00003190strong_alias(lseek, __lseek)
3191strong_alias(open, __open)
3192strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00003193strong_alias(read, __read)
3194strong_alias(wait, __wait)
3195strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00003196strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00003197strong_alias(send, __send)
sewardj3fd559e2002-10-20 16:24:04 +00003198strong_alias(poll, __poll)
3199strong_alias(select, __select)
sewardj5905fae2002-04-26 13:25:00 +00003200
sewardj726c4122002-05-16 23:39:10 +00003201weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00003202weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00003203weak_alias(__fork, fork)
njn25e49d8e72002-09-23 09:36:25 +00003204weak_alias(__vfork, vfork)
sewardj7f6456d2002-05-21 00:51:21 +00003205
sewardjf0b06452002-06-04 08:38:04 +00003206weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00003207
3208/*--------------------------------------------------*/
3209
sewardj5905fae2002-04-26 13:25:00 +00003210weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00003211weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00003212weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00003213
sewardja1ac5cb2002-05-27 13:00:05 +00003214weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
3215weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
3216weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
3217weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
3218
sewardj060b04f2002-04-26 21:01:13 +00003219
sewardj3b13f0e2002-04-25 20:17:29 +00003220/* I've no idea what these are, but they get called quite a lot.
3221 Anybody know? */
3222
3223#undef _IO_flockfile
3224void _IO_flockfile ( _IO_FILE * file )
3225{
sewardj853f55d2002-04-26 00:27:53 +00003226 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003227}
sewardj5905fae2002-04-26 13:25:00 +00003228weak_alias(_IO_flockfile, flockfile);
3229
sewardj3b13f0e2002-04-25 20:17:29 +00003230
3231#undef _IO_funlockfile
3232void _IO_funlockfile ( _IO_FILE * file )
3233{
sewardj853f55d2002-04-26 00:27:53 +00003234 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00003235}
sewardj5905fae2002-04-26 13:25:00 +00003236weak_alias(_IO_funlockfile, funlockfile);
3237
sewardj3b13f0e2002-04-25 20:17:29 +00003238
sewardjd4f2c712002-04-30 10:20:10 +00003239/* This doesn't seem to be needed to simulate libpthread.so's external
3240 interface, but many people complain about its absence. */
3241
3242strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
3243weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00003244
3245
3246/*--------------------------------------------------------------------*/
3247/*--- end vg_libpthread.c ---*/
3248/*--------------------------------------------------------------------*/