blob: 8a74a5c382de9da03a040184c8ee49181dca3910 [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/*
8 This file is part of Valgrind, an x86 protected-mode emulator
9 designed for debugging and profiling binaries on x86-Unixes.
10
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
29 The GNU General Public License is contained in the file LICENSE.
30*/
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
78
sewardje663cb92002-04-12 10:26:32 +000079/* ---------------------------------------------------------------------
80 Helpers. We have to be pretty self-sufficient.
81 ------------------------------------------------------------------ */
82
sewardj436e0582002-04-26 14:31:40 +000083/* Number of times any given error message is printed. */
84#define N_MOANS 3
85
sewardj45b4b372002-04-16 22:50:32 +000086/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
87 Returns 0 (none) if not running on Valgrind. */
88static
89int get_pt_trace_level ( void )
90{
91 int res;
92 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
93 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
94 0, 0, 0, 0);
95 return res;
96}
97
98
sewardje663cb92002-04-12 10:26:32 +000099static
sewardj2d94c112002-06-03 01:25:54 +0000100void my_exit ( int arg )
sewardje663cb92002-04-12 10:26:32 +0000101{
sewardj45b4b372002-04-16 22:50:32 +0000102 int __res;
sewardje663cb92002-04-12 10:26:32 +0000103 __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
104 : "=a" (__res)
105 : "0" (__NR_exit),
106 "c" (arg) );
sewardj45b4b372002-04-16 22:50:32 +0000107 /* We don't bother to mention the fact that this asm trashes %ebx,
108 since it won't return. If you ever do let it return ... fix
109 this! */
sewardje663cb92002-04-12 10:26:32 +0000110}
111
112
sewardj68b2dd92002-05-10 21:03:56 +0000113/* We need this guy -- it's in valgrind.so. */
114extern void VG_(startup) ( void );
115
116
117/* Just start up Valgrind if it's not already going. VG_(startup)()
118 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000119static __inline__
sewardje663cb92002-04-12 10:26:32 +0000120void ensure_valgrind ( char* caller )
121{
sewardj68b2dd92002-05-10 21:03:56 +0000122 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000123}
124
sewardjbea1caa2002-05-10 23:20:58 +0000125/* While we're at it ... hook our own startup function into this
126 game. */
127__asm__ (
128 ".section .init\n"
129 "\tcall vgPlain_startup"
130);
131
sewardje663cb92002-04-12 10:26:32 +0000132
133static
sewardj3b5d8862002-04-20 13:53:23 +0000134__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +0000135void barf ( char* str )
136{
137 char buf[100];
138 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000139 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000140 strcat(buf, str);
141 strcat(buf, "\n\n");
142 write(2, buf, strlen(buf));
sewardj2d94c112002-06-03 01:25:54 +0000143 my_exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000144 /* We have to persuade gcc into believing this doesn't return. */
145 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000146}
147
148
sewardj2a3d28c2002-04-14 13:27:00 +0000149static void ignored ( char* msg )
150{
sewardj436e0582002-04-26 14:31:40 +0000151 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000152 char* ig = "valgrind's libpthread.so: IGNORED call to: ";
sewardj45b4b372002-04-16 22:50:32 +0000153 write(2, ig, strlen(ig));
154 write(2, msg, strlen(msg));
155 ig = "\n";
156 write(2, ig, strlen(ig));
157 }
sewardj2a3d28c2002-04-14 13:27:00 +0000158}
159
sewardj30671ff2002-04-21 00:13:57 +0000160static void kludged ( char* msg )
161{
sewardj436e0582002-04-26 14:31:40 +0000162 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000163 char* ig = "valgrind's libpthread.so: KLUDGED call to: ";
164 write(2, ig, strlen(ig));
165 write(2, msg, strlen(msg));
166 ig = "\n";
167 write(2, ig, strlen(ig));
168 }
169}
170
171static void not_inside ( char* msg )
172{
sewardj68b2dd92002-05-10 21:03:56 +0000173 VG_(startup)();
sewardj30671ff2002-04-21 00:13:57 +0000174}
175
sewardjccef2e62002-05-29 19:26:32 +0000176__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000177void vgPlain_unimp ( char* what )
178{
sewardj439d45e2002-05-03 20:43:10 +0000179 char* ig = "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ";
sewardj3b13f0e2002-04-25 20:17:29 +0000180 write(2, ig, strlen(ig));
181 write(2, what, strlen(what));
182 ig = "\n";
183 write(2, ig, strlen(ig));
184 barf("Please report this bug to me at: jseward@acm.org");
185}
186
sewardje663cb92002-04-12 10:26:32 +0000187
sewardj457cc472002-06-03 23:13:47 +0000188static
sewardj2d94c112002-06-03 01:25:54 +0000189void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
190{
191 static Bool entered = False;
192 if (entered)
193 my_exit(2);
194 entered = True;
195 fprintf(stderr, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
196 "valgrind", file, line, fn, expr );
197 fprintf(stderr, "Please report this bug to me at: %s\n\n",
198 VG_EMAIL_ADDR);
199 my_exit(1);
200}
201
202#define MY__STRING(__str) #__str
203
204#define my_assert(expr) \
205 ((void) ((expr) ? 0 : \
206 (my_assert_fail (MY__STRING(expr), \
207 __FILE__, __LINE__, \
208 __PRETTY_FUNCTION__), 0)))
209
210
sewardje663cb92002-04-12 10:26:32 +0000211/* ---------------------------------------------------------------------
212 Pass pthread_ calls to Valgrind's request mechanism.
213 ------------------------------------------------------------------ */
214
sewardjf8f819e2002-04-17 23:21:37 +0000215#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000216#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000217
sewardja1ac5cb2002-05-27 13:00:05 +0000218
sewardjf8f819e2002-04-17 23:21:37 +0000219/* ---------------------------------------------------
sewardj4dced352002-06-04 22:54:20 +0000220 Ummm ..
221 ------------------------------------------------ */
222
223static
224void pthread_error ( const char* msg )
225{
226 int res;
227 VALGRIND_MAGIC_SEQUENCE(res, 0,
228 VG_USERREQ__PTHREAD_ERROR,
229 msg, 0, 0, 0);
230}
231
232
233/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000234 THREAD ATTRIBUTES
235 ------------------------------------------------ */
236
sewardj6af4b5d2002-04-16 04:40:49 +0000237int pthread_attr_init(pthread_attr_t *attr)
238{
sewardj7989d0c2002-05-28 11:00:01 +0000239 /* Just initialise the fields which we might look at. */
240 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj6af4b5d2002-04-16 04:40:49 +0000241 return 0;
242}
243
244int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
245{
sewardj7989d0c2002-05-28 11:00:01 +0000246 if (detachstate != PTHREAD_CREATE_JOINABLE
sewardj4dced352002-06-04 22:54:20 +0000247 && detachstate != PTHREAD_CREATE_DETACHED) {
248 pthread_error("pthread_attr_setdetachstate: "
249 "detachstate is invalid");
sewardj7989d0c2002-05-28 11:00:01 +0000250 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000251 }
sewardj7989d0c2002-05-28 11:00:01 +0000252 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000253 return 0;
254}
255
sewardj30671ff2002-04-21 00:13:57 +0000256int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
257{
sewardj436e0582002-04-26 14:31:40 +0000258 static int moans = N_MOANS;
259 if (moans-- > 0)
260 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000261 return 0;
262}
sewardj6af4b5d2002-04-16 04:40:49 +0000263
sewardj0286dd52002-05-16 20:51:15 +0000264__attribute__((weak))
265int pthread_attr_setstacksize (pthread_attr_t *__attr,
266 size_t __stacksize)
267{
sewardja18e2102002-05-18 10:43:22 +0000268 size_t limit;
sewardj3d7c8d62002-06-04 20:59:16 +0000269 char buf[1024];
sewardj0286dd52002-05-16 20:51:15 +0000270 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000271 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
272 - 1000; /* paranoia */
273 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000274 return 0;
sewardj3d7c8d62002-06-04 20:59:16 +0000275 snprintf(buf, sizeof(buf), "pthread_attr_setstacksize: "
276 "requested size %d >= VG_PTHREAD_STACK_SIZE\n "
277 "edit vg_include.h and rebuild.", __stacksize);
278 buf[sizeof(buf)-1] = '\0'; /* Make sure it is zero terminated */
279 barf(buf);
sewardj0286dd52002-05-16 20:51:15 +0000280}
281
282
sewardj30671ff2002-04-21 00:13:57 +0000283/* This is completely bogus. */
284int pthread_attr_getschedparam(const pthread_attr_t *attr,
285 struct sched_param *param)
286{
sewardj436e0582002-04-26 14:31:40 +0000287 static int moans = N_MOANS;
288 if (moans-- > 0)
289 kludged("pthread_attr_getschedparam");
sewardj3e909ce2002-06-03 13:27:15 +0000290# ifdef HAVE_SCHED_PRIORITY
sewardj72d58482002-04-24 02:20:20 +0000291 if (param) param->sched_priority = 0; /* who knows */
292# else
sewardj30671ff2002-04-21 00:13:57 +0000293 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000294# endif
sewardj30671ff2002-04-21 00:13:57 +0000295 return 0;
296}
297
298int pthread_attr_setschedparam(pthread_attr_t *attr,
299 const struct sched_param *param)
300{
sewardj436e0582002-04-26 14:31:40 +0000301 static int moans = N_MOANS;
302 if (moans-- > 0)
303 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000304 return 0;
305}
306
307int pthread_attr_destroy(pthread_attr_t *attr)
308{
sewardj436e0582002-04-26 14:31:40 +0000309 static int moans = N_MOANS;
310 if (moans-- > 0)
311 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000312 return 0;
313}
sewardjf8f819e2002-04-17 23:21:37 +0000314
sewardj0d844232002-06-02 09:29:31 +0000315/* These are no-ops, as with LinuxThreads. */
316int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
317{
318 ensure_valgrind("pthread_attr_setscope");
319 if (scope == PTHREAD_SCOPE_SYSTEM)
320 return 0;
sewardj4dced352002-06-04 22:54:20 +0000321 pthread_error("pthread_attr_setscope: "
322 "invalid or unsupported scope");
sewardj0d844232002-06-02 09:29:31 +0000323 if (scope == PTHREAD_SCOPE_PROCESS)
324 return ENOTSUP;
325 return EINVAL;
326}
327
328int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
329{
330 ensure_valgrind("pthread_attr_setscope");
331 if (scope)
332 *scope = PTHREAD_SCOPE_SYSTEM;
333 return 0;
334}
335
sewardj64039bb2002-06-03 00:58:18 +0000336
337/* Pretty bogus. Avoid if possible. */
338int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
339{
340 int detached;
341 size_t limit;
342 ensure_valgrind("pthread_getattr_np");
343 kludged("pthread_getattr_np");
344 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
345 - 1000; /* paranoia */
346 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
347 attr->__schedpolicy = SCHED_OTHER;
348 attr->__schedparam.sched_priority = 0;
349 attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
350 attr->__scope = PTHREAD_SCOPE_SYSTEM;
351 attr->__guardsize = VKI_BYTES_PER_PAGE;
352 attr->__stackaddr = NULL;
353 attr->__stackaddr_set = 0;
354 attr->__stacksize = limit;
355 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
356 VG_USERREQ__SET_OR_GET_DETACH,
357 2 /* get */, thread, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000358 my_assert(detached == 0 || detached == 1);
sewardj64039bb2002-06-03 00:58:18 +0000359 if (detached)
360 attr->__detachstate = PTHREAD_CREATE_DETACHED;
361 return 0;
362}
363
364
365/* Bogus ... */
366int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
367 void ** stackaddr )
368{
369 ensure_valgrind("pthread_attr_getstackaddr");
370 kludged("pthread_attr_getstackaddr");
371 if (stackaddr)
372 *stackaddr = NULL;
373 return 0;
374}
375
376/* Not bogus (!) */
377int pthread_attr_getstacksize ( const pthread_attr_t * _attr,
378 size_t * __stacksize )
379{
380 size_t limit;
381 ensure_valgrind("pthread_attr_getstacksize");
382 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
383 - 1000; /* paranoia */
384 if (__stacksize)
385 *__stacksize = limit;
386 return 0;
387}
388
sewardj20917d82002-05-28 01:36:45 +0000389/* ---------------------------------------------------
390 Helper functions for running a thread
391 and for clearing up afterwards.
392 ------------------------------------------------ */
393
394/* All exiting threads eventually pass through here, bearing the
395 return value, or PTHREAD_CANCELED, in ret_val. */
396static
397__attribute__((noreturn))
398void thread_exit_wrapper ( void* ret_val )
399{
sewardj870497a2002-05-29 01:06:47 +0000400 int detached, res;
401 CleanupEntry cu;
402 pthread_key_t key;
403
sewardj20917d82002-05-28 01:36:45 +0000404 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000405 while (1) {
406 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
407 VG_USERREQ__CLEANUP_POP,
408 &cu, 0, 0, 0);
409 if (res == -1) break; /* stack empty */
sewardj2d94c112002-06-03 01:25:54 +0000410 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000411 if (0) printf("running exit cleanup handler");
412 cu.fn ( cu.arg );
413 }
414
sewardj870497a2002-05-29 01:06:47 +0000415 /* Run this thread's key finalizers. Really this should be run
416 PTHREAD_DESTRUCTOR_ITERATIONS times. */
417 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
418 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
419 VG_USERREQ__GET_KEY_D_AND_S,
420 key, &cu, 0, 0 );
421 if (res == 0) {
422 /* valid key */
423 if (cu.fn && cu.arg)
424 cu.fn /* destructor for key */
425 ( cu.arg /* specific for key for this thread */ );
426 continue;
427 }
sewardj2d94c112002-06-03 01:25:54 +0000428 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000429 }
sewardj20917d82002-05-28 01:36:45 +0000430
431 /* Decide on my final disposition. */
432 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
433 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000434 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000435 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000436
437 if (detached) {
438 /* Detached; I just quit right now. */
439 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
440 VG_USERREQ__QUIT, 0, 0, 0, 0);
441 } else {
442 /* Not detached; so I wait for a joiner. */
443 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
444 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
445 }
446 /* NOTREACHED */
447 barf("thread_exit_wrapper: still alive?!");
448}
449
450
451/* This function is a wrapper function for running a thread. It runs
452 the root function specified in pthread_create, and then, should the
453 root function return a value, it arranges to run the thread's
454 cleanup handlers and exit correctly. */
455
456/* Struct used to convey info from pthread_create to
457 thread_wrapper. */
458typedef
459 struct {
460 pthread_attr_t* attr;
461 void* (*root_fn) ( void* );
462 void* arg;
463 }
464 NewThreadInfo;
465
466
467/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
468 not return. Note that this runs in the new thread, not the
469 parent. */
470static
471__attribute__((noreturn))
472void thread_wrapper ( NewThreadInfo* info )
473{
474 int res;
475 pthread_attr_t* attr;
476 void* (*root_fn) ( void* );
477 void* arg;
478 void* ret_val;
479
480 attr = info->attr;
481 root_fn = info->root_fn;
482 arg = info->arg;
483
sewardj20917d82002-05-28 01:36:45 +0000484 /* Free up the arg block that pthread_create malloced. */
485 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
486 VG_USERREQ__FREE, info, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000487 my_assert(res == 0);
sewardj20917d82002-05-28 01:36:45 +0000488
sewardj7989d0c2002-05-28 11:00:01 +0000489 /* Minimally observe the attributes supplied. */
490 if (attr) {
sewardj2d94c112002-06-03 01:25:54 +0000491 my_assert(attr->__detachstate == PTHREAD_CREATE_DETACHED
sewardj7989d0c2002-05-28 11:00:01 +0000492 || attr->__detachstate == PTHREAD_CREATE_JOINABLE);
493 if (attr->__detachstate == PTHREAD_CREATE_DETACHED)
494 pthread_detach(pthread_self());
495 }
496
sewardj20917d82002-05-28 01:36:45 +0000497 /* The root function might not return. But if it does we simply
498 move along to thread_exit_wrapper. All other ways out for the
499 thread (cancellation, or calling pthread_exit) lead there
500 too. */
501 ret_val = root_fn(arg);
502 thread_exit_wrapper(ret_val);
503 /* NOTREACHED */
504}
505
506
sewardjf8f819e2002-04-17 23:21:37 +0000507/* ---------------------------------------------------
508 THREADs
509 ------------------------------------------------ */
510
sewardjff42d1d2002-05-22 13:17:31 +0000511__attribute__((weak))
512int pthread_yield ( void )
513{
514 int res;
515 ensure_valgrind("pthread_yield");
516 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
517 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
518 return 0;
519}
520
521
sewardj6072c362002-04-19 14:40:57 +0000522int pthread_equal(pthread_t thread1, pthread_t thread2)
523{
524 return thread1 == thread2 ? 1 : 0;
525}
526
527
sewardj20917d82002-05-28 01:36:45 +0000528/* Bundle up the args into a malloc'd block and create a new thread
529 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000530int
531pthread_create (pthread_t *__restrict __thread,
532 __const pthread_attr_t *__restrict __attr,
533 void *(*__start_routine) (void *),
534 void *__restrict __arg)
535{
sewardj20917d82002-05-28 01:36:45 +0000536 int tid_child;
537 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000538
sewardj20917d82002-05-28 01:36:45 +0000539 ensure_valgrind("pthread_create");
540
541 /* Allocate space for the arg block. thread_wrapper will free
542 it. */
543 VALGRIND_MAGIC_SEQUENCE(info, NULL /* default */,
544 VG_USERREQ__MALLOC,
545 sizeof(NewThreadInfo), 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000546 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000547
548 info->attr = (pthread_attr_t*)__attr;
549 info->root_fn = __start_routine;
550 info->arg = __arg;
551 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
552 VG_USERREQ__APPLY_IN_NEW_THREAD,
553 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000554 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000555
556 if (__thread)
557 *__thread = tid_child;
558 return 0; /* success */
559}
sewardje663cb92002-04-12 10:26:32 +0000560
561
562int
563pthread_join (pthread_t __th, void **__thread_return)
564{
565 int res;
566 ensure_valgrind("pthread_join");
567 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
568 VG_USERREQ__PTHREAD_JOIN,
569 __th, __thread_return, 0, 0);
570 return res;
571}
572
573
sewardj3b5d8862002-04-20 13:53:23 +0000574void pthread_exit(void *retval)
575{
sewardj3b5d8862002-04-20 13:53:23 +0000576 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000577 /* Simple! */
578 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000579}
580
sewardje663cb92002-04-12 10:26:32 +0000581
sewardj3b13f0e2002-04-25 20:17:29 +0000582pthread_t pthread_self(void)
sewardje663cb92002-04-12 10:26:32 +0000583{
584 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000585 ensure_valgrind("pthread_self");
sewardj439d45e2002-05-03 20:43:10 +0000586 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardje663cb92002-04-12 10:26:32 +0000587 VG_USERREQ__PTHREAD_GET_THREADID,
588 0, 0, 0, 0);
sewardj439d45e2002-05-03 20:43:10 +0000589 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000590 barf("pthread_self: invalid ThreadId");
591 return tid;
sewardje663cb92002-04-12 10:26:32 +0000592}
593
594
sewardj853f55d2002-04-26 00:27:53 +0000595int pthread_detach(pthread_t th)
596{
sewardj20917d82002-05-28 01:36:45 +0000597 int res;
598 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000599 /* First we enquire as to the current detach state. */
600 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000601 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000602 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000603 if (res == -1) {
604 /* not found */
605 pthread_error("pthread_detach: "
606 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000607 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000608 }
609 if (res == 1) {
610 /* already detached */
611 pthread_error("pthread_detach: "
612 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000613 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000614 }
sewardj7989d0c2002-05-28 11:00:01 +0000615 if (res == 0) {
616 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
617 VG_USERREQ__SET_OR_GET_DETACH,
618 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000619 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000620 return 0;
621 }
622 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000623}
624
625
sewardjf8f819e2002-04-17 23:21:37 +0000626/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000627 CLEANUP STACKS
628 ------------------------------------------------ */
629
630void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
631 void (*__routine) (void *),
632 void *__arg)
633{
634 int res;
635 CleanupEntry cu;
636 ensure_valgrind("_pthread_cleanup_push");
637 cu.fn = __routine;
638 cu.arg = __arg;
639 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
640 VG_USERREQ__CLEANUP_PUSH,
641 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000642 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000643}
644
645
646void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
647 void (*__routine) (void *),
648 void *__arg)
649{
650 /* As _pthread_cleanup_push, but first save the thread's original
651 cancellation type in __buffer and set it to Deferred. */
652 int orig_ctype;
653 ensure_valgrind("_pthread_cleanup_push_defer");
654 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000655 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
656 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
657 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000658 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
659 VG_USERREQ__SET_CANCELTYPE,
660 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000661 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000662 *((int*)(__buffer)) = orig_ctype;
663 /* Now push the cleanup. */
664 _pthread_cleanup_push(NULL, __routine, __arg);
665}
666
667
668void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
669 int __execute)
670{
671 int res;
672 CleanupEntry cu;
673 ensure_valgrind("_pthread_cleanup_push");
674 cu.fn = cu.arg = NULL; /* paranoia */
675 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
676 VG_USERREQ__CLEANUP_POP,
677 &cu, 0, 0, 0);
678 if (res == 0) {
679 /* pop succeeded */
680 if (__execute) {
681 cu.fn ( cu.arg );
682 }
683 return;
684 }
685 if (res == -1) {
686 /* stack underflow */
687 return;
688 }
689 barf("_pthread_cleanup_pop");
690}
691
692
693void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
694 int __execute)
695{
696 int orig_ctype, fake_ctype;
697 /* As _pthread_cleanup_pop, but after popping/running the handler,
698 restore the thread's original cancellation type from the first
699 word of __buffer. */
700 _pthread_cleanup_pop(NULL, __execute);
701 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000702 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000703 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000704 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
705 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
706 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000707 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
708 VG_USERREQ__SET_CANCELTYPE,
709 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000710 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000711}
712
713
714/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000715 MUTEX ATTRIBUTES
716 ------------------------------------------------ */
717
sewardj5905fae2002-04-26 13:25:00 +0000718int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000719{
sewardjf8f819e2002-04-17 23:21:37 +0000720 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000721 return 0;
sewardje663cb92002-04-12 10:26:32 +0000722}
723
sewardj5905fae2002-04-26 13:25:00 +0000724int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000725{
726 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000727# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000728 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000729 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000730# endif
sewardja1679dd2002-05-10 22:31:40 +0000731# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000732 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000733# endif
sewardjf8f819e2002-04-17 23:21:37 +0000734 case PTHREAD_MUTEX_RECURSIVE_NP:
735 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000736 attr->__mutexkind = type;
737 return 0;
738 default:
sewardj4dced352002-06-04 22:54:20 +0000739 pthread_error("pthread_mutexattr_settype: "
740 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000741 return EINVAL;
742 }
743}
744
sewardj5905fae2002-04-26 13:25:00 +0000745int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000746{
747 return 0;
748}
749
750
751/* ---------------------------------------------------
752 MUTEXes
753 ------------------------------------------------ */
754
sewardj5905fae2002-04-26 13:25:00 +0000755int __pthread_mutex_init(pthread_mutex_t *mutex,
756 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000757{
sewardj604ec3c2002-04-18 22:38:41 +0000758 mutex->__m_count = 0;
759 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
760 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
761 if (mutexattr)
762 mutex->__m_kind = mutexattr->__mutexkind;
763 return 0;
sewardje663cb92002-04-12 10:26:32 +0000764}
765
sewardj439d45e2002-05-03 20:43:10 +0000766
sewardj5905fae2002-04-26 13:25:00 +0000767int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000768{
769 int res;
sewardj436e0582002-04-26 14:31:40 +0000770 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000771 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000772 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
773 VG_USERREQ__PTHREAD_MUTEX_LOCK,
774 mutex, 0, 0, 0);
775 return res;
sewardj439d45e2002-05-03 20:43:10 +0000776 } else {
777 if (moans-- > 0)
778 not_inside("pthread_mutex_lock");
779 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000780 }
781}
782
sewardj439d45e2002-05-03 20:43:10 +0000783
sewardj5905fae2002-04-26 13:25:00 +0000784int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000785{
786 int res;
sewardj436e0582002-04-26 14:31:40 +0000787 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000788 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000789 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
790 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
791 mutex, 0, 0, 0);
792 return res;
sewardj439d45e2002-05-03 20:43:10 +0000793 } else {
794 if (moans-- > 0)
795 not_inside("pthread_mutex_trylock");
796 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000797 }
798}
799
sewardj439d45e2002-05-03 20:43:10 +0000800
sewardj5905fae2002-04-26 13:25:00 +0000801int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000802{
803 int res;
sewardj436e0582002-04-26 14:31:40 +0000804 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000805 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000806 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
807 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
808 mutex, 0, 0, 0);
809 return res;
sewardj439d45e2002-05-03 20:43:10 +0000810 } else {
811 if (moans-- > 0)
812 not_inside("pthread_mutex_unlock");
813 return 0;
sewardje663cb92002-04-12 10:26:32 +0000814 }
815}
816
sewardj439d45e2002-05-03 20:43:10 +0000817
sewardj5905fae2002-04-26 13:25:00 +0000818int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000819{
sewardj604ec3c2002-04-18 22:38:41 +0000820 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
821 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +0000822 if (mutex->__m_count > 0) {
823 pthread_error("pthread_mutex_destroy: "
824 "mutex is still in use");
sewardj604ec3c2002-04-18 22:38:41 +0000825 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +0000826 }
827 mutex->__m_count = 0;
828 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
829 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
830 return 0;
sewardje663cb92002-04-12 10:26:32 +0000831}
832
833
sewardjf8f819e2002-04-17 23:21:37 +0000834/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000835 CONDITION VARIABLES
836 ------------------------------------------------ */
837
838/* LinuxThreads supports no attributes for conditions. Hence ... */
839
840int pthread_condattr_init(pthread_condattr_t *attr)
841{
842 return 0;
843}
844
sewardj0738a592002-04-20 13:59:33 +0000845int pthread_condattr_destroy(pthread_condattr_t *attr)
846{
847 return 0;
848}
sewardj6072c362002-04-19 14:40:57 +0000849
850int pthread_cond_init( pthread_cond_t *cond,
851 const pthread_condattr_t *cond_attr)
852{
853 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
854 return 0;
855}
856
sewardjf854f472002-04-21 12:19:41 +0000857int pthread_cond_destroy(pthread_cond_t *cond)
858{
859 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000860 static int moans = N_MOANS;
861 if (moans-- > 0)
862 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000863 return 0;
864}
sewardj6072c362002-04-19 14:40:57 +0000865
866/* ---------------------------------------------------
867 SCHEDULING
868 ------------------------------------------------ */
869
870/* This is completely bogus. */
871int pthread_getschedparam(pthread_t target_thread,
872 int *policy,
873 struct sched_param *param)
874{
sewardj436e0582002-04-26 14:31:40 +0000875 static int moans = N_MOANS;
876 if (moans-- > 0)
877 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000878 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +0000879# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +0000880 if (param) param->sched_priority = 0; /* who knows */
881# else
sewardj6072c362002-04-19 14:40:57 +0000882 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000883# endif
sewardj6072c362002-04-19 14:40:57 +0000884 return 0;
885}
886
887int pthread_setschedparam(pthread_t target_thread,
888 int policy,
889 const struct sched_param *param)
890{
sewardj436e0582002-04-26 14:31:40 +0000891 static int moans = N_MOANS;
892 if (moans-- > 0)
893 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000894 return 0;
895}
896
sewardj3b5d8862002-04-20 13:53:23 +0000897int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
898{
899 int res;
900 ensure_valgrind("pthread_cond_wait");
901 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
902 VG_USERREQ__PTHREAD_COND_WAIT,
903 cond, mutex, 0, 0);
904 return res;
905}
906
sewardj5f07b662002-04-23 16:52:51 +0000907int pthread_cond_timedwait ( pthread_cond_t *cond,
908 pthread_mutex_t *mutex,
909 const struct timespec *abstime )
910{
911 int res;
912 unsigned int ms_now, ms_end;
913 struct timeval timeval_now;
914 unsigned long long int ull_ms_now_after_1970;
915 unsigned long long int ull_ms_end_after_1970;
916
917 ensure_valgrind("pthread_cond_timedwait");
918 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
919 VG_USERREQ__READ_MILLISECOND_TIMER,
920 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000921 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +0000922 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +0000923 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +0000924
925 ull_ms_now_after_1970
926 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
927 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
928 ull_ms_end_after_1970
929 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
930 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +0000931 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
932 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +0000933 ms_end
934 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
935 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
936 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
937 cond, mutex, ms_end, 0);
938 return res;
939}
940
941
sewardj3b5d8862002-04-20 13:53:23 +0000942int pthread_cond_signal(pthread_cond_t *cond)
943{
944 int res;
945 ensure_valgrind("pthread_cond_signal");
946 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
947 VG_USERREQ__PTHREAD_COND_SIGNAL,
948 cond, 0, 0, 0);
949 return res;
950}
951
952int pthread_cond_broadcast(pthread_cond_t *cond)
953{
954 int res;
955 ensure_valgrind("pthread_cond_broadcast");
956 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
957 VG_USERREQ__PTHREAD_COND_BROADCAST,
958 cond, 0, 0, 0);
959 return res;
960}
961
sewardj6072c362002-04-19 14:40:57 +0000962
963/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000964 CANCELLATION
965 ------------------------------------------------ */
966
sewardj853f55d2002-04-26 00:27:53 +0000967int pthread_setcancelstate(int state, int *oldstate)
968{
sewardj20917d82002-05-28 01:36:45 +0000969 int res;
970 ensure_valgrind("pthread_setcancelstate");
971 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +0000972 && state != PTHREAD_CANCEL_DISABLE) {
973 pthread_error("pthread_setcancelstate: "
974 "invalid state");
sewardj20917d82002-05-28 01:36:45 +0000975 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000976 }
sewardj2d94c112002-06-03 01:25:54 +0000977 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
978 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +0000979 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
980 VG_USERREQ__SET_CANCELSTATE,
981 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000982 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +0000983 if (oldstate)
984 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +0000985 return 0;
986}
987
sewardje663cb92002-04-12 10:26:32 +0000988int pthread_setcanceltype(int type, int *oldtype)
989{
sewardj20917d82002-05-28 01:36:45 +0000990 int res;
991 ensure_valgrind("pthread_setcanceltype");
992 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +0000993 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
994 pthread_error("pthread_setcanceltype: "
995 "invalid type");
sewardj20917d82002-05-28 01:36:45 +0000996 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000997 }
sewardj2d94c112002-06-03 01:25:54 +0000998 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
999 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001000 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1001 VG_USERREQ__SET_CANCELTYPE,
1002 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001003 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001004 if (oldtype)
1005 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001006 return 0;
1007}
1008
sewardje663cb92002-04-12 10:26:32 +00001009int pthread_cancel(pthread_t thread)
1010{
1011 int res;
1012 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001013 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1014 VG_USERREQ__SET_CANCELPEND,
1015 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001016 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001017 return res;
1018}
1019
sewardjd140e442002-05-29 01:21:19 +00001020static __inline__
1021void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001022{
sewardj20917d82002-05-28 01:36:45 +00001023 int res;
1024 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1025 VG_USERREQ__TESTCANCEL,
1026 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001027 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001028}
1029
sewardjd140e442002-05-29 01:21:19 +00001030void pthread_testcancel ( void )
1031{
1032 __my_pthread_testcancel();
1033}
1034
sewardj20917d82002-05-28 01:36:45 +00001035
sewardjef037c72002-05-30 00:40:03 +00001036/* Not really sure what this is for. I suspect for doing the POSIX
1037 requirements for fork() and exec(). We do this internally anyway
1038 whenever those syscalls are observed, so this could be superfluous,
1039 but hey ...
1040*/
sewardj853f55d2002-04-26 00:27:53 +00001041void __pthread_kill_other_threads_np ( void )
1042{
sewardjef037c72002-05-30 00:40:03 +00001043 int res;
1044 ensure_valgrind("__pthread_kill_other_threads_np");
1045 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1046 VG_USERREQ__NUKE_OTHER_THREADS,
1047 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001048 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001049}
1050
sewardje663cb92002-04-12 10:26:32 +00001051
sewardjf8f819e2002-04-17 23:21:37 +00001052/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001053 SIGNALS
1054 ------------------------------------------------ */
1055
1056#include <signal.h>
1057
1058int pthread_sigmask(int how, const sigset_t *newmask,
1059 sigset_t *oldmask)
1060{
1061 int res;
1062
1063 /* A bit subtle, because the scheduler expects newmask and oldmask
1064 to be vki_sigset_t* rather than sigset_t*, and the two are
1065 different. Fortunately the first 64 bits of a sigset_t are
1066 exactly a vki_sigset_t, so we just pass the pointers through
1067 unmodified. Haaaack!
1068
1069 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001070 constants to VKI_ constants, so that the former do not have to
1071 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001072
1073 ensure_valgrind("pthread_sigmask");
1074
1075 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001076 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1077 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1078 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001079 default: pthread_error("pthread_sigmask: invalid how");
1080 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001081 }
1082
1083 /* Crude check */
1084 if (newmask == NULL)
1085 return EFAULT;
1086
1087 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1088 VG_USERREQ__PTHREAD_SIGMASK,
1089 how, newmask, oldmask, 0);
1090
1091 /* The scheduler tells us of any memory violations. */
1092 return res == 0 ? 0 : EFAULT;
1093}
1094
1095
1096int sigwait ( const sigset_t* set, int* sig )
1097{
1098 int res;
1099 ensure_valgrind("sigwait");
1100 /* As with pthread_sigmask we deliberately confuse sigset_t with
1101 vki_ksigset_t. */
1102 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1103 VG_USERREQ__SIGWAIT,
1104 set, sig, 0, 0);
1105 return res;
1106}
1107
1108
sewardj018f7622002-05-15 21:13:39 +00001109int pthread_kill(pthread_t thread, int signo)
1110{
1111 int res;
1112 ensure_valgrind("pthread_kill");
1113 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1114 VG_USERREQ__PTHREAD_KILL,
1115 thread, signo, 0, 0);
1116 return res;
1117}
1118
1119
sewardj3665ded2002-05-16 16:57:25 +00001120/* Copied verbatim from Linuxthreads */
1121/* Redefine raise() to send signal to calling thread only,
1122 as per POSIX 1003.1c */
1123int raise (int sig)
1124{
1125 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001126 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001127 return 0;
sewardj4dced352002-06-04 22:54:20 +00001128 } else {
sewardj3665ded2002-05-16 16:57:25 +00001129 errno = retcode;
1130 return -1;
1131 }
1132}
1133
1134
sewardjb48e5002002-05-13 00:16:03 +00001135/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001136 THREAD-SPECIFICs
1137 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001138
sewardj5905fae2002-04-26 13:25:00 +00001139int __pthread_key_create(pthread_key_t *key,
1140 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001141{
sewardj5f07b662002-04-23 16:52:51 +00001142 int res;
1143 ensure_valgrind("pthread_key_create");
1144 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1145 VG_USERREQ__PTHREAD_KEY_CREATE,
1146 key, destr_function, 0, 0);
1147 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001148}
1149
1150int pthread_key_delete(pthread_key_t key)
1151{
sewardj436e0582002-04-26 14:31:40 +00001152 static int moans = N_MOANS;
1153 if (moans-- > 0)
1154 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +00001155 return 0;
1156}
1157
sewardj5905fae2002-04-26 13:25:00 +00001158int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001159{
sewardj5f07b662002-04-23 16:52:51 +00001160 int res;
1161 ensure_valgrind("pthread_setspecific");
1162 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1163 VG_USERREQ__PTHREAD_SETSPECIFIC,
1164 key, pointer, 0, 0);
1165 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001166}
1167
sewardj5905fae2002-04-26 13:25:00 +00001168void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001169{
sewardj5f07b662002-04-23 16:52:51 +00001170 int res;
1171 ensure_valgrind("pthread_getspecific");
1172 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1173 VG_USERREQ__PTHREAD_GETSPECIFIC,
1174 key, 0 , 0, 0);
1175 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001176}
1177
sewardjf8f819e2002-04-17 23:21:37 +00001178
1179/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001180 ONCEry
1181 ------------------------------------------------ */
1182
1183static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1184
1185
sewardj5905fae2002-04-26 13:25:00 +00001186int __pthread_once ( pthread_once_t *once_control,
1187 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001188{
1189 int res;
1190 ensure_valgrind("pthread_once");
1191
sewardj68b2dd92002-05-10 21:03:56 +00001192 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001193
sewardj68b2dd92002-05-10 21:03:56 +00001194 if (res != 0) {
sewardj89d3d852002-04-24 19:21:39 +00001195 barf("pthread_once: Looks like your program's "
1196 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001197 }
sewardj89d3d852002-04-24 19:21:39 +00001198
1199 if (*once_control == 0) {
1200 *once_control = 1;
1201 init_routine();
1202 }
1203
sewardj68b2dd92002-05-10 21:03:56 +00001204 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001205
1206 return 0;
1207}
1208
1209
1210/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001211 MISC
1212 ------------------------------------------------ */
1213
sewardj5905fae2002-04-26 13:25:00 +00001214int __pthread_atfork ( void (*prepare)(void),
1215 void (*parent)(void),
1216 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001217{
sewardjccef2e62002-05-29 19:26:32 +00001218 /* We have to do this properly or not at all; faking it isn't an
1219 option. */
1220 vgPlain_unimp("__pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +00001221}
1222
1223
sewardjbb990782002-05-08 02:01:14 +00001224__attribute__((weak))
1225void __pthread_initialize ( void )
1226{
sewardjbea1caa2002-05-10 23:20:58 +00001227 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001228}
1229
1230
sewardj853f55d2002-04-26 00:27:53 +00001231/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001232 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001233 ------------------------------------------------ */
1234
sewardj3b13f0e2002-04-25 20:17:29 +00001235#include <resolv.h>
1236static int thread_specific_errno[VG_N_THREADS];
1237static int thread_specific_h_errno[VG_N_THREADS];
1238static struct __res_state
1239 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001240
sewardj3b13f0e2002-04-25 20:17:29 +00001241int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001242{
1243 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001244 /* ensure_valgrind("__errno_location"); */
1245 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001246 VG_USERREQ__PTHREAD_GET_THREADID,
1247 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001248 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001249 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001250 barf("__errno_location: invalid ThreadId");
1251 return & thread_specific_errno[tid];
1252}
1253
1254int* __h_errno_location ( void )
1255{
1256 int tid;
1257 /* ensure_valgrind("__h_errno_location"); */
1258 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1259 VG_USERREQ__PTHREAD_GET_THREADID,
1260 0, 0, 0, 0);
1261 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001262 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001263 barf("__h_errno_location: invalid ThreadId");
1264 return & thread_specific_h_errno[tid];
1265}
1266
1267struct __res_state* __res_state ( void )
1268{
1269 int tid;
1270 /* ensure_valgrind("__res_state"); */
1271 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1272 VG_USERREQ__PTHREAD_GET_THREADID,
1273 0, 0, 0, 0);
1274 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001275 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001276 barf("__res_state: invalid ThreadId");
1277 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001278}
1279
1280
sewardj5716dbb2002-04-26 03:28:18 +00001281/* ---------------------------------------------------
1282 LIBC-PRIVATE SPECIFIC DATA
1283 ------------------------------------------------ */
1284
1285/* Relies on assumption that initial private data is NULL. This
1286 should be fixed somehow. */
1287
1288/* The allowable keys (indices) (all 2 of them).
1289 From sysdeps/pthread/bits/libc-tsd.h
1290*/
sewardj70adeb22002-04-27 01:35:38 +00001291#define N_LIBC_TSD_EXTRA_KEYS 1
1292
sewardj5716dbb2002-04-26 03:28:18 +00001293enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1294 _LIBC_TSD_KEY_DL_ERROR,
1295 _LIBC_TSD_KEY_N };
1296
1297/* Auto-initialising subsystem. libc_specifics_inited is set
1298 after initialisation. libc_specifics_inited_mx guards it. */
1299static int libc_specifics_inited = 0;
1300static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1301
1302/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001303static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1304 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001305
1306/* Initialise the keys, if they are not already initialise. */
1307static
1308void init_libc_tsd_keys ( void )
1309{
1310 int res, i;
1311 pthread_key_t k;
1312
1313 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1314 if (res != 0) barf("init_libc_tsd_keys: lock");
1315
1316 if (libc_specifics_inited == 0) {
1317 /* printf("INIT libc specifics\n"); */
1318 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001319 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001320 res = pthread_key_create(&k, NULL);
1321 if (res != 0) barf("init_libc_tsd_keys: create");
1322 libc_specifics_keys[i] = k;
1323 }
1324 }
1325
1326 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1327 if (res != 0) barf("init_libc_tsd_keys: unlock");
1328}
1329
1330
1331static int
1332libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1333 const void * pointer )
1334{
sewardj70adeb22002-04-27 01:35:38 +00001335 int res;
1336 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001337 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001338 if (key < _LIBC_TSD_KEY_MALLOC
1339 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001340 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001341 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1342 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001343 "valgrind's libpthread.so: libc_internal_tsd_set: "
1344 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001345 init_libc_tsd_keys();
1346 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1347 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1348 return 0;
1349}
1350
1351static void *
1352libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1353{
sewardj70adeb22002-04-27 01:35:38 +00001354 void* v;
1355 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001356 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001357 if (key < _LIBC_TSD_KEY_MALLOC
1358 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001359 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001360 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1361 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001362 "valgrind's libpthread.so: libc_internal_tsd_get: "
1363 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001364 init_libc_tsd_keys();
1365 v = pthread_getspecific(libc_specifics_keys[key]);
1366 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1367 return v;
1368}
1369
1370
1371
1372
sewardj70adeb22002-04-27 01:35:38 +00001373int (*__libc_internal_tsd_set)
1374 (enum __libc_tsd_key_t key, const void * pointer)
1375 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001376
sewardj70adeb22002-04-27 01:35:38 +00001377void* (*__libc_internal_tsd_get)
1378 (enum __libc_tsd_key_t key)
1379 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001380
1381
sewardje663cb92002-04-12 10:26:32 +00001382/* ---------------------------------------------------------------------
1383 These are here (I think) because they are deemed cancellation
1384 points by POSIX. For the moment we'll simply pass the call along
1385 to the corresponding thread-unaware (?) libc routine.
1386 ------------------------------------------------------------------ */
1387
sewardje663cb92002-04-12 10:26:32 +00001388#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001389#include <sys/types.h>
1390#include <sys/socket.h>
1391
sewardjd529a442002-05-04 19:49:21 +00001392#ifdef GLIBC_2_1
1393extern
1394int __sigaction
1395 (int signum,
1396 const struct sigaction *act,
1397 struct sigaction *oldact);
1398#else
sewardje663cb92002-04-12 10:26:32 +00001399extern
1400int __libc_sigaction
1401 (int signum,
1402 const struct sigaction *act,
1403 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001404#endif
sewardje663cb92002-04-12 10:26:32 +00001405int sigaction(int signum,
1406 const struct sigaction *act,
1407 struct sigaction *oldact)
1408{
sewardjd140e442002-05-29 01:21:19 +00001409 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001410# ifdef GLIBC_2_1
1411 return __sigaction(signum, act, oldact);
1412# else
sewardj45b4b372002-04-16 22:50:32 +00001413 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001414# endif
sewardje663cb92002-04-12 10:26:32 +00001415}
1416
1417
1418extern
1419int __libc_connect(int sockfd,
1420 const struct sockaddr *serv_addr,
1421 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001422__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001423int connect(int sockfd,
1424 const struct sockaddr *serv_addr,
1425 socklen_t addrlen)
1426{
sewardjd140e442002-05-29 01:21:19 +00001427 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001428 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001429}
1430
1431
1432extern
1433int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001434__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001435int fcntl(int fd, int cmd, long arg)
1436{
sewardjd140e442002-05-29 01:21:19 +00001437 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001438 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001439}
1440
1441
1442extern
1443ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001444__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001445ssize_t write(int fd, const void *buf, size_t count)
1446{
sewardjd140e442002-05-29 01:21:19 +00001447 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001448 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001449}
1450
1451
1452extern
1453ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001454__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001455ssize_t read(int fd, void *buf, size_t count)
1456{
sewardjd140e442002-05-29 01:21:19 +00001457 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001458 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001459}
1460
sewardjbe32e452002-04-24 20:29:58 +00001461
1462extern
sewardj853f55d2002-04-26 00:27:53 +00001463int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001464__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001465int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001466{
sewardjd140e442002-05-29 01:21:19 +00001467 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001468 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001469}
1470
sewardje663cb92002-04-12 10:26:32 +00001471
1472extern
sewardj853f55d2002-04-26 00:27:53 +00001473int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001474__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001475int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001476{
sewardjd140e442002-05-29 01:21:19 +00001477 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001478 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001479}
1480
1481
1482extern
1483int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001484__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001485int close(int fd)
1486{
sewardjd140e442002-05-29 01:21:19 +00001487 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001488 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001489}
1490
1491
1492extern
1493int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001494__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001495int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1496{
sewardjd140e442002-05-29 01:21:19 +00001497 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001498 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001499 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001500 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001501}
1502
1503
1504extern
1505pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001506pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001507{
sewardjd140e442002-05-29 01:21:19 +00001508 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001509 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001510}
1511
1512
1513extern
1514pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001515__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001516pid_t waitpid(pid_t pid, int *status, int options)
1517{
sewardjd140e442002-05-29 01:21:19 +00001518 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001519 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001520}
1521
1522
1523extern
1524int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001525__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001526int nanosleep(const struct timespec *req, struct timespec *rem)
1527{
sewardjd140e442002-05-29 01:21:19 +00001528 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001529 return __libc_nanosleep(req, rem);
1530}
1531
sewardjbe32e452002-04-24 20:29:58 +00001532
sewardje663cb92002-04-12 10:26:32 +00001533extern
1534int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001535__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001536int fsync(int fd)
1537{
sewardjd140e442002-05-29 01:21:19 +00001538 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001539 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001540}
1541
sewardjbe32e452002-04-24 20:29:58 +00001542
sewardj70c75362002-04-13 04:18:32 +00001543extern
1544off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001545__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001546off_t lseek(int fildes, off_t offset, int whence)
1547{
sewardjd140e442002-05-29 01:21:19 +00001548 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001549 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001550}
1551
sewardjbe32e452002-04-24 20:29:58 +00001552
1553extern
1554__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001555__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001556__off64_t lseek64(int fildes, __off64_t offset, int whence)
1557{
sewardjd140e442002-05-29 01:21:19 +00001558 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001559 return __libc_lseek64(fildes, offset, whence);
1560}
1561
1562
sewardj726c4122002-05-16 23:39:10 +00001563extern
1564ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1565 __off64_t __offset);
1566ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1567 __off64_t __offset)
1568{
sewardjd140e442002-05-29 01:21:19 +00001569 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001570 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1571}
1572
1573
sewardja18e2102002-05-18 10:43:22 +00001574extern
1575ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1576 __off64_t __offset);
1577ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1578 __off64_t __offset)
1579{
sewardjd140e442002-05-29 01:21:19 +00001580 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001581 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1582}
1583
sewardj726c4122002-05-16 23:39:10 +00001584
sewardj39b93b12002-05-18 10:56:27 +00001585extern
1586ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1587__attribute__((weak))
1588ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1589{
sewardjd140e442002-05-29 01:21:19 +00001590 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001591 return __libc_pwrite(fd, buf, count, offset);
1592}
1593
1594
1595extern
1596ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1597__attribute__((weak))
1598ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1599{
sewardjd140e442002-05-29 01:21:19 +00001600 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001601 return __libc_pread(fd, buf, count, offset);
1602}
1603
1604
sewardj6af4b5d2002-04-16 04:40:49 +00001605extern
1606void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001607/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001608void longjmp(jmp_buf env, int val)
1609{
sewardjd140e442002-05-29 01:21:19 +00001610 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001611 __libc_longjmp(env, val);
1612}
1613
sewardjbe32e452002-04-24 20:29:58 +00001614
sewardj6af4b5d2002-04-16 04:40:49 +00001615extern
1616int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001617__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001618int send(int s, const void *msg, size_t len, int flags)
1619{
sewardjd140e442002-05-29 01:21:19 +00001620 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001621 return __libc_send(s, msg, len, flags);
1622}
1623
sewardjbe32e452002-04-24 20:29:58 +00001624
sewardj1e8cdc92002-04-18 11:37:52 +00001625extern
1626int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001627__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001628int recv(int s, void *buf, size_t len, int flags)
1629{
sewardjd140e442002-05-29 01:21:19 +00001630 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001631 return __libc_recv(s, buf, len, flags);
1632}
1633
sewardjbe32e452002-04-24 20:29:58 +00001634
sewardj3665ded2002-05-16 16:57:25 +00001635extern
1636int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1637__attribute__((weak))
1638int sendmsg(int s, const struct msghdr *msg, int flags)
1639{
sewardjd140e442002-05-29 01:21:19 +00001640 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001641 return __libc_sendmsg(s, msg, flags);
1642}
1643
1644
sewardj796d6a22002-04-24 02:28:34 +00001645extern
sewardj436e0582002-04-26 14:31:40 +00001646int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1647 struct sockaddr *from, socklen_t *fromlen);
1648__attribute__((weak))
1649int recvfrom(int s, void *buf, size_t len, int flags,
1650 struct sockaddr *from, socklen_t *fromlen)
1651{
sewardjd140e442002-05-29 01:21:19 +00001652 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001653 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1654}
1655
1656
1657extern
sewardj796d6a22002-04-24 02:28:34 +00001658int __libc_sendto(int s, const void *msg, size_t len, int flags,
1659 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001660__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001661int sendto(int s, const void *msg, size_t len, int flags,
1662 const struct sockaddr *to, socklen_t tolen)
1663{
sewardjd140e442002-05-29 01:21:19 +00001664 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001665 return __libc_sendto(s, msg, len, flags, to, tolen);
1666}
1667
sewardjbe32e452002-04-24 20:29:58 +00001668
sewardj369b1702002-04-24 13:28:15 +00001669extern
1670int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001671__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001672int system(const char* str)
1673{
sewardjd140e442002-05-29 01:21:19 +00001674 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001675 return __libc_system(str);
1676}
1677
sewardjbe32e452002-04-24 20:29:58 +00001678
sewardjab0b1c32002-04-24 19:26:47 +00001679extern
1680pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001681__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001682pid_t wait(int *status)
1683{
sewardjd140e442002-05-29 01:21:19 +00001684 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00001685 return __libc_wait(status);
1686}
1687
sewardj45b4b372002-04-16 22:50:32 +00001688
sewardj67f1d582002-05-24 02:11:32 +00001689extern
1690int __libc_msync(const void *start, size_t length, int flags);
1691__attribute__((weak))
1692int msync(const void *start, size_t length, int flags)
1693{
sewardjd140e442002-05-29 01:21:19 +00001694 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00001695 return __libc_msync(start, length, flags);
1696}
1697
sewardj5905fae2002-04-26 13:25:00 +00001698
sewardj3b13f0e2002-04-25 20:17:29 +00001699/* ---------------------------------------------------------------------
1700 Nonblocking implementations of select() and poll(). This stuff will
1701 surely rot your mind.
1702 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001703
sewardj08a4c3f2002-04-13 03:45:44 +00001704/*--------------------------------------------------*/
1705
1706#include "vg_kerneliface.h"
1707
1708static
1709__inline__
1710int is_kerror ( int res )
1711{
1712 if (res >= -4095 && res <= -1)
1713 return 1;
1714 else
1715 return 0;
1716}
1717
1718
1719static
1720int my_do_syscall1 ( int syscallno, int arg1 )
1721{
1722 int __res;
1723 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1724 : "=a" (__res)
1725 : "0" (syscallno),
1726 "d" (arg1) );
1727 return __res;
1728}
1729
1730static
1731int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001732 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001733{
1734 int __res;
1735 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1736 : "=a" (__res)
1737 : "0" (syscallno),
1738 "d" (arg1),
1739 "c" (arg2) );
1740 return __res;
1741}
1742
1743static
sewardjf854f472002-04-21 12:19:41 +00001744int my_do_syscall3 ( int syscallno,
1745 int arg1, int arg2, int arg3 )
1746{
1747 int __res;
1748 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1749 : "=a" (__res)
1750 : "0" (syscallno),
1751 "S" (arg1),
1752 "c" (arg2),
1753 "d" (arg3) );
1754 return __res;
1755}
1756
1757static
sewardj08a4c3f2002-04-13 03:45:44 +00001758int do_syscall_select( int n,
1759 vki_fd_set* readfds,
1760 vki_fd_set* writefds,
1761 vki_fd_set* exceptfds,
1762 struct vki_timeval * timeout )
1763{
1764 int res;
1765 int args[5];
1766 args[0] = n;
1767 args[1] = (int)readfds;
1768 args[2] = (int)writefds;
1769 args[3] = (int)exceptfds;
1770 args[4] = (int)timeout;
1771 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001772 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001773}
1774
1775
1776/* This is a wrapper round select(), which makes it thread-safe,
1777 meaning that only this thread will block, rather than the entire
1778 process. This wrapper in turn depends on nanosleep() not to block
1779 the entire process, but I think (hope? suspect?) that POSIX
1780 pthreads guarantees that to be the case.
1781
1782 Basic idea is: modify the timeout parameter to select so that it
1783 returns immediately. Poll like this until select returns non-zero,
1784 indicating something interesting happened, or until our time is up.
1785 Space out the polls with nanosleeps of say 20 milliseconds, which
1786 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001787
1788 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00001789 * (checked via my_assert) types fd_set and vki_fd_set are identical.
1790 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00001791 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1792 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001793*/
sewardj08a4c3f2002-04-13 03:45:44 +00001794
sewardj5905fae2002-04-26 13:25:00 +00001795/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001796int select ( int n,
1797 fd_set *rfds,
1798 fd_set *wfds,
1799 fd_set *xfds,
1800 struct timeval *timeout )
1801{
sewardj5f07b662002-04-23 16:52:51 +00001802 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001803 int res;
1804 fd_set rfds_copy;
1805 fd_set wfds_copy;
1806 fd_set xfds_copy;
1807 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001808 struct vki_timeval zero_timeout;
1809 struct vki_timespec nanosleep_interval;
1810
sewardjd140e442002-05-29 01:21:19 +00001811 __my_pthread_testcancel();
1812
sewardj5f07b662002-04-23 16:52:51 +00001813 /* gcc's complains about ms_end being used uninitialised -- classic
1814 case it can't understand, where ms_end is both defined and used
1815 only if timeout != NULL. Hence ... */
1816 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001817
1818 /* We assume that the kernel and libc data layouts are identical
1819 for the following types. These asserts provide a crude
1820 check. */
1821 if (sizeof(fd_set) != sizeof(vki_fd_set)
1822 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1823 barf("valgrind's hacky non-blocking select(): data sizes error");
1824
sewardj5f07b662002-04-23 16:52:51 +00001825 /* Detect the current time and simultaneously find out if we are
1826 running on Valgrind. */
1827 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1828 VG_USERREQ__READ_MILLISECOND_TIMER,
1829 0, 0, 0, 0);
1830
1831 /* If a zero timeout specified, this call is harmless. Also go
1832 this route if we're not running on Valgrind, for whatever
1833 reason. */
1834 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1835 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001836 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001837 (vki_fd_set*)wfds,
1838 (vki_fd_set*)xfds,
1839 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001840 if (is_kerror(res)) {
1841 * (__errno_location()) = -res;
1842 return -1;
1843 } else {
1844 return res;
1845 }
1846 }
sewardj08a4c3f2002-04-13 03:45:44 +00001847
sewardj5f07b662002-04-23 16:52:51 +00001848 /* If a timeout was specified, set ms_end to be the end millisecond
1849 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001850 if (timeout) {
1851 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00001852 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001853 ms_end = ms_now;
1854 ms_end += (timeout->tv_usec / 1000);
1855 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001856 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00001857 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001858 }
1859
1860 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1861
1862 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001863 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001864 while (1) {
1865 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +00001866 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1867 VG_USERREQ__READ_MILLISECOND_TIMER,
1868 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001869 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001870 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +00001871 /* timeout; nothing interesting happened. */
1872 if (rfds) FD_ZERO(rfds);
1873 if (wfds) FD_ZERO(wfds);
1874 if (xfds) FD_ZERO(xfds);
1875 return 0;
1876 }
1877 }
1878
1879 /* These could be trashed each time round the loop, so restore
1880 them each time. */
1881 if (rfds) rfds_copy = *rfds;
1882 if (wfds) wfds_copy = *wfds;
1883 if (xfds) xfds_copy = *xfds;
1884
1885 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1886
1887 res = do_syscall_select( n,
1888 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1889 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1890 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1891 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001892 if (is_kerror(res)) {
1893 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001894 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001895 * (__errno_location()) = -res;
1896 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001897 }
1898 if (res > 0) {
1899 /* one or more fds is ready. Copy out resulting sets and
1900 return. */
1901 if (rfds) *rfds = rfds_copy;
1902 if (wfds) *wfds = wfds_copy;
1903 if (xfds) *xfds = xfds_copy;
1904 return res;
1905 }
1906 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1907 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001908 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001909 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001910 /* It's critical here that valgrind's nanosleep implementation
1911 is nonblocking. */
1912 (void)my_do_syscall2(__NR_nanosleep,
1913 (int)(&nanosleep_interval), (int)NULL);
1914 }
1915}
1916
1917
1918
1919
1920#include <sys/poll.h>
1921
sewardj3e909ce2002-06-03 13:27:15 +00001922#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00001923typedef unsigned long int nfds_t;
1924#endif
1925
sewardj705d3cb2002-05-23 13:13:12 +00001926
sewardj5905fae2002-04-26 13:25:00 +00001927/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00001928int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1929{
sewardj5f07b662002-04-23 16:52:51 +00001930 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001931 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001932 struct vki_timespec nanosleep_interval;
1933
sewardjd140e442002-05-29 01:21:19 +00001934 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00001935 ensure_valgrind("poll");
1936
sewardj5f07b662002-04-23 16:52:51 +00001937 /* Detect the current time and simultaneously find out if we are
1938 running on Valgrind. */
1939 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1940 VG_USERREQ__READ_MILLISECOND_TIMER,
1941 0, 0, 0, 0);
1942
sewardjf854f472002-04-21 12:19:41 +00001943 if (/* CHECK SIZES FOR struct pollfd */
1944 sizeof(struct timeval) != sizeof(struct vki_timeval))
1945 barf("valgrind's hacky non-blocking poll(): data sizes error");
1946
sewardj5f07b662002-04-23 16:52:51 +00001947 /* dummy initialisation to keep gcc -Wall happy */
1948 ms_end = 0;
1949
1950 /* If a zero timeout specified, this call is harmless. Also do
1951 this if not running on Valgrind. */
1952 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001953 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1954 if (is_kerror(res)) {
1955 * (__errno_location()) = -res;
1956 return -1;
1957 } else {
1958 return res;
1959 }
1960 }
1961
sewardj5f07b662002-04-23 16:52:51 +00001962 /* If a timeout was specified, set ms_end to be the end wallclock
1963 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001964 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00001965 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001966 }
1967
1968 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1969
1970 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1971 in which case t_end holds the end time. */
sewardj2d94c112002-06-03 01:25:54 +00001972 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00001973
sewardjf854f472002-04-21 12:19:41 +00001974 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001975 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001976 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1977 VG_USERREQ__READ_MILLISECOND_TIMER,
1978 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001979 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001980 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001981 /* timeout; nothing interesting happened. */
1982 for (i = 0; i < __nfds; i++)
1983 __fds[i].revents = 0;
1984 return 0;
1985 }
1986 }
1987
sewardj5f07b662002-04-23 16:52:51 +00001988 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001989 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1990 if (is_kerror(res)) {
1991 /* Some kind of error. Set errno and return. */
1992 * (__errno_location()) = -res;
1993 return -1;
1994 }
1995 if (res > 0) {
1996 /* One or more fds is ready. Return now. */
1997 return res;
1998 }
1999 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2000 /* nanosleep and go round again */
2001 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00002002 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00002003 /* It's critical here that valgrind's nanosleep implementation
2004 is nonblocking. */
2005 (void)my_do_syscall2(__NR_nanosleep,
2006 (int)(&nanosleep_interval), (int)NULL);
2007 }
2008}
sewardj3b13f0e2002-04-25 20:17:29 +00002009
2010
sewardj705d3cb2002-05-23 13:13:12 +00002011/* Helper function used to make accept() non-blocking. Idea is to use
2012 the above nonblocking poll() to make this thread ONLY wait for the
2013 specified fd to become ready, and then return. */
2014static void wait_for_fd_to_be_readable_or_erring ( int fd )
2015{
2016 struct pollfd pfd;
sewardj6e6cbaa2002-05-24 02:12:52 +00002017 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardj705d3cb2002-05-23 13:13:12 +00002018 pfd.fd = fd;
2019 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2020 /* ... but not POLLOUT, you may notice. */
2021 pfd.revents = 0;
2022 (void)poll(&pfd, 1, -1 /* forever */);
2023}
2024
2025
sewardj3b13f0e2002-04-25 20:17:29 +00002026/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002027 Hacky implementation of semaphores.
2028 ------------------------------------------------------------------ */
2029
2030#include <semaphore.h>
2031
2032/* This is a terrible way to do the remapping. Plan is to import an
2033 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002034
2035typedef
2036 struct {
2037 pthread_mutex_t se_mx;
2038 pthread_cond_t se_cv;
2039 int count;
2040 }
2041 vg_sem_t;
2042
2043static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2044
2045static int se_remap_used = 0;
2046static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2047static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2048
2049static vg_sem_t* se_remap ( sem_t* orig )
2050{
2051 int res, i;
2052 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002053 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002054
2055 for (i = 0; i < se_remap_used; i++) {
2056 if (se_remap_orig[i] == orig)
2057 break;
2058 }
2059 if (i == se_remap_used) {
2060 if (se_remap_used == VG_N_SEMAPHORES) {
2061 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002062 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002063 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002064 }
2065 se_remap_used++;
2066 se_remap_orig[i] = orig;
2067 /* printf("allocated semaphore %d\n", i); */
2068 }
2069 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002070 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002071 return &se_remap_new[i];
2072}
2073
2074
2075int sem_init(sem_t *sem, int pshared, unsigned int value)
2076{
2077 int res;
2078 vg_sem_t* vg_sem;
2079 ensure_valgrind("sem_init");
2080 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002081 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002082 errno = ENOSYS;
2083 return -1;
2084 }
2085 vg_sem = se_remap(sem);
2086 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002087 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002088 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002089 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002090 vg_sem->count = value;
2091 return 0;
2092}
2093
2094
2095int sem_wait ( sem_t* sem )
2096{
2097 int res;
2098 vg_sem_t* vg_sem;
2099 ensure_valgrind("sem_wait");
2100 vg_sem = se_remap(sem);
2101 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002102 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002103 while (vg_sem->count == 0) {
2104 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002105 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002106 }
2107 vg_sem->count--;
2108 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002109 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002110 return 0;
2111}
2112
2113int sem_post ( sem_t* sem )
2114{
2115 int res;
2116 vg_sem_t* vg_sem;
2117 ensure_valgrind("sem_post");
2118 vg_sem = se_remap(sem);
2119 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002120 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002121 if (vg_sem->count == 0) {
2122 vg_sem->count++;
2123 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002124 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002125 } else {
2126 vg_sem->count++;
2127 }
2128 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002129 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002130 return 0;
2131}
2132
2133
2134int sem_trywait ( sem_t* sem )
2135{
2136 int ret, res;
2137 vg_sem_t* vg_sem;
2138 ensure_valgrind("sem_trywait");
2139 vg_sem = se_remap(sem);
2140 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002141 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002142 if (vg_sem->count > 0) {
2143 vg_sem->count--;
2144 ret = 0;
2145 } else {
2146 ret = -1;
2147 errno = EAGAIN;
2148 }
2149 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002150 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002151 return ret;
2152}
2153
2154
2155int sem_getvalue(sem_t* sem, int * sval)
2156{
2157 vg_sem_t* vg_sem;
2158 ensure_valgrind("sem_trywait");
2159 vg_sem = se_remap(sem);
2160 *sval = vg_sem->count;
2161 return 0;
2162}
2163
2164
2165int sem_destroy(sem_t * sem)
2166{
2167 kludged("sem_destroy");
2168 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2169 return 0;
2170}
2171
2172
2173/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002174 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002175 ------------------------------------------------------------------ */
2176
sewardj2d8b3f02002-06-01 14:14:19 +00002177typedef
2178 struct {
2179 int initted; /* != 0 --> in use; sanity check only */
2180 int prefer_w; /* != 0 --> prefer writer */
2181 int nwait_r; /* # of waiting readers */
2182 int nwait_w; /* # of waiting writers */
2183 pthread_cond_t cv_r; /* for signalling readers */
2184 pthread_cond_t cv_w; /* for signalling writers */
2185 pthread_mutex_t mx;
2186 int status;
2187 /* allowed range for status: >= -1. -1 means 1 writer currently
2188 active, >= 0 means N readers currently active. */
2189 }
2190 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002191
2192
2193static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2194
2195static int rw_remap_used = 0;
2196static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2197static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2198
sewardj2d8b3f02002-06-01 14:14:19 +00002199
2200static
2201void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2202{
2203 int res = 0;
2204 vg_rwl->initted = 1;
2205 vg_rwl->prefer_w = 1;
2206 vg_rwl->nwait_r = 0;
2207 vg_rwl->nwait_w = 0;
2208 vg_rwl->status = 0;
2209 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2210 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2211 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002212 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002213}
2214
2215
sewardja1ac5cb2002-05-27 13:00:05 +00002216/* Take the address of a LinuxThreads rwlock_t and return the shadow
2217 address of our version. Further, if the LinuxThreads version
2218 appears to have been statically initialised, do the same to the one
2219 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2220 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2221 uninitialised and non-zero meaning initialised.
2222*/
2223static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2224{
2225 int res, i;
2226 vg_rwlock_t* vg_rwl;
2227 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002228 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002229
2230 for (i = 0; i < rw_remap_used; i++) {
2231 if (rw_remap_orig[i] == orig)
2232 break;
2233 }
2234 if (i == rw_remap_used) {
2235 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002236 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002237 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002238 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2239 }
2240 rw_remap_used++;
2241 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002242 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002243 if (0) printf("allocated rwlock %d\n", i);
2244 }
2245 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002246 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002247 vg_rwl = &rw_remap_new[i];
2248
sewardj2d8b3f02002-06-01 14:14:19 +00002249 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002250 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002251 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002252 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002253 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002254 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002255 }
2256
2257 return vg_rwl;
2258}
2259
2260
sewardja1ac5cb2002-05-27 13:00:05 +00002261int pthread_rwlock_init ( pthread_rwlock_t* orig,
2262 const pthread_rwlockattr_t* attr )
2263{
sewardja1ac5cb2002-05-27 13:00:05 +00002264 vg_rwlock_t* rwl;
2265 if (0) printf ("pthread_rwlock_init\n");
2266 /* Force the remapper to initialise the shadow. */
2267 orig->__rw_readers = 0;
2268 /* Install the lock preference; the remapper needs to know it. */
2269 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2270 if (attr)
2271 orig->__rw_kind = attr->__lockkind;
2272 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002273 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002274}
2275
sewardj2d8b3f02002-06-01 14:14:19 +00002276
2277static
2278void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002279{
sewardj2d8b3f02002-06-01 14:14:19 +00002280 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2281 rwl->nwait_r--;
2282 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002283}
2284
sewardj2d8b3f02002-06-01 14:14:19 +00002285
sewardja1ac5cb2002-05-27 13:00:05 +00002286int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2287{
2288 int res;
2289 vg_rwlock_t* rwl;
2290 if (0) printf ("pthread_rwlock_rdlock\n");
2291 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002292 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002293 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002294 if (!rwl->initted) {
2295 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002296 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002297 return EINVAL;
2298 }
2299 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002300 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002301 rwl->nwait_r++;
2302 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2303 while (1) {
2304 if (rwl->status == 0) break;
2305 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002306 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002307 }
2308 pthread_cleanup_pop(0);
2309 rwl->nwait_r--;
2310 }
sewardj2d94c112002-06-03 01:25:54 +00002311 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002312 rwl->status++;
2313 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002314 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002315 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002316}
2317
sewardj2d8b3f02002-06-01 14:14:19 +00002318
sewardja1ac5cb2002-05-27 13:00:05 +00002319int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2320{
2321 int res;
2322 vg_rwlock_t* rwl;
2323 if (0) printf ("pthread_rwlock_tryrdlock\n");
2324 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002325 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002326 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002327 if (!rwl->initted) {
2328 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002329 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002330 return EINVAL;
2331 }
2332 if (rwl->status == -1) {
2333 /* Writer active; we have to give up. */
2334 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002335 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002336 return EBUSY;
2337 }
2338 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002339 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002340 rwl->status++;
2341 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002342 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002343 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002344}
2345
sewardj2d8b3f02002-06-01 14:14:19 +00002346
2347static
2348void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2349{
2350 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2351 rwl->nwait_w--;
2352 pthread_mutex_unlock (&rwl->mx);
2353}
2354
2355
sewardja1ac5cb2002-05-27 13:00:05 +00002356int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2357{
2358 int res;
2359 vg_rwlock_t* rwl;
2360 if (0) printf ("pthread_rwlock_wrlock\n");
2361 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002362 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002363 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002364 if (!rwl->initted) {
2365 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002366 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002367 return EINVAL;
2368 }
2369 if (rwl->status != 0) {
2370 rwl->nwait_w++;
2371 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2372 while (1) {
2373 if (rwl->status == 0) break;
2374 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002375 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002376 }
2377 pthread_cleanup_pop(0);
2378 rwl->nwait_w--;
2379 }
sewardj2d94c112002-06-03 01:25:54 +00002380 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002381 rwl->status = -1;
2382 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002383 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002384 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002385}
2386
sewardj2d8b3f02002-06-01 14:14:19 +00002387
sewardja1ac5cb2002-05-27 13:00:05 +00002388int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2389{
2390 int res;
2391 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002392 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002393 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002394 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002395 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002396 if (!rwl->initted) {
2397 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002398 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002399 return EINVAL;
2400 }
2401 if (rwl->status != 0) {
2402 /* Reader(s) or a writer active; we have to give up. */
2403 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002404 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002405 return EBUSY;
2406 }
2407 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002408 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002409 rwl->status = -1;
2410 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002411 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002412 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002413}
2414
sewardj2d8b3f02002-06-01 14:14:19 +00002415
sewardja1ac5cb2002-05-27 13:00:05 +00002416int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2417{
2418 int res;
2419 vg_rwlock_t* rwl;
2420 if (0) printf ("pthread_rwlock_unlock\n");
2421 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002422 rwl = rw_remap ( orig );
2423 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002424 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002425 if (!rwl->initted) {
2426 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002427 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002428 return EINVAL;
2429 }
2430 if (rwl->status == 0) {
2431 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002432 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002433 return EPERM;
2434 }
sewardj2d94c112002-06-03 01:25:54 +00002435 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002436 if (rwl->status == -1) {
2437 rwl->status = 0;
2438 } else {
sewardj2d94c112002-06-03 01:25:54 +00002439 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002440 rwl->status--;
2441 }
2442
sewardj2d94c112002-06-03 01:25:54 +00002443 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002444
2445 if (rwl->prefer_w) {
2446
2447 /* Favour waiting writers, if any. */
2448 if (rwl->nwait_w > 0) {
2449 /* Writer(s) are waiting. */
2450 if (rwl->status == 0) {
2451 /* We can let a writer in. */
2452 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002453 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002454 } else {
2455 /* There are still readers active. Do nothing; eventually
2456 they will disappear, at which point a writer will be
2457 admitted. */
2458 }
2459 }
2460 else
2461 /* No waiting writers. */
2462 if (rwl->nwait_r > 0) {
2463 /* Let in a waiting reader. */
2464 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002465 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002466 }
2467
2468 } else {
2469
2470 /* Favour waiting readers, if any. */
2471 if (rwl->nwait_r > 0) {
2472 /* Reader(s) are waiting; let one in. */
2473 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002474 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002475 }
2476 else
2477 /* No waiting readers. */
2478 if (rwl->nwait_w > 0 && rwl->status == 0) {
2479 /* We have waiting writers and no active readers; let a
2480 writer in. */
2481 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002482 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002483 }
2484 }
2485
2486 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002487 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002488 return 0;
2489}
2490
2491
2492int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2493{
2494 int res;
2495 vg_rwlock_t* rwl;
2496 if (0) printf ("pthread_rwlock_destroy\n");
2497 rwl = rw_remap ( orig );
2498 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002499 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002500 if (!rwl->initted) {
2501 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002502 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002503 return EINVAL;
2504 }
2505 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2506 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002507 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002508 return EBUSY;
2509 }
2510 rwl->initted = 0;
2511 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002512 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002513 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002514}
2515
2516
2517/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002518 B'stard.
2519 ------------------------------------------------------------------ */
2520
2521# define strong_alias(name, aliasname) \
2522 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2523
sewardj5905fae2002-04-26 13:25:00 +00002524# define weak_alias(name, aliasname) \
2525 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002526
sewardj5905fae2002-04-26 13:25:00 +00002527strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2528strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2529strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2530strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2531 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2532strong_alias(__pthread_mutex_init, pthread_mutex_init)
2533strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2534strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2535strong_alias(__pthread_once, pthread_once)
2536strong_alias(__pthread_atfork, pthread_atfork)
2537strong_alias(__pthread_key_create, pthread_key_create)
2538strong_alias(__pthread_getspecific, pthread_getspecific)
2539strong_alias(__pthread_setspecific, pthread_setspecific)
2540
sewardjd529a442002-05-04 19:49:21 +00002541#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002542strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002543#endif
2544
sewardj5905fae2002-04-26 13:25:00 +00002545strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002546strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002547strong_alias(lseek, __lseek)
2548strong_alias(open, __open)
2549strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002550strong_alias(read, __read)
2551strong_alias(wait, __wait)
2552strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002553strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002554strong_alias(send, __send)
2555
sewardj726c4122002-05-16 23:39:10 +00002556weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002557weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002558weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002559
sewardjf0b06452002-06-04 08:38:04 +00002560weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00002561
2562/*--------------------------------------------------*/
2563
sewardj5905fae2002-04-26 13:25:00 +00002564weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002565weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002566weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002567
sewardja1ac5cb2002-05-27 13:00:05 +00002568weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2569weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2570weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2571weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2572
sewardj060b04f2002-04-26 21:01:13 +00002573
sewardj3b13f0e2002-04-25 20:17:29 +00002574/* I've no idea what these are, but they get called quite a lot.
2575 Anybody know? */
2576
2577#undef _IO_flockfile
2578void _IO_flockfile ( _IO_FILE * file )
2579{
sewardj853f55d2002-04-26 00:27:53 +00002580 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002581}
sewardj5905fae2002-04-26 13:25:00 +00002582weak_alias(_IO_flockfile, flockfile);
2583
sewardj3b13f0e2002-04-25 20:17:29 +00002584
2585#undef _IO_funlockfile
2586void _IO_funlockfile ( _IO_FILE * file )
2587{
sewardj853f55d2002-04-26 00:27:53 +00002588 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002589}
sewardj5905fae2002-04-26 13:25:00 +00002590weak_alias(_IO_funlockfile, funlockfile);
2591
sewardj3b13f0e2002-04-25 20:17:29 +00002592
sewardjd4f2c712002-04-30 10:20:10 +00002593/* This doesn't seem to be needed to simulate libpthread.so's external
2594 interface, but many people complain about its absence. */
2595
2596strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2597weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002598
2599
2600/*--------------------------------------------------------------------*/
2601/*--- end vg_libpthread.c ---*/
2602/*--------------------------------------------------------------------*/