blob: 22799a7a9e7551f38ad1f4dc92f28de442d3c70c [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
sewardja3be12f2002-06-17 12:19:44 +0000389int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
390{
391 if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
392 return EINVAL;
393 attr->__schedpolicy = policy;
394 return 0;
395}
396
397int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
398{
399 *policy = attr->__schedpolicy;
400 return 0;
401}
402
403
sewardj20917d82002-05-28 01:36:45 +0000404/* ---------------------------------------------------
405 Helper functions for running a thread
406 and for clearing up afterwards.
407 ------------------------------------------------ */
408
409/* All exiting threads eventually pass through here, bearing the
410 return value, or PTHREAD_CANCELED, in ret_val. */
411static
412__attribute__((noreturn))
413void thread_exit_wrapper ( void* ret_val )
414{
sewardj870497a2002-05-29 01:06:47 +0000415 int detached, res;
416 CleanupEntry cu;
417 pthread_key_t key;
418
sewardj20917d82002-05-28 01:36:45 +0000419 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000420 while (1) {
421 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
422 VG_USERREQ__CLEANUP_POP,
423 &cu, 0, 0, 0);
424 if (res == -1) break; /* stack empty */
sewardj2d94c112002-06-03 01:25:54 +0000425 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000426 if (0) printf("running exit cleanup handler");
427 cu.fn ( cu.arg );
428 }
429
sewardj870497a2002-05-29 01:06:47 +0000430 /* Run this thread's key finalizers. Really this should be run
431 PTHREAD_DESTRUCTOR_ITERATIONS times. */
432 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
433 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
434 VG_USERREQ__GET_KEY_D_AND_S,
435 key, &cu, 0, 0 );
436 if (res == 0) {
437 /* valid key */
438 if (cu.fn && cu.arg)
439 cu.fn /* destructor for key */
440 ( cu.arg /* specific for key for this thread */ );
441 continue;
442 }
sewardj2d94c112002-06-03 01:25:54 +0000443 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000444 }
sewardj20917d82002-05-28 01:36:45 +0000445
446 /* Decide on my final disposition. */
447 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
448 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000449 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000450 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000451
452 if (detached) {
453 /* Detached; I just quit right now. */
454 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
455 VG_USERREQ__QUIT, 0, 0, 0, 0);
456 } else {
457 /* Not detached; so I wait for a joiner. */
458 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
459 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
460 }
461 /* NOTREACHED */
462 barf("thread_exit_wrapper: still alive?!");
463}
464
465
466/* This function is a wrapper function for running a thread. It runs
467 the root function specified in pthread_create, and then, should the
468 root function return a value, it arranges to run the thread's
469 cleanup handlers and exit correctly. */
470
471/* Struct used to convey info from pthread_create to
472 thread_wrapper. */
473typedef
474 struct {
475 pthread_attr_t* attr;
476 void* (*root_fn) ( void* );
477 void* arg;
478 }
479 NewThreadInfo;
480
481
482/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
483 not return. Note that this runs in the new thread, not the
484 parent. */
485static
486__attribute__((noreturn))
487void thread_wrapper ( NewThreadInfo* info )
488{
489 int res;
490 pthread_attr_t* attr;
491 void* (*root_fn) ( void* );
492 void* arg;
493 void* ret_val;
494
495 attr = info->attr;
496 root_fn = info->root_fn;
497 arg = info->arg;
498
sewardj20917d82002-05-28 01:36:45 +0000499 /* Free up the arg block that pthread_create malloced. */
500 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
501 VG_USERREQ__FREE, info, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000502 my_assert(res == 0);
sewardj20917d82002-05-28 01:36:45 +0000503
sewardj7989d0c2002-05-28 11:00:01 +0000504 /* Minimally observe the attributes supplied. */
505 if (attr) {
sewardj2d94c112002-06-03 01:25:54 +0000506 my_assert(attr->__detachstate == PTHREAD_CREATE_DETACHED
sewardj7989d0c2002-05-28 11:00:01 +0000507 || attr->__detachstate == PTHREAD_CREATE_JOINABLE);
508 if (attr->__detachstate == PTHREAD_CREATE_DETACHED)
509 pthread_detach(pthread_self());
510 }
511
sewardj20917d82002-05-28 01:36:45 +0000512 /* The root function might not return. But if it does we simply
513 move along to thread_exit_wrapper. All other ways out for the
514 thread (cancellation, or calling pthread_exit) lead there
515 too. */
516 ret_val = root_fn(arg);
517 thread_exit_wrapper(ret_val);
518 /* NOTREACHED */
519}
520
521
sewardjf8f819e2002-04-17 23:21:37 +0000522/* ---------------------------------------------------
523 THREADs
524 ------------------------------------------------ */
525
sewardjff42d1d2002-05-22 13:17:31 +0000526__attribute__((weak))
527int pthread_yield ( void )
528{
529 int res;
530 ensure_valgrind("pthread_yield");
531 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
532 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
533 return 0;
534}
535
536
sewardj6072c362002-04-19 14:40:57 +0000537int pthread_equal(pthread_t thread1, pthread_t thread2)
538{
539 return thread1 == thread2 ? 1 : 0;
540}
541
542
sewardj20917d82002-05-28 01:36:45 +0000543/* Bundle up the args into a malloc'd block and create a new thread
544 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000545int
546pthread_create (pthread_t *__restrict __thread,
547 __const pthread_attr_t *__restrict __attr,
548 void *(*__start_routine) (void *),
549 void *__restrict __arg)
550{
sewardj20917d82002-05-28 01:36:45 +0000551 int tid_child;
552 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000553
sewardj20917d82002-05-28 01:36:45 +0000554 ensure_valgrind("pthread_create");
555
556 /* Allocate space for the arg block. thread_wrapper will free
557 it. */
558 VALGRIND_MAGIC_SEQUENCE(info, NULL /* default */,
559 VG_USERREQ__MALLOC,
560 sizeof(NewThreadInfo), 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000561 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000562
563 info->attr = (pthread_attr_t*)__attr;
564 info->root_fn = __start_routine;
565 info->arg = __arg;
566 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
567 VG_USERREQ__APPLY_IN_NEW_THREAD,
568 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000569 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000570
571 if (__thread)
572 *__thread = tid_child;
573 return 0; /* success */
574}
sewardje663cb92002-04-12 10:26:32 +0000575
576
577int
578pthread_join (pthread_t __th, void **__thread_return)
579{
580 int res;
581 ensure_valgrind("pthread_join");
582 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
583 VG_USERREQ__PTHREAD_JOIN,
584 __th, __thread_return, 0, 0);
585 return res;
586}
587
588
sewardj3b5d8862002-04-20 13:53:23 +0000589void pthread_exit(void *retval)
590{
sewardj3b5d8862002-04-20 13:53:23 +0000591 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000592 /* Simple! */
593 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000594}
595
sewardje663cb92002-04-12 10:26:32 +0000596
sewardj3b13f0e2002-04-25 20:17:29 +0000597pthread_t pthread_self(void)
sewardje663cb92002-04-12 10:26:32 +0000598{
599 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000600 ensure_valgrind("pthread_self");
sewardj439d45e2002-05-03 20:43:10 +0000601 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardje663cb92002-04-12 10:26:32 +0000602 VG_USERREQ__PTHREAD_GET_THREADID,
603 0, 0, 0, 0);
sewardj439d45e2002-05-03 20:43:10 +0000604 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000605 barf("pthread_self: invalid ThreadId");
606 return tid;
sewardje663cb92002-04-12 10:26:32 +0000607}
608
609
sewardj853f55d2002-04-26 00:27:53 +0000610int pthread_detach(pthread_t th)
611{
sewardj20917d82002-05-28 01:36:45 +0000612 int res;
613 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000614 /* First we enquire as to the current detach state. */
615 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000616 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000617 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000618 if (res == -1) {
619 /* not found */
620 pthread_error("pthread_detach: "
621 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000622 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000623 }
624 if (res == 1) {
625 /* already detached */
626 pthread_error("pthread_detach: "
627 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000628 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000629 }
sewardj7989d0c2002-05-28 11:00:01 +0000630 if (res == 0) {
631 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
632 VG_USERREQ__SET_OR_GET_DETACH,
633 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000634 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000635 return 0;
636 }
637 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000638}
639
640
sewardjf8f819e2002-04-17 23:21:37 +0000641/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000642 CLEANUP STACKS
643 ------------------------------------------------ */
644
645void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
646 void (*__routine) (void *),
647 void *__arg)
648{
649 int res;
650 CleanupEntry cu;
651 ensure_valgrind("_pthread_cleanup_push");
652 cu.fn = __routine;
653 cu.arg = __arg;
654 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
655 VG_USERREQ__CLEANUP_PUSH,
656 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000657 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000658}
659
660
661void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
662 void (*__routine) (void *),
663 void *__arg)
664{
665 /* As _pthread_cleanup_push, but first save the thread's original
666 cancellation type in __buffer and set it to Deferred. */
667 int orig_ctype;
668 ensure_valgrind("_pthread_cleanup_push_defer");
669 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000670 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
671 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
672 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000673 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
674 VG_USERREQ__SET_CANCELTYPE,
675 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000676 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000677 *((int*)(__buffer)) = orig_ctype;
678 /* Now push the cleanup. */
679 _pthread_cleanup_push(NULL, __routine, __arg);
680}
681
682
683void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
684 int __execute)
685{
686 int res;
687 CleanupEntry cu;
688 ensure_valgrind("_pthread_cleanup_push");
689 cu.fn = cu.arg = NULL; /* paranoia */
690 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
691 VG_USERREQ__CLEANUP_POP,
692 &cu, 0, 0, 0);
693 if (res == 0) {
694 /* pop succeeded */
695 if (__execute) {
696 cu.fn ( cu.arg );
697 }
698 return;
699 }
700 if (res == -1) {
701 /* stack underflow */
702 return;
703 }
704 barf("_pthread_cleanup_pop");
705}
706
707
708void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
709 int __execute)
710{
711 int orig_ctype, fake_ctype;
712 /* As _pthread_cleanup_pop, but after popping/running the handler,
713 restore the thread's original cancellation type from the first
714 word of __buffer. */
715 _pthread_cleanup_pop(NULL, __execute);
716 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000717 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000718 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000719 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
720 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
721 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000722 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
723 VG_USERREQ__SET_CANCELTYPE,
724 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000725 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000726}
727
728
729/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000730 MUTEX ATTRIBUTES
731 ------------------------------------------------ */
732
sewardj5905fae2002-04-26 13:25:00 +0000733int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000734{
sewardjf8f819e2002-04-17 23:21:37 +0000735 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000736 return 0;
sewardje663cb92002-04-12 10:26:32 +0000737}
738
sewardj5905fae2002-04-26 13:25:00 +0000739int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000740{
741 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000742# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000743 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000744 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000745# endif
sewardja1679dd2002-05-10 22:31:40 +0000746# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000747 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000748# endif
sewardjf8f819e2002-04-17 23:21:37 +0000749 case PTHREAD_MUTEX_RECURSIVE_NP:
750 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000751 attr->__mutexkind = type;
752 return 0;
753 default:
sewardj4dced352002-06-04 22:54:20 +0000754 pthread_error("pthread_mutexattr_settype: "
755 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000756 return EINVAL;
757 }
758}
759
sewardj5905fae2002-04-26 13:25:00 +0000760int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000761{
762 return 0;
763}
764
765
766/* ---------------------------------------------------
767 MUTEXes
768 ------------------------------------------------ */
769
sewardj5905fae2002-04-26 13:25:00 +0000770int __pthread_mutex_init(pthread_mutex_t *mutex,
771 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000772{
sewardj604ec3c2002-04-18 22:38:41 +0000773 mutex->__m_count = 0;
774 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
775 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
776 if (mutexattr)
777 mutex->__m_kind = mutexattr->__mutexkind;
778 return 0;
sewardje663cb92002-04-12 10:26:32 +0000779}
780
sewardj439d45e2002-05-03 20:43:10 +0000781
sewardj5905fae2002-04-26 13:25:00 +0000782int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000783{
784 int res;
sewardj436e0582002-04-26 14:31:40 +0000785 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000786 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000787 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
788 VG_USERREQ__PTHREAD_MUTEX_LOCK,
789 mutex, 0, 0, 0);
790 return res;
sewardj439d45e2002-05-03 20:43:10 +0000791 } else {
792 if (moans-- > 0)
793 not_inside("pthread_mutex_lock");
794 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000795 }
796}
797
sewardj439d45e2002-05-03 20:43:10 +0000798
sewardj5905fae2002-04-26 13:25:00 +0000799int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000800{
801 int res;
sewardj436e0582002-04-26 14:31:40 +0000802 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000803 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000804 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
805 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
806 mutex, 0, 0, 0);
807 return res;
sewardj439d45e2002-05-03 20:43:10 +0000808 } else {
809 if (moans-- > 0)
810 not_inside("pthread_mutex_trylock");
811 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000812 }
813}
814
sewardj439d45e2002-05-03 20:43:10 +0000815
sewardj5905fae2002-04-26 13:25:00 +0000816int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000817{
818 int res;
sewardj436e0582002-04-26 14:31:40 +0000819 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000820 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000821 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
822 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
823 mutex, 0, 0, 0);
824 return res;
sewardj439d45e2002-05-03 20:43:10 +0000825 } else {
826 if (moans-- > 0)
827 not_inside("pthread_mutex_unlock");
828 return 0;
sewardje663cb92002-04-12 10:26:32 +0000829 }
830}
831
sewardj439d45e2002-05-03 20:43:10 +0000832
sewardj5905fae2002-04-26 13:25:00 +0000833int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000834{
sewardj604ec3c2002-04-18 22:38:41 +0000835 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
836 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +0000837 if (mutex->__m_count > 0) {
838 pthread_error("pthread_mutex_destroy: "
839 "mutex is still in use");
sewardj604ec3c2002-04-18 22:38:41 +0000840 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +0000841 }
842 mutex->__m_count = 0;
843 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
844 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
845 return 0;
sewardje663cb92002-04-12 10:26:32 +0000846}
847
848
sewardjf8f819e2002-04-17 23:21:37 +0000849/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000850 CONDITION VARIABLES
851 ------------------------------------------------ */
852
853/* LinuxThreads supports no attributes for conditions. Hence ... */
854
855int pthread_condattr_init(pthread_condattr_t *attr)
856{
857 return 0;
858}
859
sewardj0738a592002-04-20 13:59:33 +0000860int pthread_condattr_destroy(pthread_condattr_t *attr)
861{
862 return 0;
863}
sewardj6072c362002-04-19 14:40:57 +0000864
865int pthread_cond_init( pthread_cond_t *cond,
866 const pthread_condattr_t *cond_attr)
867{
868 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
869 return 0;
870}
871
sewardjf854f472002-04-21 12:19:41 +0000872int pthread_cond_destroy(pthread_cond_t *cond)
873{
874 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000875 static int moans = N_MOANS;
876 if (moans-- > 0)
877 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000878 return 0;
879}
sewardj6072c362002-04-19 14:40:57 +0000880
881/* ---------------------------------------------------
882 SCHEDULING
883 ------------------------------------------------ */
884
885/* This is completely bogus. */
886int pthread_getschedparam(pthread_t target_thread,
887 int *policy,
888 struct sched_param *param)
889{
sewardj436e0582002-04-26 14:31:40 +0000890 static int moans = N_MOANS;
891 if (moans-- > 0)
892 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000893 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +0000894# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +0000895 if (param) param->sched_priority = 0; /* who knows */
896# else
sewardj6072c362002-04-19 14:40:57 +0000897 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000898# endif
sewardj6072c362002-04-19 14:40:57 +0000899 return 0;
900}
901
902int pthread_setschedparam(pthread_t target_thread,
903 int policy,
904 const struct sched_param *param)
905{
sewardj436e0582002-04-26 14:31:40 +0000906 static int moans = N_MOANS;
907 if (moans-- > 0)
908 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000909 return 0;
910}
911
sewardj3b5d8862002-04-20 13:53:23 +0000912int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
913{
914 int res;
915 ensure_valgrind("pthread_cond_wait");
916 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
917 VG_USERREQ__PTHREAD_COND_WAIT,
918 cond, mutex, 0, 0);
919 return res;
920}
921
sewardj5f07b662002-04-23 16:52:51 +0000922int pthread_cond_timedwait ( pthread_cond_t *cond,
923 pthread_mutex_t *mutex,
924 const struct timespec *abstime )
925{
926 int res;
927 unsigned int ms_now, ms_end;
928 struct timeval timeval_now;
929 unsigned long long int ull_ms_now_after_1970;
930 unsigned long long int ull_ms_end_after_1970;
931
932 ensure_valgrind("pthread_cond_timedwait");
933 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
934 VG_USERREQ__READ_MILLISECOND_TIMER,
935 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000936 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +0000937 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +0000938 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +0000939
940 ull_ms_now_after_1970
941 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
942 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
943 ull_ms_end_after_1970
944 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
945 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +0000946 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
947 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +0000948 ms_end
949 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
950 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
951 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
952 cond, mutex, ms_end, 0);
953 return res;
954}
955
956
sewardj3b5d8862002-04-20 13:53:23 +0000957int pthread_cond_signal(pthread_cond_t *cond)
958{
959 int res;
960 ensure_valgrind("pthread_cond_signal");
961 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
962 VG_USERREQ__PTHREAD_COND_SIGNAL,
963 cond, 0, 0, 0);
964 return res;
965}
966
967int pthread_cond_broadcast(pthread_cond_t *cond)
968{
969 int res;
970 ensure_valgrind("pthread_cond_broadcast");
971 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
972 VG_USERREQ__PTHREAD_COND_BROADCAST,
973 cond, 0, 0, 0);
974 return res;
975}
976
sewardj6072c362002-04-19 14:40:57 +0000977
978/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000979 CANCELLATION
980 ------------------------------------------------ */
981
sewardj853f55d2002-04-26 00:27:53 +0000982int pthread_setcancelstate(int state, int *oldstate)
983{
sewardj20917d82002-05-28 01:36:45 +0000984 int res;
985 ensure_valgrind("pthread_setcancelstate");
986 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +0000987 && state != PTHREAD_CANCEL_DISABLE) {
988 pthread_error("pthread_setcancelstate: "
989 "invalid state");
sewardj20917d82002-05-28 01:36:45 +0000990 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000991 }
sewardj2d94c112002-06-03 01:25:54 +0000992 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
993 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +0000994 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
995 VG_USERREQ__SET_CANCELSTATE,
996 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000997 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +0000998 if (oldstate)
999 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001000 return 0;
1001}
1002
sewardje663cb92002-04-12 10:26:32 +00001003int pthread_setcanceltype(int type, int *oldtype)
1004{
sewardj20917d82002-05-28 01:36:45 +00001005 int res;
1006 ensure_valgrind("pthread_setcanceltype");
1007 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001008 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1009 pthread_error("pthread_setcanceltype: "
1010 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001011 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001012 }
sewardj2d94c112002-06-03 01:25:54 +00001013 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1014 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001015 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1016 VG_USERREQ__SET_CANCELTYPE,
1017 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001018 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001019 if (oldtype)
1020 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001021 return 0;
1022}
1023
sewardje663cb92002-04-12 10:26:32 +00001024int pthread_cancel(pthread_t thread)
1025{
1026 int res;
1027 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001028 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1029 VG_USERREQ__SET_CANCELPEND,
1030 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001031 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001032 return res;
1033}
1034
sewardjd140e442002-05-29 01:21:19 +00001035static __inline__
1036void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001037{
sewardj20917d82002-05-28 01:36:45 +00001038 int res;
1039 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1040 VG_USERREQ__TESTCANCEL,
1041 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001042 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001043}
1044
sewardjd140e442002-05-29 01:21:19 +00001045void pthread_testcancel ( void )
1046{
1047 __my_pthread_testcancel();
1048}
1049
sewardj20917d82002-05-28 01:36:45 +00001050
sewardjef037c72002-05-30 00:40:03 +00001051/* Not really sure what this is for. I suspect for doing the POSIX
1052 requirements for fork() and exec(). We do this internally anyway
1053 whenever those syscalls are observed, so this could be superfluous,
1054 but hey ...
1055*/
sewardj853f55d2002-04-26 00:27:53 +00001056void __pthread_kill_other_threads_np ( void )
1057{
sewardjef037c72002-05-30 00:40:03 +00001058 int res;
1059 ensure_valgrind("__pthread_kill_other_threads_np");
1060 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1061 VG_USERREQ__NUKE_OTHER_THREADS,
1062 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001063 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001064}
1065
sewardje663cb92002-04-12 10:26:32 +00001066
sewardjf8f819e2002-04-17 23:21:37 +00001067/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001068 SIGNALS
1069 ------------------------------------------------ */
1070
1071#include <signal.h>
1072
1073int pthread_sigmask(int how, const sigset_t *newmask,
1074 sigset_t *oldmask)
1075{
1076 int res;
1077
1078 /* A bit subtle, because the scheduler expects newmask and oldmask
1079 to be vki_sigset_t* rather than sigset_t*, and the two are
1080 different. Fortunately the first 64 bits of a sigset_t are
1081 exactly a vki_sigset_t, so we just pass the pointers through
1082 unmodified. Haaaack!
1083
1084 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001085 constants to VKI_ constants, so that the former do not have to
1086 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001087
1088 ensure_valgrind("pthread_sigmask");
1089
1090 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001091 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1092 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1093 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001094 default: pthread_error("pthread_sigmask: invalid how");
1095 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001096 }
1097
1098 /* Crude check */
1099 if (newmask == NULL)
1100 return EFAULT;
1101
1102 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1103 VG_USERREQ__PTHREAD_SIGMASK,
1104 how, newmask, oldmask, 0);
1105
1106 /* The scheduler tells us of any memory violations. */
1107 return res == 0 ? 0 : EFAULT;
1108}
1109
1110
1111int sigwait ( const sigset_t* set, int* sig )
1112{
1113 int res;
1114 ensure_valgrind("sigwait");
1115 /* As with pthread_sigmask we deliberately confuse sigset_t with
1116 vki_ksigset_t. */
1117 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1118 VG_USERREQ__SIGWAIT,
1119 set, sig, 0, 0);
1120 return res;
1121}
1122
1123
sewardj018f7622002-05-15 21:13:39 +00001124int pthread_kill(pthread_t thread, int signo)
1125{
1126 int res;
1127 ensure_valgrind("pthread_kill");
1128 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1129 VG_USERREQ__PTHREAD_KILL,
1130 thread, signo, 0, 0);
1131 return res;
1132}
1133
1134
sewardj3665ded2002-05-16 16:57:25 +00001135/* Copied verbatim from Linuxthreads */
1136/* Redefine raise() to send signal to calling thread only,
1137 as per POSIX 1003.1c */
1138int raise (int sig)
1139{
1140 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001141 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001142 return 0;
sewardj4dced352002-06-04 22:54:20 +00001143 } else {
sewardj3665ded2002-05-16 16:57:25 +00001144 errno = retcode;
1145 return -1;
1146 }
1147}
1148
1149
sewardjb48e5002002-05-13 00:16:03 +00001150/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001151 THREAD-SPECIFICs
1152 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001153
sewardj5905fae2002-04-26 13:25:00 +00001154int __pthread_key_create(pthread_key_t *key,
1155 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001156{
sewardj5f07b662002-04-23 16:52:51 +00001157 int res;
1158 ensure_valgrind("pthread_key_create");
1159 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1160 VG_USERREQ__PTHREAD_KEY_CREATE,
1161 key, destr_function, 0, 0);
1162 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001163}
1164
1165int pthread_key_delete(pthread_key_t key)
1166{
sewardj436e0582002-04-26 14:31:40 +00001167 static int moans = N_MOANS;
1168 if (moans-- > 0)
1169 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +00001170 return 0;
1171}
1172
sewardj5905fae2002-04-26 13:25:00 +00001173int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001174{
sewardj5f07b662002-04-23 16:52:51 +00001175 int res;
1176 ensure_valgrind("pthread_setspecific");
1177 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1178 VG_USERREQ__PTHREAD_SETSPECIFIC,
1179 key, pointer, 0, 0);
1180 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001181}
1182
sewardj5905fae2002-04-26 13:25:00 +00001183void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001184{
sewardj5f07b662002-04-23 16:52:51 +00001185 int res;
1186 ensure_valgrind("pthread_getspecific");
1187 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1188 VG_USERREQ__PTHREAD_GETSPECIFIC,
1189 key, 0 , 0, 0);
1190 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001191}
1192
sewardjf8f819e2002-04-17 23:21:37 +00001193
1194/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001195 ONCEry
1196 ------------------------------------------------ */
1197
1198static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1199
1200
sewardj5905fae2002-04-26 13:25:00 +00001201int __pthread_once ( pthread_once_t *once_control,
1202 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001203{
1204 int res;
1205 ensure_valgrind("pthread_once");
1206
sewardj68b2dd92002-05-10 21:03:56 +00001207 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001208
sewardj68b2dd92002-05-10 21:03:56 +00001209 if (res != 0) {
sewardj89d3d852002-04-24 19:21:39 +00001210 barf("pthread_once: Looks like your program's "
1211 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001212 }
sewardj89d3d852002-04-24 19:21:39 +00001213
1214 if (*once_control == 0) {
1215 *once_control = 1;
1216 init_routine();
1217 }
1218
sewardj68b2dd92002-05-10 21:03:56 +00001219 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001220
1221 return 0;
1222}
1223
1224
1225/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001226 MISC
1227 ------------------------------------------------ */
1228
sewardj5905fae2002-04-26 13:25:00 +00001229int __pthread_atfork ( void (*prepare)(void),
1230 void (*parent)(void),
1231 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001232{
sewardjccef2e62002-05-29 19:26:32 +00001233 /* We have to do this properly or not at all; faking it isn't an
1234 option. */
1235 vgPlain_unimp("__pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +00001236}
1237
1238
sewardjbb990782002-05-08 02:01:14 +00001239__attribute__((weak))
1240void __pthread_initialize ( void )
1241{
sewardjbea1caa2002-05-10 23:20:58 +00001242 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001243}
1244
1245
sewardj853f55d2002-04-26 00:27:53 +00001246/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001247 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001248 ------------------------------------------------ */
1249
sewardj3b13f0e2002-04-25 20:17:29 +00001250#include <resolv.h>
1251static int thread_specific_errno[VG_N_THREADS];
1252static int thread_specific_h_errno[VG_N_THREADS];
1253static struct __res_state
1254 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001255
sewardj3b13f0e2002-04-25 20:17:29 +00001256int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001257{
1258 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001259 /* ensure_valgrind("__errno_location"); */
1260 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001261 VG_USERREQ__PTHREAD_GET_THREADID,
1262 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001263 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001264 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001265 barf("__errno_location: invalid ThreadId");
1266 return & thread_specific_errno[tid];
1267}
1268
1269int* __h_errno_location ( void )
1270{
1271 int tid;
1272 /* ensure_valgrind("__h_errno_location"); */
1273 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1274 VG_USERREQ__PTHREAD_GET_THREADID,
1275 0, 0, 0, 0);
1276 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001277 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001278 barf("__h_errno_location: invalid ThreadId");
1279 return & thread_specific_h_errno[tid];
1280}
1281
1282struct __res_state* __res_state ( void )
1283{
1284 int tid;
1285 /* ensure_valgrind("__res_state"); */
1286 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1287 VG_USERREQ__PTHREAD_GET_THREADID,
1288 0, 0, 0, 0);
1289 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001290 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001291 barf("__res_state: invalid ThreadId");
1292 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001293}
1294
1295
sewardj5716dbb2002-04-26 03:28:18 +00001296/* ---------------------------------------------------
1297 LIBC-PRIVATE SPECIFIC DATA
1298 ------------------------------------------------ */
1299
1300/* Relies on assumption that initial private data is NULL. This
1301 should be fixed somehow. */
1302
1303/* The allowable keys (indices) (all 2 of them).
1304 From sysdeps/pthread/bits/libc-tsd.h
1305*/
sewardj70adeb22002-04-27 01:35:38 +00001306#define N_LIBC_TSD_EXTRA_KEYS 1
1307
sewardj5716dbb2002-04-26 03:28:18 +00001308enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1309 _LIBC_TSD_KEY_DL_ERROR,
1310 _LIBC_TSD_KEY_N };
1311
1312/* Auto-initialising subsystem. libc_specifics_inited is set
1313 after initialisation. libc_specifics_inited_mx guards it. */
1314static int libc_specifics_inited = 0;
1315static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1316
1317/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001318static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1319 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001320
1321/* Initialise the keys, if they are not already initialise. */
1322static
1323void init_libc_tsd_keys ( void )
1324{
1325 int res, i;
1326 pthread_key_t k;
1327
1328 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1329 if (res != 0) barf("init_libc_tsd_keys: lock");
1330
1331 if (libc_specifics_inited == 0) {
1332 /* printf("INIT libc specifics\n"); */
1333 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001334 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001335 res = pthread_key_create(&k, NULL);
1336 if (res != 0) barf("init_libc_tsd_keys: create");
1337 libc_specifics_keys[i] = k;
1338 }
1339 }
1340
1341 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1342 if (res != 0) barf("init_libc_tsd_keys: unlock");
1343}
1344
1345
1346static int
1347libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1348 const void * pointer )
1349{
sewardj70adeb22002-04-27 01:35:38 +00001350 int res;
1351 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001352 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001353 if (key < _LIBC_TSD_KEY_MALLOC
1354 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001355 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001356 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1357 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001358 "valgrind's libpthread.so: libc_internal_tsd_set: "
1359 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001360 init_libc_tsd_keys();
1361 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1362 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1363 return 0;
1364}
1365
1366static void *
1367libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1368{
sewardj70adeb22002-04-27 01:35:38 +00001369 void* v;
1370 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001371 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001372 if (key < _LIBC_TSD_KEY_MALLOC
1373 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001374 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001375 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1376 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001377 "valgrind's libpthread.so: libc_internal_tsd_get: "
1378 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001379 init_libc_tsd_keys();
1380 v = pthread_getspecific(libc_specifics_keys[key]);
1381 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1382 return v;
1383}
1384
1385
1386
1387
sewardj70adeb22002-04-27 01:35:38 +00001388int (*__libc_internal_tsd_set)
1389 (enum __libc_tsd_key_t key, const void * pointer)
1390 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001391
sewardj70adeb22002-04-27 01:35:38 +00001392void* (*__libc_internal_tsd_get)
1393 (enum __libc_tsd_key_t key)
1394 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001395
1396
sewardje663cb92002-04-12 10:26:32 +00001397/* ---------------------------------------------------------------------
1398 These are here (I think) because they are deemed cancellation
1399 points by POSIX. For the moment we'll simply pass the call along
1400 to the corresponding thread-unaware (?) libc routine.
1401 ------------------------------------------------------------------ */
1402
sewardje663cb92002-04-12 10:26:32 +00001403#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001404#include <sys/types.h>
1405#include <sys/socket.h>
1406
sewardjd529a442002-05-04 19:49:21 +00001407#ifdef GLIBC_2_1
1408extern
1409int __sigaction
1410 (int signum,
1411 const struct sigaction *act,
1412 struct sigaction *oldact);
1413#else
sewardje663cb92002-04-12 10:26:32 +00001414extern
1415int __libc_sigaction
1416 (int signum,
1417 const struct sigaction *act,
1418 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001419#endif
sewardje663cb92002-04-12 10:26:32 +00001420int sigaction(int signum,
1421 const struct sigaction *act,
1422 struct sigaction *oldact)
1423{
sewardjd140e442002-05-29 01:21:19 +00001424 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001425# ifdef GLIBC_2_1
1426 return __sigaction(signum, act, oldact);
1427# else
sewardj45b4b372002-04-16 22:50:32 +00001428 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001429# endif
sewardje663cb92002-04-12 10:26:32 +00001430}
1431
1432
1433extern
1434int __libc_connect(int sockfd,
1435 const struct sockaddr *serv_addr,
1436 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001437__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001438int connect(int sockfd,
1439 const struct sockaddr *serv_addr,
1440 socklen_t addrlen)
1441{
sewardjd140e442002-05-29 01:21:19 +00001442 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001443 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001444}
1445
1446
1447extern
1448int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001449__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001450int fcntl(int fd, int cmd, long arg)
1451{
sewardjd140e442002-05-29 01:21:19 +00001452 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001453 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001454}
1455
1456
1457extern
1458ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001459__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001460ssize_t write(int fd, const void *buf, size_t count)
1461{
sewardjd140e442002-05-29 01:21:19 +00001462 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001463 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001464}
1465
1466
1467extern
1468ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001469__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001470ssize_t read(int fd, void *buf, size_t count)
1471{
sewardjd140e442002-05-29 01:21:19 +00001472 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001473 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001474}
1475
sewardjbe32e452002-04-24 20:29:58 +00001476
1477extern
sewardj853f55d2002-04-26 00:27:53 +00001478int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001479__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001480int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001481{
sewardjd140e442002-05-29 01:21:19 +00001482 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001483 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001484}
1485
sewardje663cb92002-04-12 10:26:32 +00001486
1487extern
sewardj853f55d2002-04-26 00:27:53 +00001488int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001489__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001490int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001491{
sewardjd140e442002-05-29 01:21:19 +00001492 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001493 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001494}
1495
1496
1497extern
1498int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001499__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001500int close(int fd)
1501{
sewardjd140e442002-05-29 01:21:19 +00001502 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001503 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001504}
1505
1506
1507extern
1508int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001509__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001510int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1511{
sewardjd140e442002-05-29 01:21:19 +00001512 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001513 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001514 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001515 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001516}
1517
1518
1519extern
1520pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001521pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001522{
sewardjd140e442002-05-29 01:21:19 +00001523 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001524 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001525}
1526
1527
1528extern
1529pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001530__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001531pid_t waitpid(pid_t pid, int *status, int options)
1532{
sewardjd140e442002-05-29 01:21:19 +00001533 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001534 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001535}
1536
1537
1538extern
1539int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001540__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001541int nanosleep(const struct timespec *req, struct timespec *rem)
1542{
sewardjd140e442002-05-29 01:21:19 +00001543 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001544 return __libc_nanosleep(req, rem);
1545}
1546
sewardjbe32e452002-04-24 20:29:58 +00001547
sewardje663cb92002-04-12 10:26:32 +00001548extern
1549int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001550__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001551int fsync(int fd)
1552{
sewardjd140e442002-05-29 01:21:19 +00001553 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001554 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001555}
1556
sewardjbe32e452002-04-24 20:29:58 +00001557
sewardj70c75362002-04-13 04:18:32 +00001558extern
1559off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001560__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001561off_t lseek(int fildes, off_t offset, int whence)
1562{
sewardjd140e442002-05-29 01:21:19 +00001563 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001564 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001565}
1566
sewardjbe32e452002-04-24 20:29:58 +00001567
1568extern
1569__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001570__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001571__off64_t lseek64(int fildes, __off64_t offset, int whence)
1572{
sewardjd140e442002-05-29 01:21:19 +00001573 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001574 return __libc_lseek64(fildes, offset, whence);
1575}
1576
1577
sewardj726c4122002-05-16 23:39:10 +00001578extern
1579ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1580 __off64_t __offset);
1581ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1582 __off64_t __offset)
1583{
sewardjd140e442002-05-29 01:21:19 +00001584 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001585 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1586}
1587
1588
sewardja18e2102002-05-18 10:43:22 +00001589extern
1590ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1591 __off64_t __offset);
1592ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1593 __off64_t __offset)
1594{
sewardjd140e442002-05-29 01:21:19 +00001595 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001596 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1597}
1598
sewardj726c4122002-05-16 23:39:10 +00001599
sewardj39b93b12002-05-18 10:56:27 +00001600extern
1601ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1602__attribute__((weak))
1603ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1604{
sewardjd140e442002-05-29 01:21:19 +00001605 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001606 return __libc_pwrite(fd, buf, count, offset);
1607}
1608
1609
1610extern
1611ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1612__attribute__((weak))
1613ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1614{
sewardjd140e442002-05-29 01:21:19 +00001615 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001616 return __libc_pread(fd, buf, count, offset);
1617}
1618
1619
sewardj6af4b5d2002-04-16 04:40:49 +00001620extern
1621void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001622/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001623void longjmp(jmp_buf env, int val)
1624{
1625 __libc_longjmp(env, val);
1626}
1627
sewardjbe32e452002-04-24 20:29:58 +00001628
sewardj436c2db2002-06-18 09:07:54 +00001629extern void __libc_siglongjmp (sigjmp_buf env, int val)
1630 __attribute__ ((noreturn));
1631void siglongjmp(sigjmp_buf env, int val)
1632{
1633 kludged("siglongjmp (cleanup handlers are ignored)");
1634 __libc_siglongjmp(env, val);
1635}
1636
1637
sewardj6af4b5d2002-04-16 04:40:49 +00001638extern
1639int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001640__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001641int send(int s, const void *msg, size_t len, int flags)
1642{
sewardjd140e442002-05-29 01:21:19 +00001643 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001644 return __libc_send(s, msg, len, flags);
1645}
1646
sewardjbe32e452002-04-24 20:29:58 +00001647
sewardj1e8cdc92002-04-18 11:37:52 +00001648extern
1649int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001650__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001651int recv(int s, void *buf, size_t len, int flags)
1652{
sewardjd140e442002-05-29 01:21:19 +00001653 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001654 return __libc_recv(s, buf, len, flags);
1655}
1656
sewardjbe32e452002-04-24 20:29:58 +00001657
sewardj3665ded2002-05-16 16:57:25 +00001658extern
1659int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1660__attribute__((weak))
1661int sendmsg(int s, const struct msghdr *msg, int flags)
1662{
sewardjd140e442002-05-29 01:21:19 +00001663 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001664 return __libc_sendmsg(s, msg, flags);
1665}
1666
1667
sewardj796d6a22002-04-24 02:28:34 +00001668extern
sewardj59da27a2002-06-06 08:33:54 +00001669int __libc_recvmsg(int s, struct msghdr *msg, int flags);
1670__attribute__((weak))
1671int recvmsg(int s, struct msghdr *msg, int flags)
1672{
1673 __my_pthread_testcancel();
1674 return __libc_recvmsg(s, msg, flags);
1675}
1676
1677
1678extern
sewardj436e0582002-04-26 14:31:40 +00001679int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1680 struct sockaddr *from, socklen_t *fromlen);
1681__attribute__((weak))
1682int recvfrom(int s, void *buf, size_t len, int flags,
1683 struct sockaddr *from, socklen_t *fromlen)
1684{
sewardjd140e442002-05-29 01:21:19 +00001685 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00001686 wait_for_fd_to_be_readable_or_erring(s);
1687 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001688 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1689}
1690
1691
1692extern
sewardj796d6a22002-04-24 02:28:34 +00001693int __libc_sendto(int s, const void *msg, size_t len, int flags,
1694 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001695__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001696int sendto(int s, const void *msg, size_t len, int flags,
1697 const struct sockaddr *to, socklen_t tolen)
1698{
sewardjd140e442002-05-29 01:21:19 +00001699 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001700 return __libc_sendto(s, msg, len, flags, to, tolen);
1701}
1702
sewardjbe32e452002-04-24 20:29:58 +00001703
sewardj369b1702002-04-24 13:28:15 +00001704extern
1705int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001706__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001707int system(const char* str)
1708{
sewardjd140e442002-05-29 01:21:19 +00001709 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001710 return __libc_system(str);
1711}
1712
sewardjbe32e452002-04-24 20:29:58 +00001713
sewardjab0b1c32002-04-24 19:26:47 +00001714extern
1715pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001716__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001717pid_t wait(int *status)
1718{
sewardjd140e442002-05-29 01:21:19 +00001719 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00001720 return __libc_wait(status);
1721}
1722
sewardj45b4b372002-04-16 22:50:32 +00001723
sewardj67f1d582002-05-24 02:11:32 +00001724extern
1725int __libc_msync(const void *start, size_t length, int flags);
1726__attribute__((weak))
1727int msync(const void *start, size_t length, int flags)
1728{
sewardjd140e442002-05-29 01:21:19 +00001729 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00001730 return __libc_msync(start, length, flags);
1731}
1732
sewardj5905fae2002-04-26 13:25:00 +00001733
sewardj3b13f0e2002-04-25 20:17:29 +00001734/* ---------------------------------------------------------------------
1735 Nonblocking implementations of select() and poll(). This stuff will
1736 surely rot your mind.
1737 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001738
sewardj08a4c3f2002-04-13 03:45:44 +00001739/*--------------------------------------------------*/
1740
1741#include "vg_kerneliface.h"
1742
1743static
1744__inline__
1745int is_kerror ( int res )
1746{
1747 if (res >= -4095 && res <= -1)
1748 return 1;
1749 else
1750 return 0;
1751}
1752
1753
1754static
1755int my_do_syscall1 ( int syscallno, int arg1 )
1756{
1757 int __res;
1758 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1759 : "=a" (__res)
1760 : "0" (syscallno),
1761 "d" (arg1) );
1762 return __res;
1763}
1764
1765static
1766int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001767 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001768{
1769 int __res;
1770 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1771 : "=a" (__res)
1772 : "0" (syscallno),
1773 "d" (arg1),
1774 "c" (arg2) );
1775 return __res;
1776}
1777
1778static
sewardjf854f472002-04-21 12:19:41 +00001779int my_do_syscall3 ( int syscallno,
1780 int arg1, int arg2, int arg3 )
1781{
1782 int __res;
1783 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1784 : "=a" (__res)
1785 : "0" (syscallno),
1786 "S" (arg1),
1787 "c" (arg2),
1788 "d" (arg3) );
1789 return __res;
1790}
1791
1792static
sewardj08a4c3f2002-04-13 03:45:44 +00001793int do_syscall_select( int n,
1794 vki_fd_set* readfds,
1795 vki_fd_set* writefds,
1796 vki_fd_set* exceptfds,
1797 struct vki_timeval * timeout )
1798{
1799 int res;
1800 int args[5];
1801 args[0] = n;
1802 args[1] = (int)readfds;
1803 args[2] = (int)writefds;
1804 args[3] = (int)exceptfds;
1805 args[4] = (int)timeout;
1806 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001807 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001808}
1809
1810
1811/* This is a wrapper round select(), which makes it thread-safe,
1812 meaning that only this thread will block, rather than the entire
1813 process. This wrapper in turn depends on nanosleep() not to block
1814 the entire process, but I think (hope? suspect?) that POSIX
1815 pthreads guarantees that to be the case.
1816
1817 Basic idea is: modify the timeout parameter to select so that it
1818 returns immediately. Poll like this until select returns non-zero,
1819 indicating something interesting happened, or until our time is up.
1820 Space out the polls with nanosleeps of say 20 milliseconds, which
1821 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001822
1823 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00001824 * (checked via my_assert) types fd_set and vki_fd_set are identical.
1825 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00001826 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1827 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001828*/
sewardj08a4c3f2002-04-13 03:45:44 +00001829
sewardj5905fae2002-04-26 13:25:00 +00001830/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001831int select ( int n,
1832 fd_set *rfds,
1833 fd_set *wfds,
1834 fd_set *xfds,
1835 struct timeval *timeout )
1836{
sewardj5f07b662002-04-23 16:52:51 +00001837 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001838 int res;
1839 fd_set rfds_copy;
1840 fd_set wfds_copy;
1841 fd_set xfds_copy;
1842 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001843 struct vki_timeval zero_timeout;
1844 struct vki_timespec nanosleep_interval;
1845
sewardjd140e442002-05-29 01:21:19 +00001846 __my_pthread_testcancel();
1847
sewardj5f07b662002-04-23 16:52:51 +00001848 /* gcc's complains about ms_end being used uninitialised -- classic
1849 case it can't understand, where ms_end is both defined and used
1850 only if timeout != NULL. Hence ... */
1851 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001852
1853 /* We assume that the kernel and libc data layouts are identical
1854 for the following types. These asserts provide a crude
1855 check. */
1856 if (sizeof(fd_set) != sizeof(vki_fd_set)
1857 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1858 barf("valgrind's hacky non-blocking select(): data sizes error");
1859
sewardj5f07b662002-04-23 16:52:51 +00001860 /* Detect the current time and simultaneously find out if we are
1861 running on Valgrind. */
1862 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1863 VG_USERREQ__READ_MILLISECOND_TIMER,
1864 0, 0, 0, 0);
1865
1866 /* If a zero timeout specified, this call is harmless. Also go
1867 this route if we're not running on Valgrind, for whatever
1868 reason. */
1869 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1870 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001871 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001872 (vki_fd_set*)wfds,
1873 (vki_fd_set*)xfds,
1874 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001875 if (is_kerror(res)) {
1876 * (__errno_location()) = -res;
1877 return -1;
1878 } else {
1879 return res;
1880 }
1881 }
sewardj08a4c3f2002-04-13 03:45:44 +00001882
sewardj5f07b662002-04-23 16:52:51 +00001883 /* If a timeout was specified, set ms_end to be the end millisecond
1884 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001885 if (timeout) {
1886 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00001887 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001888 ms_end = ms_now;
1889 ms_end += (timeout->tv_usec / 1000);
1890 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001891 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00001892 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001893 }
1894
1895 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1896
1897 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001898 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001899 while (1) {
1900 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +00001901 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1902 VG_USERREQ__READ_MILLISECOND_TIMER,
1903 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001904 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001905 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +00001906 /* timeout; nothing interesting happened. */
1907 if (rfds) FD_ZERO(rfds);
1908 if (wfds) FD_ZERO(wfds);
1909 if (xfds) FD_ZERO(xfds);
1910 return 0;
1911 }
1912 }
1913
1914 /* These could be trashed each time round the loop, so restore
1915 them each time. */
1916 if (rfds) rfds_copy = *rfds;
1917 if (wfds) wfds_copy = *wfds;
1918 if (xfds) xfds_copy = *xfds;
1919
1920 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1921
1922 res = do_syscall_select( n,
1923 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1924 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1925 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1926 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001927 if (is_kerror(res)) {
1928 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001929 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001930 * (__errno_location()) = -res;
1931 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001932 }
1933 if (res > 0) {
1934 /* one or more fds is ready. Copy out resulting sets and
1935 return. */
1936 if (rfds) *rfds = rfds_copy;
1937 if (wfds) *wfds = wfds_copy;
1938 if (xfds) *xfds = xfds_copy;
1939 return res;
1940 }
1941 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1942 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001943 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001944 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001945 /* It's critical here that valgrind's nanosleep implementation
1946 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00001947 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00001948 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00001949 if (res == -VKI_EINTR) {
1950 /* The nanosleep was interrupted by a signal. So we do the
1951 same. */
1952 * (__errno_location()) = EINTR;
1953 return -1;
1954 }
sewardjf854f472002-04-21 12:19:41 +00001955 }
1956}
1957
1958
1959
1960
1961#include <sys/poll.h>
1962
sewardj3e909ce2002-06-03 13:27:15 +00001963#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00001964typedef unsigned long int nfds_t;
1965#endif
1966
sewardj705d3cb2002-05-23 13:13:12 +00001967
sewardj5905fae2002-04-26 13:25:00 +00001968/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00001969int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1970{
sewardj5f07b662002-04-23 16:52:51 +00001971 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001972 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001973 struct vki_timespec nanosleep_interval;
1974
sewardjd140e442002-05-29 01:21:19 +00001975 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00001976 ensure_valgrind("poll");
1977
sewardj5f07b662002-04-23 16:52:51 +00001978 /* Detect the current time and simultaneously find out if we are
1979 running on Valgrind. */
1980 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1981 VG_USERREQ__READ_MILLISECOND_TIMER,
1982 0, 0, 0, 0);
1983
sewardjf854f472002-04-21 12:19:41 +00001984 if (/* CHECK SIZES FOR struct pollfd */
1985 sizeof(struct timeval) != sizeof(struct vki_timeval))
1986 barf("valgrind's hacky non-blocking poll(): data sizes error");
1987
sewardj5f07b662002-04-23 16:52:51 +00001988 /* dummy initialisation to keep gcc -Wall happy */
1989 ms_end = 0;
1990
1991 /* If a zero timeout specified, this call is harmless. Also do
1992 this if not running on Valgrind. */
1993 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001994 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1995 if (is_kerror(res)) {
1996 * (__errno_location()) = -res;
1997 return -1;
1998 } else {
1999 return res;
2000 }
2001 }
2002
sewardj5f07b662002-04-23 16:52:51 +00002003 /* If a timeout was specified, set ms_end to be the end wallclock
2004 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002005 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002006 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002007 }
2008
2009 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2010
2011 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2012 in which case t_end holds the end time. */
sewardj2d94c112002-06-03 01:25:54 +00002013 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002014
sewardjf854f472002-04-21 12:19:41 +00002015 while (1) {
sewardjf854f472002-04-21 12:19:41 +00002016 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002017 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2018 VG_USERREQ__READ_MILLISECOND_TIMER,
2019 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002020 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002021 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002022 /* timeout; nothing interesting happened. */
2023 for (i = 0; i < __nfds; i++)
2024 __fds[i].revents = 0;
2025 return 0;
2026 }
2027 }
2028
sewardj5f07b662002-04-23 16:52:51 +00002029 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00002030 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2031 if (is_kerror(res)) {
2032 /* Some kind of error. Set errno and return. */
2033 * (__errno_location()) = -res;
2034 return -1;
2035 }
2036 if (res > 0) {
2037 /* One or more fds is ready. Return now. */
2038 return res;
2039 }
2040 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2041 /* nanosleep and go round again */
2042 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00002043 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00002044 /* It's critical here that valgrind's nanosleep implementation
2045 is nonblocking. */
2046 (void)my_do_syscall2(__NR_nanosleep,
2047 (int)(&nanosleep_interval), (int)NULL);
2048 }
2049}
sewardj3b13f0e2002-04-25 20:17:29 +00002050
2051
sewardj705d3cb2002-05-23 13:13:12 +00002052/* Helper function used to make accept() non-blocking. Idea is to use
2053 the above nonblocking poll() to make this thread ONLY wait for the
2054 specified fd to become ready, and then return. */
2055static void wait_for_fd_to_be_readable_or_erring ( int fd )
2056{
2057 struct pollfd pfd;
sewardj6e6cbaa2002-05-24 02:12:52 +00002058 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardj705d3cb2002-05-23 13:13:12 +00002059 pfd.fd = fd;
2060 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2061 /* ... but not POLLOUT, you may notice. */
2062 pfd.revents = 0;
2063 (void)poll(&pfd, 1, -1 /* forever */);
2064}
2065
2066
sewardj3b13f0e2002-04-25 20:17:29 +00002067/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002068 Hacky implementation of semaphores.
2069 ------------------------------------------------------------------ */
2070
2071#include <semaphore.h>
2072
2073/* This is a terrible way to do the remapping. Plan is to import an
2074 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002075
2076typedef
2077 struct {
2078 pthread_mutex_t se_mx;
2079 pthread_cond_t se_cv;
2080 int count;
2081 }
2082 vg_sem_t;
2083
2084static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2085
2086static int se_remap_used = 0;
2087static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2088static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2089
2090static vg_sem_t* se_remap ( sem_t* orig )
2091{
2092 int res, i;
2093 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002094 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002095
2096 for (i = 0; i < se_remap_used; i++) {
2097 if (se_remap_orig[i] == orig)
2098 break;
2099 }
2100 if (i == se_remap_used) {
2101 if (se_remap_used == VG_N_SEMAPHORES) {
2102 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002103 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002104 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002105 }
2106 se_remap_used++;
2107 se_remap_orig[i] = orig;
2108 /* printf("allocated semaphore %d\n", i); */
2109 }
2110 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002111 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002112 return &se_remap_new[i];
2113}
2114
2115
2116int sem_init(sem_t *sem, int pshared, unsigned int value)
2117{
2118 int res;
2119 vg_sem_t* vg_sem;
2120 ensure_valgrind("sem_init");
2121 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002122 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002123 errno = ENOSYS;
2124 return -1;
2125 }
2126 vg_sem = se_remap(sem);
2127 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002128 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002129 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002130 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002131 vg_sem->count = value;
2132 return 0;
2133}
2134
2135
2136int sem_wait ( sem_t* sem )
2137{
2138 int res;
2139 vg_sem_t* vg_sem;
2140 ensure_valgrind("sem_wait");
2141 vg_sem = se_remap(sem);
2142 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002143 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002144 while (vg_sem->count == 0) {
2145 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002146 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002147 }
2148 vg_sem->count--;
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 0;
2152}
2153
2154int sem_post ( sem_t* sem )
2155{
2156 int res;
2157 vg_sem_t* vg_sem;
2158 ensure_valgrind("sem_post");
2159 vg_sem = se_remap(sem);
2160 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002161 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002162 if (vg_sem->count == 0) {
2163 vg_sem->count++;
2164 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002165 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002166 } else {
2167 vg_sem->count++;
2168 }
2169 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002170 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002171 return 0;
2172}
2173
2174
2175int sem_trywait ( sem_t* sem )
2176{
2177 int ret, res;
2178 vg_sem_t* vg_sem;
2179 ensure_valgrind("sem_trywait");
2180 vg_sem = se_remap(sem);
2181 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002182 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002183 if (vg_sem->count > 0) {
2184 vg_sem->count--;
2185 ret = 0;
2186 } else {
2187 ret = -1;
2188 errno = EAGAIN;
2189 }
2190 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002191 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002192 return ret;
2193}
2194
2195
2196int sem_getvalue(sem_t* sem, int * sval)
2197{
2198 vg_sem_t* vg_sem;
2199 ensure_valgrind("sem_trywait");
2200 vg_sem = se_remap(sem);
2201 *sval = vg_sem->count;
2202 return 0;
2203}
2204
2205
2206int sem_destroy(sem_t * sem)
2207{
2208 kludged("sem_destroy");
2209 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2210 return 0;
2211}
2212
2213
2214/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002215 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002216 ------------------------------------------------------------------ */
2217
sewardj2d8b3f02002-06-01 14:14:19 +00002218typedef
2219 struct {
2220 int initted; /* != 0 --> in use; sanity check only */
2221 int prefer_w; /* != 0 --> prefer writer */
2222 int nwait_r; /* # of waiting readers */
2223 int nwait_w; /* # of waiting writers */
2224 pthread_cond_t cv_r; /* for signalling readers */
2225 pthread_cond_t cv_w; /* for signalling writers */
2226 pthread_mutex_t mx;
2227 int status;
2228 /* allowed range for status: >= -1. -1 means 1 writer currently
2229 active, >= 0 means N readers currently active. */
2230 }
2231 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002232
2233
2234static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2235
2236static int rw_remap_used = 0;
2237static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2238static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2239
sewardj2d8b3f02002-06-01 14:14:19 +00002240
2241static
2242void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2243{
2244 int res = 0;
2245 vg_rwl->initted = 1;
2246 vg_rwl->prefer_w = 1;
2247 vg_rwl->nwait_r = 0;
2248 vg_rwl->nwait_w = 0;
2249 vg_rwl->status = 0;
2250 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2251 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2252 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002253 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002254}
2255
2256
sewardja1ac5cb2002-05-27 13:00:05 +00002257/* Take the address of a LinuxThreads rwlock_t and return the shadow
2258 address of our version. Further, if the LinuxThreads version
2259 appears to have been statically initialised, do the same to the one
2260 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2261 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2262 uninitialised and non-zero meaning initialised.
2263*/
2264static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2265{
2266 int res, i;
2267 vg_rwlock_t* vg_rwl;
2268 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002269 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002270
2271 for (i = 0; i < rw_remap_used; i++) {
2272 if (rw_remap_orig[i] == orig)
2273 break;
2274 }
2275 if (i == rw_remap_used) {
2276 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002277 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002278 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002279 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2280 }
2281 rw_remap_used++;
2282 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002283 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002284 if (0) printf("allocated rwlock %d\n", i);
2285 }
2286 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002287 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002288 vg_rwl = &rw_remap_new[i];
2289
sewardj2d8b3f02002-06-01 14:14:19 +00002290 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002291 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002292 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002293 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002294 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002295 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002296 }
2297
2298 return vg_rwl;
2299}
2300
2301
sewardja1ac5cb2002-05-27 13:00:05 +00002302int pthread_rwlock_init ( pthread_rwlock_t* orig,
2303 const pthread_rwlockattr_t* attr )
2304{
sewardja1ac5cb2002-05-27 13:00:05 +00002305 vg_rwlock_t* rwl;
2306 if (0) printf ("pthread_rwlock_init\n");
2307 /* Force the remapper to initialise the shadow. */
2308 orig->__rw_readers = 0;
2309 /* Install the lock preference; the remapper needs to know it. */
2310 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2311 if (attr)
2312 orig->__rw_kind = attr->__lockkind;
2313 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002314 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002315}
2316
sewardj2d8b3f02002-06-01 14:14:19 +00002317
2318static
2319void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002320{
sewardj2d8b3f02002-06-01 14:14:19 +00002321 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2322 rwl->nwait_r--;
2323 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002324}
2325
sewardj2d8b3f02002-06-01 14:14:19 +00002326
sewardja1ac5cb2002-05-27 13:00:05 +00002327int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2328{
2329 int res;
2330 vg_rwlock_t* rwl;
2331 if (0) printf ("pthread_rwlock_rdlock\n");
2332 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002333 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002334 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002335 if (!rwl->initted) {
2336 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002337 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002338 return EINVAL;
2339 }
2340 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002341 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002342 rwl->nwait_r++;
2343 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2344 while (1) {
2345 if (rwl->status == 0) break;
2346 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002347 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002348 }
2349 pthread_cleanup_pop(0);
2350 rwl->nwait_r--;
2351 }
sewardj2d94c112002-06-03 01:25:54 +00002352 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002353 rwl->status++;
2354 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002355 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002356 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002357}
2358
sewardj2d8b3f02002-06-01 14:14:19 +00002359
sewardja1ac5cb2002-05-27 13:00:05 +00002360int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2361{
2362 int res;
2363 vg_rwlock_t* rwl;
2364 if (0) printf ("pthread_rwlock_tryrdlock\n");
2365 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002366 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002367 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002368 if (!rwl->initted) {
2369 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002370 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002371 return EINVAL;
2372 }
2373 if (rwl->status == -1) {
2374 /* Writer active; we have to give up. */
2375 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002376 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002377 return EBUSY;
2378 }
2379 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002380 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002381 rwl->status++;
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
2388static
2389void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2390{
2391 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2392 rwl->nwait_w--;
2393 pthread_mutex_unlock (&rwl->mx);
2394}
2395
2396
sewardja1ac5cb2002-05-27 13:00:05 +00002397int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2398{
2399 int res;
2400 vg_rwlock_t* rwl;
2401 if (0) printf ("pthread_rwlock_wrlock\n");
2402 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002403 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002404 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002405 if (!rwl->initted) {
2406 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002407 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002408 return EINVAL;
2409 }
2410 if (rwl->status != 0) {
2411 rwl->nwait_w++;
2412 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2413 while (1) {
2414 if (rwl->status == 0) break;
2415 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002416 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002417 }
2418 pthread_cleanup_pop(0);
2419 rwl->nwait_w--;
2420 }
sewardj2d94c112002-06-03 01:25:54 +00002421 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002422 rwl->status = -1;
2423 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002424 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002425 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002426}
2427
sewardj2d8b3f02002-06-01 14:14:19 +00002428
sewardja1ac5cb2002-05-27 13:00:05 +00002429int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2430{
2431 int res;
2432 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002433 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002434 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002435 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002436 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002437 if (!rwl->initted) {
2438 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002439 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002440 return EINVAL;
2441 }
2442 if (rwl->status != 0) {
2443 /* Reader(s) or a writer active; we have to give up. */
2444 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002445 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002446 return EBUSY;
2447 }
2448 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002449 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002450 rwl->status = -1;
2451 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002452 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002453 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002454}
2455
sewardj2d8b3f02002-06-01 14:14:19 +00002456
sewardja1ac5cb2002-05-27 13:00:05 +00002457int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2458{
2459 int res;
2460 vg_rwlock_t* rwl;
2461 if (0) printf ("pthread_rwlock_unlock\n");
2462 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002463 rwl = rw_remap ( orig );
2464 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002465 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002466 if (!rwl->initted) {
2467 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002468 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002469 return EINVAL;
2470 }
2471 if (rwl->status == 0) {
2472 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002473 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002474 return EPERM;
2475 }
sewardj2d94c112002-06-03 01:25:54 +00002476 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002477 if (rwl->status == -1) {
2478 rwl->status = 0;
2479 } else {
sewardj2d94c112002-06-03 01:25:54 +00002480 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002481 rwl->status--;
2482 }
2483
sewardj2d94c112002-06-03 01:25:54 +00002484 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002485
2486 if (rwl->prefer_w) {
2487
2488 /* Favour waiting writers, if any. */
2489 if (rwl->nwait_w > 0) {
2490 /* Writer(s) are waiting. */
2491 if (rwl->status == 0) {
2492 /* We can let a writer in. */
2493 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002494 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002495 } else {
2496 /* There are still readers active. Do nothing; eventually
2497 they will disappear, at which point a writer will be
2498 admitted. */
2499 }
2500 }
2501 else
2502 /* No waiting writers. */
2503 if (rwl->nwait_r > 0) {
2504 /* Let in a waiting reader. */
2505 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002506 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002507 }
2508
2509 } else {
2510
2511 /* Favour waiting readers, if any. */
2512 if (rwl->nwait_r > 0) {
2513 /* Reader(s) are waiting; let one in. */
2514 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002515 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002516 }
2517 else
2518 /* No waiting readers. */
2519 if (rwl->nwait_w > 0 && rwl->status == 0) {
2520 /* We have waiting writers and no active readers; let a
2521 writer in. */
2522 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002523 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002524 }
2525 }
2526
2527 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002528 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002529 return 0;
2530}
2531
2532
2533int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2534{
2535 int res;
2536 vg_rwlock_t* rwl;
2537 if (0) printf ("pthread_rwlock_destroy\n");
2538 rwl = rw_remap ( orig );
2539 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002540 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002541 if (!rwl->initted) {
2542 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002543 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002544 return EINVAL;
2545 }
2546 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2547 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002548 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002549 return EBUSY;
2550 }
2551 rwl->initted = 0;
2552 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002553 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002554 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002555}
2556
2557
2558/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002559 B'stard.
2560 ------------------------------------------------------------------ */
2561
2562# define strong_alias(name, aliasname) \
2563 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2564
sewardj5905fae2002-04-26 13:25:00 +00002565# define weak_alias(name, aliasname) \
2566 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002567
sewardj5905fae2002-04-26 13:25:00 +00002568strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2569strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2570strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2571strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2572 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2573strong_alias(__pthread_mutex_init, pthread_mutex_init)
2574strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2575strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2576strong_alias(__pthread_once, pthread_once)
2577strong_alias(__pthread_atfork, pthread_atfork)
2578strong_alias(__pthread_key_create, pthread_key_create)
2579strong_alias(__pthread_getspecific, pthread_getspecific)
2580strong_alias(__pthread_setspecific, pthread_setspecific)
2581
sewardjd529a442002-05-04 19:49:21 +00002582#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002583strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002584#endif
2585
sewardj5905fae2002-04-26 13:25:00 +00002586strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002587strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002588strong_alias(lseek, __lseek)
2589strong_alias(open, __open)
2590strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002591strong_alias(read, __read)
2592strong_alias(wait, __wait)
2593strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002594strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002595strong_alias(send, __send)
2596
sewardj726c4122002-05-16 23:39:10 +00002597weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002598weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002599weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002600
sewardjf0b06452002-06-04 08:38:04 +00002601weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00002602
2603/*--------------------------------------------------*/
2604
sewardj5905fae2002-04-26 13:25:00 +00002605weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002606weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002607weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002608
sewardja1ac5cb2002-05-27 13:00:05 +00002609weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2610weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2611weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2612weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2613
sewardj060b04f2002-04-26 21:01:13 +00002614
sewardj3b13f0e2002-04-25 20:17:29 +00002615/* I've no idea what these are, but they get called quite a lot.
2616 Anybody know? */
2617
2618#undef _IO_flockfile
2619void _IO_flockfile ( _IO_FILE * file )
2620{
sewardj853f55d2002-04-26 00:27:53 +00002621 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002622}
sewardj5905fae2002-04-26 13:25:00 +00002623weak_alias(_IO_flockfile, flockfile);
2624
sewardj3b13f0e2002-04-25 20:17:29 +00002625
2626#undef _IO_funlockfile
2627void _IO_funlockfile ( _IO_FILE * file )
2628{
sewardj853f55d2002-04-26 00:27:53 +00002629 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002630}
sewardj5905fae2002-04-26 13:25:00 +00002631weak_alias(_IO_funlockfile, funlockfile);
2632
sewardj3b13f0e2002-04-25 20:17:29 +00002633
sewardjd4f2c712002-04-30 10:20:10 +00002634/* This doesn't seem to be needed to simulate libpthread.so's external
2635 interface, but many people complain about its absence. */
2636
2637strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2638weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002639
2640
2641/*--------------------------------------------------------------------*/
2642/*--- end vg_libpthread.c ---*/
2643/*--------------------------------------------------------------------*/