blob: 3220cca1a7eba70dde6baf3c52fa40589c0945cb [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
sewardj9a2224b2002-06-19 10:17:40 +000078static
79int my_do_syscall2 ( int syscallno,
80 int arg1, int arg2 );
81
sewardj705d3cb2002-05-23 13:13:12 +000082
sewardje663cb92002-04-12 10:26:32 +000083/* ---------------------------------------------------------------------
84 Helpers. We have to be pretty self-sufficient.
85 ------------------------------------------------------------------ */
86
sewardj436e0582002-04-26 14:31:40 +000087/* Number of times any given error message is printed. */
88#define N_MOANS 3
89
sewardj45b4b372002-04-16 22:50:32 +000090/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
91 Returns 0 (none) if not running on Valgrind. */
92static
93int get_pt_trace_level ( void )
94{
95 int res;
96 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
97 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
98 0, 0, 0, 0);
99 return res;
100}
101
102
sewardje663cb92002-04-12 10:26:32 +0000103static
sewardj2d94c112002-06-03 01:25:54 +0000104void my_exit ( int arg )
sewardje663cb92002-04-12 10:26:32 +0000105{
sewardj45b4b372002-04-16 22:50:32 +0000106 int __res;
sewardje663cb92002-04-12 10:26:32 +0000107 __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
108 : "=a" (__res)
109 : "0" (__NR_exit),
110 "c" (arg) );
sewardj45b4b372002-04-16 22:50:32 +0000111 /* We don't bother to mention the fact that this asm trashes %ebx,
112 since it won't return. If you ever do let it return ... fix
113 this! */
sewardje663cb92002-04-12 10:26:32 +0000114}
115
116
sewardj68b2dd92002-05-10 21:03:56 +0000117/* We need this guy -- it's in valgrind.so. */
118extern void VG_(startup) ( void );
119
120
121/* Just start up Valgrind if it's not already going. VG_(startup)()
122 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000123static __inline__
sewardje663cb92002-04-12 10:26:32 +0000124void ensure_valgrind ( char* caller )
125{
sewardj68b2dd92002-05-10 21:03:56 +0000126 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000127}
128
sewardjbea1caa2002-05-10 23:20:58 +0000129/* While we're at it ... hook our own startup function into this
130 game. */
131__asm__ (
132 ".section .init\n"
133 "\tcall vgPlain_startup"
134);
135
sewardje663cb92002-04-12 10:26:32 +0000136
137static
sewardj3b5d8862002-04-20 13:53:23 +0000138__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +0000139void barf ( char* str )
140{
141 char buf[100];
142 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000143 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000144 strcat(buf, str);
145 strcat(buf, "\n\n");
146 write(2, buf, strlen(buf));
sewardj2d94c112002-06-03 01:25:54 +0000147 my_exit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000148 /* We have to persuade gcc into believing this doesn't return. */
149 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000150}
151
152
sewardj2a3d28c2002-04-14 13:27:00 +0000153static void ignored ( char* msg )
154{
sewardj436e0582002-04-26 14:31:40 +0000155 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000156 char* ig = "valgrind's libpthread.so: IGNORED call to: ";
sewardj45b4b372002-04-16 22:50:32 +0000157 write(2, ig, strlen(ig));
158 write(2, msg, strlen(msg));
159 ig = "\n";
160 write(2, ig, strlen(ig));
161 }
sewardj2a3d28c2002-04-14 13:27:00 +0000162}
163
sewardj30671ff2002-04-21 00:13:57 +0000164static void kludged ( char* msg )
165{
sewardj436e0582002-04-26 14:31:40 +0000166 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000167 char* ig = "valgrind's libpthread.so: KLUDGED call to: ";
168 write(2, ig, strlen(ig));
169 write(2, msg, strlen(msg));
170 ig = "\n";
171 write(2, ig, strlen(ig));
172 }
173}
174
175static void not_inside ( char* msg )
176{
sewardj68b2dd92002-05-10 21:03:56 +0000177 VG_(startup)();
sewardj30671ff2002-04-21 00:13:57 +0000178}
179
sewardjccef2e62002-05-29 19:26:32 +0000180__attribute__((noreturn))
sewardj3b13f0e2002-04-25 20:17:29 +0000181void vgPlain_unimp ( char* what )
182{
sewardj439d45e2002-05-03 20:43:10 +0000183 char* ig = "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ";
sewardj3b13f0e2002-04-25 20:17:29 +0000184 write(2, ig, strlen(ig));
185 write(2, what, strlen(what));
186 ig = "\n";
187 write(2, ig, strlen(ig));
188 barf("Please report this bug to me at: jseward@acm.org");
189}
190
sewardje663cb92002-04-12 10:26:32 +0000191
sewardj457cc472002-06-03 23:13:47 +0000192static
sewardj2d94c112002-06-03 01:25:54 +0000193void my_assert_fail ( Char* expr, Char* file, Int line, Char* fn )
194{
195 static Bool entered = False;
196 if (entered)
197 my_exit(2);
198 entered = True;
199 fprintf(stderr, "\n%s: %s:%d (%s): Assertion `%s' failed.\n",
200 "valgrind", file, line, fn, expr );
201 fprintf(stderr, "Please report this bug to me at: %s\n\n",
202 VG_EMAIL_ADDR);
203 my_exit(1);
204}
205
206#define MY__STRING(__str) #__str
207
208#define my_assert(expr) \
209 ((void) ((expr) ? 0 : \
210 (my_assert_fail (MY__STRING(expr), \
211 __FILE__, __LINE__, \
212 __PRETTY_FUNCTION__), 0)))
213
214
sewardje663cb92002-04-12 10:26:32 +0000215/* ---------------------------------------------------------------------
216 Pass pthread_ calls to Valgrind's request mechanism.
217 ------------------------------------------------------------------ */
218
sewardjf8f819e2002-04-17 23:21:37 +0000219#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000220#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000221
sewardja1ac5cb2002-05-27 13:00:05 +0000222
sewardjf8f819e2002-04-17 23:21:37 +0000223/* ---------------------------------------------------
sewardj4dced352002-06-04 22:54:20 +0000224 Ummm ..
225 ------------------------------------------------ */
226
227static
228void pthread_error ( const char* msg )
229{
230 int res;
231 VALGRIND_MAGIC_SEQUENCE(res, 0,
232 VG_USERREQ__PTHREAD_ERROR,
233 msg, 0, 0, 0);
234}
235
236
237/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000238 THREAD ATTRIBUTES
239 ------------------------------------------------ */
240
sewardj6af4b5d2002-04-16 04:40:49 +0000241int pthread_attr_init(pthread_attr_t *attr)
242{
sewardj7989d0c2002-05-28 11:00:01 +0000243 /* Just initialise the fields which we might look at. */
244 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj6af4b5d2002-04-16 04:40:49 +0000245 return 0;
246}
247
248int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
249{
sewardj7989d0c2002-05-28 11:00:01 +0000250 if (detachstate != PTHREAD_CREATE_JOINABLE
sewardj4dced352002-06-04 22:54:20 +0000251 && detachstate != PTHREAD_CREATE_DETACHED) {
252 pthread_error("pthread_attr_setdetachstate: "
253 "detachstate is invalid");
sewardj7989d0c2002-05-28 11:00:01 +0000254 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000255 }
sewardj7989d0c2002-05-28 11:00:01 +0000256 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000257 return 0;
258}
259
sewardj30671ff2002-04-21 00:13:57 +0000260int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
261{
sewardj436e0582002-04-26 14:31:40 +0000262 static int moans = N_MOANS;
263 if (moans-- > 0)
264 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000265 return 0;
266}
sewardj6af4b5d2002-04-16 04:40:49 +0000267
sewardj0286dd52002-05-16 20:51:15 +0000268__attribute__((weak))
269int pthread_attr_setstacksize (pthread_attr_t *__attr,
270 size_t __stacksize)
271{
sewardja18e2102002-05-18 10:43:22 +0000272 size_t limit;
sewardj3d7c8d62002-06-04 20:59:16 +0000273 char buf[1024];
sewardj0286dd52002-05-16 20:51:15 +0000274 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000275 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
276 - 1000; /* paranoia */
277 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000278 return 0;
sewardj3d7c8d62002-06-04 20:59:16 +0000279 snprintf(buf, sizeof(buf), "pthread_attr_setstacksize: "
280 "requested size %d >= VG_PTHREAD_STACK_SIZE\n "
281 "edit vg_include.h and rebuild.", __stacksize);
282 buf[sizeof(buf)-1] = '\0'; /* Make sure it is zero terminated */
283 barf(buf);
sewardj0286dd52002-05-16 20:51:15 +0000284}
285
286
sewardj30671ff2002-04-21 00:13:57 +0000287/* This is completely bogus. */
288int pthread_attr_getschedparam(const pthread_attr_t *attr,
289 struct sched_param *param)
290{
sewardj436e0582002-04-26 14:31:40 +0000291 static int moans = N_MOANS;
292 if (moans-- > 0)
293 kludged("pthread_attr_getschedparam");
sewardj3e909ce2002-06-03 13:27:15 +0000294# ifdef HAVE_SCHED_PRIORITY
sewardj72d58482002-04-24 02:20:20 +0000295 if (param) param->sched_priority = 0; /* who knows */
296# else
sewardj30671ff2002-04-21 00:13:57 +0000297 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000298# endif
sewardj30671ff2002-04-21 00:13:57 +0000299 return 0;
300}
301
302int pthread_attr_setschedparam(pthread_attr_t *attr,
303 const struct sched_param *param)
304{
sewardj436e0582002-04-26 14:31:40 +0000305 static int moans = N_MOANS;
306 if (moans-- > 0)
307 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000308 return 0;
309}
310
311int pthread_attr_destroy(pthread_attr_t *attr)
312{
sewardj436e0582002-04-26 14:31:40 +0000313 static int moans = N_MOANS;
314 if (moans-- > 0)
315 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000316 return 0;
317}
sewardjf8f819e2002-04-17 23:21:37 +0000318
sewardj0d844232002-06-02 09:29:31 +0000319/* These are no-ops, as with LinuxThreads. */
320int pthread_attr_setscope ( pthread_attr_t *attr, int scope )
321{
322 ensure_valgrind("pthread_attr_setscope");
323 if (scope == PTHREAD_SCOPE_SYSTEM)
324 return 0;
sewardj4dced352002-06-04 22:54:20 +0000325 pthread_error("pthread_attr_setscope: "
326 "invalid or unsupported scope");
sewardj0d844232002-06-02 09:29:31 +0000327 if (scope == PTHREAD_SCOPE_PROCESS)
328 return ENOTSUP;
329 return EINVAL;
330}
331
332int pthread_attr_getscope ( const pthread_attr_t *attr, int *scope )
333{
334 ensure_valgrind("pthread_attr_setscope");
335 if (scope)
336 *scope = PTHREAD_SCOPE_SYSTEM;
337 return 0;
338}
339
sewardj64039bb2002-06-03 00:58:18 +0000340
341/* Pretty bogus. Avoid if possible. */
342int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
343{
344 int detached;
345 size_t limit;
346 ensure_valgrind("pthread_getattr_np");
347 kludged("pthread_getattr_np");
348 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
349 - 1000; /* paranoia */
350 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
351 attr->__schedpolicy = SCHED_OTHER;
352 attr->__schedparam.sched_priority = 0;
353 attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
354 attr->__scope = PTHREAD_SCOPE_SYSTEM;
355 attr->__guardsize = VKI_BYTES_PER_PAGE;
356 attr->__stackaddr = NULL;
357 attr->__stackaddr_set = 0;
358 attr->__stacksize = limit;
359 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
360 VG_USERREQ__SET_OR_GET_DETACH,
361 2 /* get */, thread, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000362 my_assert(detached == 0 || detached == 1);
sewardj64039bb2002-06-03 00:58:18 +0000363 if (detached)
364 attr->__detachstate = PTHREAD_CREATE_DETACHED;
365 return 0;
366}
367
368
369/* Bogus ... */
370int pthread_attr_getstackaddr ( const pthread_attr_t * attr,
371 void ** stackaddr )
372{
373 ensure_valgrind("pthread_attr_getstackaddr");
374 kludged("pthread_attr_getstackaddr");
375 if (stackaddr)
376 *stackaddr = NULL;
377 return 0;
378}
379
380/* Not bogus (!) */
381int pthread_attr_getstacksize ( const pthread_attr_t * _attr,
382 size_t * __stacksize )
383{
384 size_t limit;
385 ensure_valgrind("pthread_attr_getstacksize");
386 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
387 - 1000; /* paranoia */
388 if (__stacksize)
389 *__stacksize = limit;
390 return 0;
391}
392
sewardja3be12f2002-06-17 12:19:44 +0000393int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
394{
395 if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
396 return EINVAL;
397 attr->__schedpolicy = policy;
398 return 0;
399}
400
401int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
402{
403 *policy = attr->__schedpolicy;
404 return 0;
405}
406
407
sewardj20917d82002-05-28 01:36:45 +0000408/* ---------------------------------------------------
409 Helper functions for running a thread
410 and for clearing up afterwards.
411 ------------------------------------------------ */
412
413/* All exiting threads eventually pass through here, bearing the
414 return value, or PTHREAD_CANCELED, in ret_val. */
415static
416__attribute__((noreturn))
417void thread_exit_wrapper ( void* ret_val )
418{
sewardj870497a2002-05-29 01:06:47 +0000419 int detached, res;
420 CleanupEntry cu;
421 pthread_key_t key;
422
sewardj20917d82002-05-28 01:36:45 +0000423 /* Run this thread's cleanup handlers. */
sewardj8ad94e12002-05-29 00:10:20 +0000424 while (1) {
425 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
426 VG_USERREQ__CLEANUP_POP,
427 &cu, 0, 0, 0);
428 if (res == -1) break; /* stack empty */
sewardj2d94c112002-06-03 01:25:54 +0000429 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000430 if (0) printf("running exit cleanup handler");
431 cu.fn ( cu.arg );
432 }
433
sewardj870497a2002-05-29 01:06:47 +0000434 /* Run this thread's key finalizers. Really this should be run
435 PTHREAD_DESTRUCTOR_ITERATIONS times. */
436 for (key = 0; key < VG_N_THREAD_KEYS; key++) {
437 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
438 VG_USERREQ__GET_KEY_D_AND_S,
439 key, &cu, 0, 0 );
440 if (res == 0) {
441 /* valid key */
442 if (cu.fn && cu.arg)
443 cu.fn /* destructor for key */
444 ( cu.arg /* specific for key for this thread */ );
445 continue;
446 }
sewardj2d94c112002-06-03 01:25:54 +0000447 my_assert(res == -1);
sewardj870497a2002-05-29 01:06:47 +0000448 }
sewardj20917d82002-05-28 01:36:45 +0000449
450 /* Decide on my final disposition. */
451 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
452 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000453 2 /* get */, pthread_self(), 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000454 my_assert(detached == 0 || detached == 1);
sewardj20917d82002-05-28 01:36:45 +0000455
456 if (detached) {
457 /* Detached; I just quit right now. */
458 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
459 VG_USERREQ__QUIT, 0, 0, 0, 0);
460 } else {
461 /* Not detached; so I wait for a joiner. */
462 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
463 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
464 }
465 /* NOTREACHED */
466 barf("thread_exit_wrapper: still alive?!");
467}
468
469
470/* This function is a wrapper function for running a thread. It runs
471 the root function specified in pthread_create, and then, should the
472 root function return a value, it arranges to run the thread's
473 cleanup handlers and exit correctly. */
474
475/* Struct used to convey info from pthread_create to
476 thread_wrapper. */
477typedef
478 struct {
479 pthread_attr_t* attr;
480 void* (*root_fn) ( void* );
481 void* arg;
482 }
483 NewThreadInfo;
484
485
486/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
487 not return. Note that this runs in the new thread, not the
488 parent. */
489static
490__attribute__((noreturn))
491void thread_wrapper ( NewThreadInfo* info )
492{
493 int res;
494 pthread_attr_t* attr;
495 void* (*root_fn) ( void* );
496 void* arg;
497 void* ret_val;
498
499 attr = info->attr;
500 root_fn = info->root_fn;
501 arg = info->arg;
502
sewardj20917d82002-05-28 01:36:45 +0000503 /* Free up the arg block that pthread_create malloced. */
504 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
505 VG_USERREQ__FREE, info, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000506 my_assert(res == 0);
sewardj20917d82002-05-28 01:36:45 +0000507
sewardj7989d0c2002-05-28 11:00:01 +0000508 /* Minimally observe the attributes supplied. */
509 if (attr) {
sewardj2d94c112002-06-03 01:25:54 +0000510 my_assert(attr->__detachstate == PTHREAD_CREATE_DETACHED
sewardj7989d0c2002-05-28 11:00:01 +0000511 || attr->__detachstate == PTHREAD_CREATE_JOINABLE);
512 if (attr->__detachstate == PTHREAD_CREATE_DETACHED)
513 pthread_detach(pthread_self());
514 }
515
sewardj20917d82002-05-28 01:36:45 +0000516 /* The root function might not return. But if it does we simply
517 move along to thread_exit_wrapper. All other ways out for the
518 thread (cancellation, or calling pthread_exit) lead there
519 too. */
520 ret_val = root_fn(arg);
521 thread_exit_wrapper(ret_val);
522 /* NOTREACHED */
523}
524
525
sewardjf8f819e2002-04-17 23:21:37 +0000526/* ---------------------------------------------------
527 THREADs
528 ------------------------------------------------ */
529
sewardjff42d1d2002-05-22 13:17:31 +0000530__attribute__((weak))
531int pthread_yield ( void )
532{
533 int res;
534 ensure_valgrind("pthread_yield");
535 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
536 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
537 return 0;
538}
539
540
sewardj6072c362002-04-19 14:40:57 +0000541int pthread_equal(pthread_t thread1, pthread_t thread2)
542{
543 return thread1 == thread2 ? 1 : 0;
544}
545
546
sewardj20917d82002-05-28 01:36:45 +0000547/* Bundle up the args into a malloc'd block and create a new thread
548 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000549int
550pthread_create (pthread_t *__restrict __thread,
551 __const pthread_attr_t *__restrict __attr,
552 void *(*__start_routine) (void *),
553 void *__restrict __arg)
554{
sewardj20917d82002-05-28 01:36:45 +0000555 int tid_child;
556 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000557
sewardj20917d82002-05-28 01:36:45 +0000558 ensure_valgrind("pthread_create");
559
560 /* Allocate space for the arg block. thread_wrapper will free
561 it. */
562 VALGRIND_MAGIC_SEQUENCE(info, NULL /* default */,
563 VG_USERREQ__MALLOC,
564 sizeof(NewThreadInfo), 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000565 my_assert(info != NULL);
sewardj20917d82002-05-28 01:36:45 +0000566
567 info->attr = (pthread_attr_t*)__attr;
568 info->root_fn = __start_routine;
569 info->arg = __arg;
570 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
571 VG_USERREQ__APPLY_IN_NEW_THREAD,
572 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000573 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000574
575 if (__thread)
576 *__thread = tid_child;
577 return 0; /* success */
578}
sewardje663cb92002-04-12 10:26:32 +0000579
580
581int
582pthread_join (pthread_t __th, void **__thread_return)
583{
584 int res;
585 ensure_valgrind("pthread_join");
586 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
587 VG_USERREQ__PTHREAD_JOIN,
588 __th, __thread_return, 0, 0);
589 return res;
590}
591
592
sewardj3b5d8862002-04-20 13:53:23 +0000593void pthread_exit(void *retval)
594{
sewardj3b5d8862002-04-20 13:53:23 +0000595 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000596 /* Simple! */
597 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000598}
599
sewardje663cb92002-04-12 10:26:32 +0000600
sewardj3b13f0e2002-04-25 20:17:29 +0000601pthread_t pthread_self(void)
sewardje663cb92002-04-12 10:26:32 +0000602{
603 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000604 ensure_valgrind("pthread_self");
sewardj439d45e2002-05-03 20:43:10 +0000605 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardje663cb92002-04-12 10:26:32 +0000606 VG_USERREQ__PTHREAD_GET_THREADID,
607 0, 0, 0, 0);
sewardj439d45e2002-05-03 20:43:10 +0000608 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000609 barf("pthread_self: invalid ThreadId");
610 return tid;
sewardje663cb92002-04-12 10:26:32 +0000611}
612
613
sewardj853f55d2002-04-26 00:27:53 +0000614int pthread_detach(pthread_t th)
615{
sewardj20917d82002-05-28 01:36:45 +0000616 int res;
617 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000618 /* First we enquire as to the current detach state. */
619 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000620 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000621 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000622 if (res == -1) {
623 /* not found */
624 pthread_error("pthread_detach: "
625 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000626 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000627 }
628 if (res == 1) {
629 /* already detached */
630 pthread_error("pthread_detach: "
631 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000632 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000633 }
sewardj7989d0c2002-05-28 11:00:01 +0000634 if (res == 0) {
635 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
636 VG_USERREQ__SET_OR_GET_DETACH,
637 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000638 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000639 return 0;
640 }
641 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000642}
643
644
sewardjf8f819e2002-04-17 23:21:37 +0000645/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000646 CLEANUP STACKS
647 ------------------------------------------------ */
648
649void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
650 void (*__routine) (void *),
651 void *__arg)
652{
653 int res;
654 CleanupEntry cu;
655 ensure_valgrind("_pthread_cleanup_push");
656 cu.fn = __routine;
657 cu.arg = __arg;
658 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
659 VG_USERREQ__CLEANUP_PUSH,
660 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000661 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000662}
663
664
665void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
666 void (*__routine) (void *),
667 void *__arg)
668{
669 /* As _pthread_cleanup_push, but first save the thread's original
670 cancellation type in __buffer and set it to Deferred. */
671 int orig_ctype;
672 ensure_valgrind("_pthread_cleanup_push_defer");
673 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000674 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
675 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
676 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000677 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
678 VG_USERREQ__SET_CANCELTYPE,
679 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000680 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000681 *((int*)(__buffer)) = orig_ctype;
682 /* Now push the cleanup. */
683 _pthread_cleanup_push(NULL, __routine, __arg);
684}
685
686
687void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
688 int __execute)
689{
690 int res;
691 CleanupEntry cu;
692 ensure_valgrind("_pthread_cleanup_push");
693 cu.fn = cu.arg = NULL; /* paranoia */
694 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
695 VG_USERREQ__CLEANUP_POP,
696 &cu, 0, 0, 0);
697 if (res == 0) {
698 /* pop succeeded */
699 if (__execute) {
700 cu.fn ( cu.arg );
701 }
702 return;
703 }
704 if (res == -1) {
705 /* stack underflow */
706 return;
707 }
708 barf("_pthread_cleanup_pop");
709}
710
711
712void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
713 int __execute)
714{
715 int orig_ctype, fake_ctype;
716 /* As _pthread_cleanup_pop, but after popping/running the handler,
717 restore the thread's original cancellation type from the first
718 word of __buffer. */
719 _pthread_cleanup_pop(NULL, __execute);
720 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000721 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000722 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000723 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
724 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
725 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000726 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
727 VG_USERREQ__SET_CANCELTYPE,
728 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000729 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000730}
731
732
733/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000734 MUTEX ATTRIBUTES
735 ------------------------------------------------ */
736
sewardj5905fae2002-04-26 13:25:00 +0000737int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000738{
sewardjf8f819e2002-04-17 23:21:37 +0000739 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000740 return 0;
sewardje663cb92002-04-12 10:26:32 +0000741}
742
sewardj5905fae2002-04-26 13:25:00 +0000743int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000744{
745 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000746# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000747 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000748 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000749# endif
sewardja1679dd2002-05-10 22:31:40 +0000750# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000751 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000752# endif
sewardjf8f819e2002-04-17 23:21:37 +0000753 case PTHREAD_MUTEX_RECURSIVE_NP:
754 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000755 attr->__mutexkind = type;
756 return 0;
757 default:
sewardj4dced352002-06-04 22:54:20 +0000758 pthread_error("pthread_mutexattr_settype: "
759 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000760 return EINVAL;
761 }
762}
763
sewardj5905fae2002-04-26 13:25:00 +0000764int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000765{
766 return 0;
767}
768
769
770/* ---------------------------------------------------
771 MUTEXes
772 ------------------------------------------------ */
773
sewardj5905fae2002-04-26 13:25:00 +0000774int __pthread_mutex_init(pthread_mutex_t *mutex,
775 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000776{
sewardj604ec3c2002-04-18 22:38:41 +0000777 mutex->__m_count = 0;
778 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
779 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
780 if (mutexattr)
781 mutex->__m_kind = mutexattr->__mutexkind;
782 return 0;
sewardje663cb92002-04-12 10:26:32 +0000783}
784
sewardj439d45e2002-05-03 20:43:10 +0000785
sewardj5905fae2002-04-26 13:25:00 +0000786int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000787{
788 int res;
sewardj436e0582002-04-26 14:31:40 +0000789 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000790 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000791 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
792 VG_USERREQ__PTHREAD_MUTEX_LOCK,
793 mutex, 0, 0, 0);
794 return res;
sewardj439d45e2002-05-03 20:43:10 +0000795 } else {
796 if (moans-- > 0)
797 not_inside("pthread_mutex_lock");
798 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000799 }
800}
801
sewardj439d45e2002-05-03 20:43:10 +0000802
sewardj5905fae2002-04-26 13:25:00 +0000803int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000804{
805 int res;
sewardj436e0582002-04-26 14:31:40 +0000806 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000807 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000808 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
809 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
810 mutex, 0, 0, 0);
811 return res;
sewardj439d45e2002-05-03 20:43:10 +0000812 } else {
813 if (moans-- > 0)
814 not_inside("pthread_mutex_trylock");
815 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000816 }
817}
818
sewardj439d45e2002-05-03 20:43:10 +0000819
sewardj5905fae2002-04-26 13:25:00 +0000820int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000821{
822 int res;
sewardj436e0582002-04-26 14:31:40 +0000823 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000824 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000825 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
826 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
827 mutex, 0, 0, 0);
828 return res;
sewardj439d45e2002-05-03 20:43:10 +0000829 } else {
830 if (moans-- > 0)
831 not_inside("pthread_mutex_unlock");
832 return 0;
sewardje663cb92002-04-12 10:26:32 +0000833 }
834}
835
sewardj439d45e2002-05-03 20:43:10 +0000836
sewardj5905fae2002-04-26 13:25:00 +0000837int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000838{
sewardj604ec3c2002-04-18 22:38:41 +0000839 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
840 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +0000841 if (mutex->__m_count > 0) {
842 pthread_error("pthread_mutex_destroy: "
843 "mutex is still in use");
sewardj604ec3c2002-04-18 22:38:41 +0000844 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +0000845 }
846 mutex->__m_count = 0;
847 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
848 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
849 return 0;
sewardje663cb92002-04-12 10:26:32 +0000850}
851
852
sewardjf8f819e2002-04-17 23:21:37 +0000853/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000854 CONDITION VARIABLES
855 ------------------------------------------------ */
856
857/* LinuxThreads supports no attributes for conditions. Hence ... */
858
859int pthread_condattr_init(pthread_condattr_t *attr)
860{
861 return 0;
862}
863
sewardj0738a592002-04-20 13:59:33 +0000864int pthread_condattr_destroy(pthread_condattr_t *attr)
865{
866 return 0;
867}
sewardj6072c362002-04-19 14:40:57 +0000868
869int pthread_cond_init( pthread_cond_t *cond,
870 const pthread_condattr_t *cond_attr)
871{
872 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
873 return 0;
874}
875
sewardjf854f472002-04-21 12:19:41 +0000876int pthread_cond_destroy(pthread_cond_t *cond)
877{
878 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000879 static int moans = N_MOANS;
880 if (moans-- > 0)
881 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000882 return 0;
883}
sewardj6072c362002-04-19 14:40:57 +0000884
885/* ---------------------------------------------------
886 SCHEDULING
887 ------------------------------------------------ */
888
889/* This is completely bogus. */
890int pthread_getschedparam(pthread_t target_thread,
891 int *policy,
892 struct sched_param *param)
893{
sewardj436e0582002-04-26 14:31:40 +0000894 static int moans = N_MOANS;
895 if (moans-- > 0)
896 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000897 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +0000898# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +0000899 if (param) param->sched_priority = 0; /* who knows */
900# else
sewardj6072c362002-04-19 14:40:57 +0000901 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000902# endif
sewardj6072c362002-04-19 14:40:57 +0000903 return 0;
904}
905
906int pthread_setschedparam(pthread_t target_thread,
907 int policy,
908 const struct sched_param *param)
909{
sewardj436e0582002-04-26 14:31:40 +0000910 static int moans = N_MOANS;
911 if (moans-- > 0)
912 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000913 return 0;
914}
915
sewardj3b5d8862002-04-20 13:53:23 +0000916int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
917{
918 int res;
919 ensure_valgrind("pthread_cond_wait");
920 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
921 VG_USERREQ__PTHREAD_COND_WAIT,
922 cond, mutex, 0, 0);
923 return res;
924}
925
sewardj5f07b662002-04-23 16:52:51 +0000926int pthread_cond_timedwait ( pthread_cond_t *cond,
927 pthread_mutex_t *mutex,
928 const struct timespec *abstime )
929{
930 int res;
931 unsigned int ms_now, ms_end;
932 struct timeval timeval_now;
933 unsigned long long int ull_ms_now_after_1970;
934 unsigned long long int ull_ms_end_after_1970;
935
936 ensure_valgrind("pthread_cond_timedwait");
937 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
938 VG_USERREQ__READ_MILLISECOND_TIMER,
939 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000940 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +0000941 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +0000942 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +0000943
944 ull_ms_now_after_1970
945 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
946 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
947 ull_ms_end_after_1970
948 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
949 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +0000950 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
951 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +0000952 ms_end
953 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
954 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
955 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
956 cond, mutex, ms_end, 0);
957 return res;
958}
959
960
sewardj3b5d8862002-04-20 13:53:23 +0000961int pthread_cond_signal(pthread_cond_t *cond)
962{
963 int res;
964 ensure_valgrind("pthread_cond_signal");
965 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
966 VG_USERREQ__PTHREAD_COND_SIGNAL,
967 cond, 0, 0, 0);
968 return res;
969}
970
971int pthread_cond_broadcast(pthread_cond_t *cond)
972{
973 int res;
974 ensure_valgrind("pthread_cond_broadcast");
975 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
976 VG_USERREQ__PTHREAD_COND_BROADCAST,
977 cond, 0, 0, 0);
978 return res;
979}
980
sewardj6072c362002-04-19 14:40:57 +0000981
982/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000983 CANCELLATION
984 ------------------------------------------------ */
985
sewardj853f55d2002-04-26 00:27:53 +0000986int pthread_setcancelstate(int state, int *oldstate)
987{
sewardj20917d82002-05-28 01:36:45 +0000988 int res;
989 ensure_valgrind("pthread_setcancelstate");
990 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +0000991 && state != PTHREAD_CANCEL_DISABLE) {
992 pthread_error("pthread_setcancelstate: "
993 "invalid state");
sewardj20917d82002-05-28 01:36:45 +0000994 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000995 }
sewardj2d94c112002-06-03 01:25:54 +0000996 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
997 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +0000998 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
999 VG_USERREQ__SET_CANCELSTATE,
1000 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001001 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001002 if (oldstate)
1003 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001004 return 0;
1005}
1006
sewardje663cb92002-04-12 10:26:32 +00001007int pthread_setcanceltype(int type, int *oldtype)
1008{
sewardj20917d82002-05-28 01:36:45 +00001009 int res;
1010 ensure_valgrind("pthread_setcanceltype");
1011 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001012 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1013 pthread_error("pthread_setcanceltype: "
1014 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001015 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001016 }
sewardj2d94c112002-06-03 01:25:54 +00001017 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1018 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001019 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1020 VG_USERREQ__SET_CANCELTYPE,
1021 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001022 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001023 if (oldtype)
1024 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001025 return 0;
1026}
1027
sewardje663cb92002-04-12 10:26:32 +00001028int pthread_cancel(pthread_t thread)
1029{
1030 int res;
1031 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001032 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1033 VG_USERREQ__SET_CANCELPEND,
1034 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001035 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001036 return res;
1037}
1038
sewardjd140e442002-05-29 01:21:19 +00001039static __inline__
1040void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001041{
sewardj20917d82002-05-28 01:36:45 +00001042 int res;
1043 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1044 VG_USERREQ__TESTCANCEL,
1045 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001046 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001047}
1048
sewardjd140e442002-05-29 01:21:19 +00001049void pthread_testcancel ( void )
1050{
1051 __my_pthread_testcancel();
1052}
1053
sewardj20917d82002-05-28 01:36:45 +00001054
sewardjef037c72002-05-30 00:40:03 +00001055/* Not really sure what this is for. I suspect for doing the POSIX
1056 requirements for fork() and exec(). We do this internally anyway
1057 whenever those syscalls are observed, so this could be superfluous,
1058 but hey ...
1059*/
sewardj853f55d2002-04-26 00:27:53 +00001060void __pthread_kill_other_threads_np ( void )
1061{
sewardjef037c72002-05-30 00:40:03 +00001062 int res;
1063 ensure_valgrind("__pthread_kill_other_threads_np");
1064 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1065 VG_USERREQ__NUKE_OTHER_THREADS,
1066 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001067 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001068}
1069
sewardje663cb92002-04-12 10:26:32 +00001070
sewardjf8f819e2002-04-17 23:21:37 +00001071/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001072 SIGNALS
1073 ------------------------------------------------ */
1074
1075#include <signal.h>
1076
1077int pthread_sigmask(int how, const sigset_t *newmask,
1078 sigset_t *oldmask)
1079{
1080 int res;
1081
1082 /* A bit subtle, because the scheduler expects newmask and oldmask
1083 to be vki_sigset_t* rather than sigset_t*, and the two are
1084 different. Fortunately the first 64 bits of a sigset_t are
1085 exactly a vki_sigset_t, so we just pass the pointers through
1086 unmodified. Haaaack!
1087
1088 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001089 constants to VKI_ constants, so that the former do not have to
1090 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001091
1092 ensure_valgrind("pthread_sigmask");
1093
1094 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001095 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1096 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1097 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001098 default: pthread_error("pthread_sigmask: invalid how");
1099 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001100 }
1101
1102 /* Crude check */
1103 if (newmask == NULL)
1104 return EFAULT;
1105
1106 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1107 VG_USERREQ__PTHREAD_SIGMASK,
1108 how, newmask, oldmask, 0);
1109
1110 /* The scheduler tells us of any memory violations. */
1111 return res == 0 ? 0 : EFAULT;
1112}
1113
1114
1115int sigwait ( const sigset_t* set, int* sig )
1116{
1117 int res;
1118 ensure_valgrind("sigwait");
1119 /* As with pthread_sigmask we deliberately confuse sigset_t with
1120 vki_ksigset_t. */
1121 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1122 VG_USERREQ__SIGWAIT,
1123 set, sig, 0, 0);
1124 return res;
1125}
1126
1127
sewardj018f7622002-05-15 21:13:39 +00001128int pthread_kill(pthread_t thread, int signo)
1129{
1130 int res;
1131 ensure_valgrind("pthread_kill");
1132 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1133 VG_USERREQ__PTHREAD_KILL,
1134 thread, signo, 0, 0);
1135 return res;
1136}
1137
1138
sewardj3665ded2002-05-16 16:57:25 +00001139/* Copied verbatim from Linuxthreads */
1140/* Redefine raise() to send signal to calling thread only,
1141 as per POSIX 1003.1c */
1142int raise (int sig)
1143{
1144 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001145 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001146 return 0;
sewardj4dced352002-06-04 22:54:20 +00001147 } else {
sewardj3665ded2002-05-16 16:57:25 +00001148 errno = retcode;
1149 return -1;
1150 }
1151}
1152
1153
sewardj9a2224b2002-06-19 10:17:40 +00001154int pause ( void )
1155{
1156 unsigned int n_orig, n_now;
1157 struct vki_timespec nanosleep_interval;
1158 ensure_valgrind("pause");
1159
1160 /* This is surely a cancellation point. */
1161 __my_pthread_testcancel();
1162
1163 VALGRIND_MAGIC_SEQUENCE(n_orig, 0xFFFFFFFF /* default */,
1164 VG_USERREQ__GET_N_SIGS_RETURNED,
1165 0, 0, 0, 0);
1166 my_assert(n_orig != 0xFFFFFFFF);
1167
1168 while (1) {
1169 VALGRIND_MAGIC_SEQUENCE(n_now, 0xFFFFFFFF /* default */,
1170 VG_USERREQ__GET_N_SIGS_RETURNED,
1171 0, 0, 0, 0);
1172 my_assert(n_now != 0xFFFFFFFF);
1173 my_assert(n_now >= n_orig);
1174 if (n_now != n_orig) break;
1175
1176 nanosleep_interval.tv_sec = 0;
1177 nanosleep_interval.tv_nsec = 52 * 1000 * 1000; /* 52 milliseconds */
1178 /* It's critical here that valgrind's nanosleep implementation
1179 is nonblocking. */
1180 (void)my_do_syscall2(__NR_nanosleep,
1181 (int)(&nanosleep_interval), (int)NULL);
1182 }
1183
1184 * (__errno_location()) = EINTR;
1185 return -1;
1186}
1187
1188
sewardjb48e5002002-05-13 00:16:03 +00001189/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001190 THREAD-SPECIFICs
1191 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001192
sewardj5905fae2002-04-26 13:25:00 +00001193int __pthread_key_create(pthread_key_t *key,
1194 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001195{
sewardj5f07b662002-04-23 16:52:51 +00001196 int res;
1197 ensure_valgrind("pthread_key_create");
1198 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1199 VG_USERREQ__PTHREAD_KEY_CREATE,
1200 key, destr_function, 0, 0);
1201 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001202}
1203
1204int pthread_key_delete(pthread_key_t key)
1205{
sewardj436e0582002-04-26 14:31:40 +00001206 static int moans = N_MOANS;
1207 if (moans-- > 0)
1208 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +00001209 return 0;
1210}
1211
sewardj5905fae2002-04-26 13:25:00 +00001212int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001213{
sewardj5f07b662002-04-23 16:52:51 +00001214 int res;
1215 ensure_valgrind("pthread_setspecific");
1216 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1217 VG_USERREQ__PTHREAD_SETSPECIFIC,
1218 key, pointer, 0, 0);
1219 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001220}
1221
sewardj5905fae2002-04-26 13:25:00 +00001222void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001223{
sewardj5f07b662002-04-23 16:52:51 +00001224 int res;
1225 ensure_valgrind("pthread_getspecific");
1226 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1227 VG_USERREQ__PTHREAD_GETSPECIFIC,
1228 key, 0 , 0, 0);
1229 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001230}
1231
sewardjf8f819e2002-04-17 23:21:37 +00001232
1233/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001234 ONCEry
1235 ------------------------------------------------ */
1236
1237static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1238
1239
sewardj5905fae2002-04-26 13:25:00 +00001240int __pthread_once ( pthread_once_t *once_control,
1241 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001242{
1243 int res;
1244 ensure_valgrind("pthread_once");
1245
sewardj68b2dd92002-05-10 21:03:56 +00001246 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001247
sewardj68b2dd92002-05-10 21:03:56 +00001248 if (res != 0) {
sewardj89d3d852002-04-24 19:21:39 +00001249 barf("pthread_once: Looks like your program's "
1250 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001251 }
sewardj89d3d852002-04-24 19:21:39 +00001252
1253 if (*once_control == 0) {
1254 *once_control = 1;
1255 init_routine();
1256 }
1257
sewardj68b2dd92002-05-10 21:03:56 +00001258 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001259
1260 return 0;
1261}
1262
1263
1264/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001265 MISC
1266 ------------------------------------------------ */
1267
sewardj5905fae2002-04-26 13:25:00 +00001268int __pthread_atfork ( void (*prepare)(void),
1269 void (*parent)(void),
1270 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001271{
sewardjccef2e62002-05-29 19:26:32 +00001272 /* We have to do this properly or not at all; faking it isn't an
1273 option. */
1274 vgPlain_unimp("__pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +00001275}
1276
1277
sewardjbb990782002-05-08 02:01:14 +00001278__attribute__((weak))
1279void __pthread_initialize ( void )
1280{
sewardjbea1caa2002-05-10 23:20:58 +00001281 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001282}
1283
1284
sewardj853f55d2002-04-26 00:27:53 +00001285/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001286 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001287 ------------------------------------------------ */
1288
sewardj3b13f0e2002-04-25 20:17:29 +00001289#include <resolv.h>
1290static int thread_specific_errno[VG_N_THREADS];
1291static int thread_specific_h_errno[VG_N_THREADS];
1292static struct __res_state
1293 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001294
sewardj3b13f0e2002-04-25 20:17:29 +00001295int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001296{
1297 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001298 /* ensure_valgrind("__errno_location"); */
1299 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001300 VG_USERREQ__PTHREAD_GET_THREADID,
1301 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001302 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001303 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001304 barf("__errno_location: invalid ThreadId");
1305 return & thread_specific_errno[tid];
1306}
1307
1308int* __h_errno_location ( void )
1309{
1310 int tid;
1311 /* ensure_valgrind("__h_errno_location"); */
1312 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1313 VG_USERREQ__PTHREAD_GET_THREADID,
1314 0, 0, 0, 0);
1315 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001316 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001317 barf("__h_errno_location: invalid ThreadId");
1318 return & thread_specific_h_errno[tid];
1319}
1320
1321struct __res_state* __res_state ( void )
1322{
1323 int tid;
1324 /* ensure_valgrind("__res_state"); */
1325 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1326 VG_USERREQ__PTHREAD_GET_THREADID,
1327 0, 0, 0, 0);
1328 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001329 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001330 barf("__res_state: invalid ThreadId");
1331 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001332}
1333
1334
sewardj5716dbb2002-04-26 03:28:18 +00001335/* ---------------------------------------------------
1336 LIBC-PRIVATE SPECIFIC DATA
1337 ------------------------------------------------ */
1338
1339/* Relies on assumption that initial private data is NULL. This
1340 should be fixed somehow. */
1341
1342/* The allowable keys (indices) (all 2 of them).
1343 From sysdeps/pthread/bits/libc-tsd.h
1344*/
sewardj70adeb22002-04-27 01:35:38 +00001345#define N_LIBC_TSD_EXTRA_KEYS 1
1346
sewardj5716dbb2002-04-26 03:28:18 +00001347enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1348 _LIBC_TSD_KEY_DL_ERROR,
1349 _LIBC_TSD_KEY_N };
1350
1351/* Auto-initialising subsystem. libc_specifics_inited is set
1352 after initialisation. libc_specifics_inited_mx guards it. */
1353static int libc_specifics_inited = 0;
1354static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1355
1356/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001357static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1358 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001359
1360/* Initialise the keys, if they are not already initialise. */
1361static
1362void init_libc_tsd_keys ( void )
1363{
1364 int res, i;
1365 pthread_key_t k;
1366
1367 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1368 if (res != 0) barf("init_libc_tsd_keys: lock");
1369
1370 if (libc_specifics_inited == 0) {
1371 /* printf("INIT libc specifics\n"); */
1372 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001373 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001374 res = pthread_key_create(&k, NULL);
1375 if (res != 0) barf("init_libc_tsd_keys: create");
1376 libc_specifics_keys[i] = k;
1377 }
1378 }
1379
1380 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1381 if (res != 0) barf("init_libc_tsd_keys: unlock");
1382}
1383
1384
1385static int
1386libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1387 const void * pointer )
1388{
sewardj70adeb22002-04-27 01:35:38 +00001389 int res;
1390 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001391 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001392 if (key < _LIBC_TSD_KEY_MALLOC
1393 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001394 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001395 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1396 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001397 "valgrind's libpthread.so: libc_internal_tsd_set: "
1398 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001399 init_libc_tsd_keys();
1400 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1401 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1402 return 0;
1403}
1404
1405static void *
1406libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1407{
sewardj70adeb22002-04-27 01:35:38 +00001408 void* v;
1409 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001410 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001411 if (key < _LIBC_TSD_KEY_MALLOC
1412 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001413 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001414 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1415 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001416 "valgrind's libpthread.so: libc_internal_tsd_get: "
1417 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001418 init_libc_tsd_keys();
1419 v = pthread_getspecific(libc_specifics_keys[key]);
1420 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1421 return v;
1422}
1423
1424
1425
1426
sewardj70adeb22002-04-27 01:35:38 +00001427int (*__libc_internal_tsd_set)
1428 (enum __libc_tsd_key_t key, const void * pointer)
1429 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001430
sewardj70adeb22002-04-27 01:35:38 +00001431void* (*__libc_internal_tsd_get)
1432 (enum __libc_tsd_key_t key)
1433 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001434
1435
sewardje663cb92002-04-12 10:26:32 +00001436/* ---------------------------------------------------------------------
1437 These are here (I think) because they are deemed cancellation
1438 points by POSIX. For the moment we'll simply pass the call along
1439 to the corresponding thread-unaware (?) libc routine.
1440 ------------------------------------------------------------------ */
1441
sewardje663cb92002-04-12 10:26:32 +00001442#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001443#include <sys/types.h>
1444#include <sys/socket.h>
1445
sewardjd529a442002-05-04 19:49:21 +00001446#ifdef GLIBC_2_1
1447extern
1448int __sigaction
1449 (int signum,
1450 const struct sigaction *act,
1451 struct sigaction *oldact);
1452#else
sewardje663cb92002-04-12 10:26:32 +00001453extern
1454int __libc_sigaction
1455 (int signum,
1456 const struct sigaction *act,
1457 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001458#endif
sewardje663cb92002-04-12 10:26:32 +00001459int sigaction(int signum,
1460 const struct sigaction *act,
1461 struct sigaction *oldact)
1462{
sewardjd140e442002-05-29 01:21:19 +00001463 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001464# ifdef GLIBC_2_1
1465 return __sigaction(signum, act, oldact);
1466# else
sewardj45b4b372002-04-16 22:50:32 +00001467 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001468# endif
sewardje663cb92002-04-12 10:26:32 +00001469}
1470
1471
1472extern
1473int __libc_connect(int sockfd,
1474 const struct sockaddr *serv_addr,
1475 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001476__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001477int connect(int sockfd,
1478 const struct sockaddr *serv_addr,
1479 socklen_t addrlen)
1480{
sewardjd140e442002-05-29 01:21:19 +00001481 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001482 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001483}
1484
1485
1486extern
1487int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001488__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001489int fcntl(int fd, int cmd, long arg)
1490{
sewardjd140e442002-05-29 01:21:19 +00001491 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001492 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001493}
1494
1495
1496extern
1497ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001498__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001499ssize_t write(int fd, const void *buf, size_t count)
1500{
sewardjd140e442002-05-29 01:21:19 +00001501 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001502 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001503}
1504
1505
1506extern
1507ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001508__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001509ssize_t read(int fd, void *buf, size_t count)
1510{
sewardjd140e442002-05-29 01:21:19 +00001511 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001512 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001513}
1514
sewardjbe32e452002-04-24 20:29:58 +00001515
1516extern
sewardj853f55d2002-04-26 00:27:53 +00001517int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001518__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001519int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001520{
sewardjd140e442002-05-29 01:21:19 +00001521 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001522 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001523}
1524
sewardje663cb92002-04-12 10:26:32 +00001525
1526extern
sewardj853f55d2002-04-26 00:27:53 +00001527int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001528__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001529int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001530{
sewardjd140e442002-05-29 01:21:19 +00001531 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001532 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001533}
1534
1535
1536extern
1537int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001538__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001539int close(int fd)
1540{
sewardjd140e442002-05-29 01:21:19 +00001541 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001542 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001543}
1544
1545
1546extern
1547int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001548__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001549int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1550{
sewardjd140e442002-05-29 01:21:19 +00001551 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001552 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001553 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001554 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001555}
1556
1557
1558extern
1559pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001560pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001561{
sewardjd140e442002-05-29 01:21:19 +00001562 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001563 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001564}
1565
1566
1567extern
1568pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001569__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001570pid_t waitpid(pid_t pid, int *status, int options)
1571{
sewardjd140e442002-05-29 01:21:19 +00001572 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001573 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001574}
1575
1576
1577extern
1578int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001579__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001580int nanosleep(const struct timespec *req, struct timespec *rem)
1581{
sewardjd140e442002-05-29 01:21:19 +00001582 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001583 return __libc_nanosleep(req, rem);
1584}
1585
sewardjbe32e452002-04-24 20:29:58 +00001586
sewardje663cb92002-04-12 10:26:32 +00001587extern
1588int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001589__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001590int fsync(int fd)
1591{
sewardjd140e442002-05-29 01:21:19 +00001592 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001593 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001594}
1595
sewardjbe32e452002-04-24 20:29:58 +00001596
sewardj70c75362002-04-13 04:18:32 +00001597extern
1598off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001599__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001600off_t lseek(int fildes, off_t offset, int whence)
1601{
sewardjd140e442002-05-29 01:21:19 +00001602 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001603 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001604}
1605
sewardjbe32e452002-04-24 20:29:58 +00001606
1607extern
1608__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001609__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001610__off64_t lseek64(int fildes, __off64_t offset, int whence)
1611{
sewardjd140e442002-05-29 01:21:19 +00001612 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001613 return __libc_lseek64(fildes, offset, whence);
1614}
1615
1616
sewardj726c4122002-05-16 23:39:10 +00001617extern
1618ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1619 __off64_t __offset);
1620ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1621 __off64_t __offset)
1622{
sewardjd140e442002-05-29 01:21:19 +00001623 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001624 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1625}
1626
1627
sewardja18e2102002-05-18 10:43:22 +00001628extern
1629ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1630 __off64_t __offset);
1631ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1632 __off64_t __offset)
1633{
sewardjd140e442002-05-29 01:21:19 +00001634 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001635 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1636}
1637
sewardj726c4122002-05-16 23:39:10 +00001638
sewardj39b93b12002-05-18 10:56:27 +00001639extern
1640ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1641__attribute__((weak))
1642ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1643{
sewardjd140e442002-05-29 01:21:19 +00001644 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001645 return __libc_pwrite(fd, buf, count, offset);
1646}
1647
1648
1649extern
1650ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1651__attribute__((weak))
1652ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1653{
sewardjd140e442002-05-29 01:21:19 +00001654 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001655 return __libc_pread(fd, buf, count, offset);
1656}
1657
1658
sewardj6af4b5d2002-04-16 04:40:49 +00001659extern
1660void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001661/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001662void longjmp(jmp_buf env, int val)
1663{
1664 __libc_longjmp(env, val);
1665}
1666
sewardjbe32e452002-04-24 20:29:58 +00001667
sewardj436c2db2002-06-18 09:07:54 +00001668extern void __libc_siglongjmp (sigjmp_buf env, int val)
1669 __attribute__ ((noreturn));
1670void siglongjmp(sigjmp_buf env, int val)
1671{
1672 kludged("siglongjmp (cleanup handlers are ignored)");
1673 __libc_siglongjmp(env, val);
1674}
1675
1676
sewardj6af4b5d2002-04-16 04:40:49 +00001677extern
1678int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001679__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001680int send(int s, const void *msg, size_t len, int flags)
1681{
sewardjd140e442002-05-29 01:21:19 +00001682 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001683 return __libc_send(s, msg, len, flags);
1684}
1685
sewardjbe32e452002-04-24 20:29:58 +00001686
sewardj1e8cdc92002-04-18 11:37:52 +00001687extern
1688int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001689__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001690int recv(int s, void *buf, size_t len, int flags)
1691{
sewardjd140e442002-05-29 01:21:19 +00001692 __my_pthread_testcancel();
sewardj1d6b3a22002-06-20 07:58:33 +00001693 wait_for_fd_to_be_readable_or_erring(s);
1694 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001695 return __libc_recv(s, buf, len, flags);
1696}
1697
sewardjbe32e452002-04-24 20:29:58 +00001698
sewardj3665ded2002-05-16 16:57:25 +00001699extern
1700int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1701__attribute__((weak))
1702int sendmsg(int s, const struct msghdr *msg, int flags)
1703{
sewardjd140e442002-05-29 01:21:19 +00001704 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001705 return __libc_sendmsg(s, msg, flags);
1706}
1707
1708
sewardj796d6a22002-04-24 02:28:34 +00001709extern
sewardj59da27a2002-06-06 08:33:54 +00001710int __libc_recvmsg(int s, struct msghdr *msg, int flags);
1711__attribute__((weak))
1712int recvmsg(int s, struct msghdr *msg, int flags)
1713{
1714 __my_pthread_testcancel();
1715 return __libc_recvmsg(s, msg, flags);
1716}
1717
1718
1719extern
sewardj436e0582002-04-26 14:31:40 +00001720int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1721 struct sockaddr *from, socklen_t *fromlen);
1722__attribute__((weak))
1723int recvfrom(int s, void *buf, size_t len, int flags,
1724 struct sockaddr *from, socklen_t *fromlen)
1725{
sewardjd140e442002-05-29 01:21:19 +00001726 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00001727 wait_for_fd_to_be_readable_or_erring(s);
1728 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001729 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1730}
1731
1732
1733extern
sewardj796d6a22002-04-24 02:28:34 +00001734int __libc_sendto(int s, const void *msg, size_t len, int flags,
1735 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001736__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001737int sendto(int s, const void *msg, size_t len, int flags,
1738 const struct sockaddr *to, socklen_t tolen)
1739{
sewardjd140e442002-05-29 01:21:19 +00001740 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001741 return __libc_sendto(s, msg, len, flags, to, tolen);
1742}
1743
sewardjbe32e452002-04-24 20:29:58 +00001744
sewardj369b1702002-04-24 13:28:15 +00001745extern
1746int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001747__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001748int system(const char* str)
1749{
sewardjd140e442002-05-29 01:21:19 +00001750 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001751 return __libc_system(str);
1752}
1753
sewardjbe32e452002-04-24 20:29:58 +00001754
sewardjab0b1c32002-04-24 19:26:47 +00001755extern
1756pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001757__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001758pid_t wait(int *status)
1759{
sewardjd140e442002-05-29 01:21:19 +00001760 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00001761 return __libc_wait(status);
1762}
1763
sewardj45b4b372002-04-16 22:50:32 +00001764
sewardj67f1d582002-05-24 02:11:32 +00001765extern
1766int __libc_msync(const void *start, size_t length, int flags);
1767__attribute__((weak))
1768int msync(const void *start, size_t length, int flags)
1769{
sewardjd140e442002-05-29 01:21:19 +00001770 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00001771 return __libc_msync(start, length, flags);
1772}
1773
sewardj5905fae2002-04-26 13:25:00 +00001774
sewardj3b13f0e2002-04-25 20:17:29 +00001775/* ---------------------------------------------------------------------
1776 Nonblocking implementations of select() and poll(). This stuff will
1777 surely rot your mind.
1778 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001779
sewardj08a4c3f2002-04-13 03:45:44 +00001780/*--------------------------------------------------*/
1781
1782#include "vg_kerneliface.h"
1783
1784static
1785__inline__
1786int is_kerror ( int res )
1787{
1788 if (res >= -4095 && res <= -1)
1789 return 1;
1790 else
1791 return 0;
1792}
1793
1794
1795static
1796int my_do_syscall1 ( int syscallno, int arg1 )
1797{
1798 int __res;
1799 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1800 : "=a" (__res)
1801 : "0" (syscallno),
1802 "d" (arg1) );
1803 return __res;
1804}
1805
1806static
1807int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001808 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001809{
1810 int __res;
1811 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1812 : "=a" (__res)
1813 : "0" (syscallno),
1814 "d" (arg1),
1815 "c" (arg2) );
1816 return __res;
1817}
1818
1819static
sewardjf854f472002-04-21 12:19:41 +00001820int my_do_syscall3 ( int syscallno,
1821 int arg1, int arg2, int arg3 )
1822{
1823 int __res;
1824 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1825 : "=a" (__res)
1826 : "0" (syscallno),
1827 "S" (arg1),
1828 "c" (arg2),
1829 "d" (arg3) );
1830 return __res;
1831}
1832
1833static
sewardj08a4c3f2002-04-13 03:45:44 +00001834int do_syscall_select( int n,
1835 vki_fd_set* readfds,
1836 vki_fd_set* writefds,
1837 vki_fd_set* exceptfds,
1838 struct vki_timeval * timeout )
1839{
1840 int res;
1841 int args[5];
1842 args[0] = n;
1843 args[1] = (int)readfds;
1844 args[2] = (int)writefds;
1845 args[3] = (int)exceptfds;
1846 args[4] = (int)timeout;
1847 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001848 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001849}
1850
1851
1852/* This is a wrapper round select(), which makes it thread-safe,
1853 meaning that only this thread will block, rather than the entire
1854 process. This wrapper in turn depends on nanosleep() not to block
1855 the entire process, but I think (hope? suspect?) that POSIX
1856 pthreads guarantees that to be the case.
1857
1858 Basic idea is: modify the timeout parameter to select so that it
1859 returns immediately. Poll like this until select returns non-zero,
1860 indicating something interesting happened, or until our time is up.
1861 Space out the polls with nanosleeps of say 20 milliseconds, which
1862 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001863
1864 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00001865 * (checked via my_assert) types fd_set and vki_fd_set are identical.
1866 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00001867 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1868 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001869*/
sewardj08a4c3f2002-04-13 03:45:44 +00001870
sewardj5905fae2002-04-26 13:25:00 +00001871/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001872int select ( int n,
1873 fd_set *rfds,
1874 fd_set *wfds,
1875 fd_set *xfds,
1876 struct timeval *timeout )
1877{
sewardj5f07b662002-04-23 16:52:51 +00001878 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001879 int res;
1880 fd_set rfds_copy;
1881 fd_set wfds_copy;
1882 fd_set xfds_copy;
1883 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001884 struct vki_timeval zero_timeout;
1885 struct vki_timespec nanosleep_interval;
1886
sewardjd140e442002-05-29 01:21:19 +00001887 __my_pthread_testcancel();
1888
sewardj5f07b662002-04-23 16:52:51 +00001889 /* gcc's complains about ms_end being used uninitialised -- classic
1890 case it can't understand, where ms_end is both defined and used
1891 only if timeout != NULL. Hence ... */
1892 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001893
1894 /* We assume that the kernel and libc data layouts are identical
1895 for the following types. These asserts provide a crude
1896 check. */
1897 if (sizeof(fd_set) != sizeof(vki_fd_set)
1898 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1899 barf("valgrind's hacky non-blocking select(): data sizes error");
1900
sewardj5f07b662002-04-23 16:52:51 +00001901 /* Detect the current time and simultaneously find out if we are
1902 running on Valgrind. */
1903 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1904 VG_USERREQ__READ_MILLISECOND_TIMER,
1905 0, 0, 0, 0);
1906
1907 /* If a zero timeout specified, this call is harmless. Also go
1908 this route if we're not running on Valgrind, for whatever
1909 reason. */
1910 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1911 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001912 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001913 (vki_fd_set*)wfds,
1914 (vki_fd_set*)xfds,
1915 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001916 if (is_kerror(res)) {
1917 * (__errno_location()) = -res;
1918 return -1;
1919 } else {
1920 return res;
1921 }
1922 }
sewardj08a4c3f2002-04-13 03:45:44 +00001923
sewardj5f07b662002-04-23 16:52:51 +00001924 /* If a timeout was specified, set ms_end to be the end millisecond
1925 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001926 if (timeout) {
1927 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00001928 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001929 ms_end = ms_now;
1930 ms_end += (timeout->tv_usec / 1000);
1931 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001932 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00001933 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001934 }
1935
1936 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1937
1938 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001939 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001940 while (1) {
1941 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +00001942 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1943 VG_USERREQ__READ_MILLISECOND_TIMER,
1944 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001945 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00001946 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +00001947 /* timeout; nothing interesting happened. */
1948 if (rfds) FD_ZERO(rfds);
1949 if (wfds) FD_ZERO(wfds);
1950 if (xfds) FD_ZERO(xfds);
1951 return 0;
1952 }
1953 }
1954
1955 /* These could be trashed each time round the loop, so restore
1956 them each time. */
1957 if (rfds) rfds_copy = *rfds;
1958 if (wfds) wfds_copy = *wfds;
1959 if (xfds) xfds_copy = *xfds;
1960
1961 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1962
1963 res = do_syscall_select( n,
1964 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1965 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1966 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1967 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001968 if (is_kerror(res)) {
1969 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001970 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001971 * (__errno_location()) = -res;
1972 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001973 }
1974 if (res > 0) {
1975 /* one or more fds is ready. Copy out resulting sets and
1976 return. */
1977 if (rfds) *rfds = rfds_copy;
1978 if (wfds) *wfds = wfds_copy;
1979 if (xfds) *xfds = xfds_copy;
1980 return res;
1981 }
1982 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1983 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001984 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001985 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001986 /* It's critical here that valgrind's nanosleep implementation
1987 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00001988 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00001989 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00001990 if (res == -VKI_EINTR) {
1991 /* The nanosleep was interrupted by a signal. So we do the
1992 same. */
1993 * (__errno_location()) = EINTR;
1994 return -1;
1995 }
sewardjf854f472002-04-21 12:19:41 +00001996 }
1997}
1998
1999
2000
2001
2002#include <sys/poll.h>
2003
sewardj3e909ce2002-06-03 13:27:15 +00002004#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00002005typedef unsigned long int nfds_t;
2006#endif
2007
sewardj705d3cb2002-05-23 13:13:12 +00002008
sewardj5905fae2002-04-26 13:25:00 +00002009/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00002010int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2011{
sewardj5f07b662002-04-23 16:52:51 +00002012 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00002013 int res, i;
sewardjf854f472002-04-21 12:19:41 +00002014 struct vki_timespec nanosleep_interval;
2015
sewardjd140e442002-05-29 01:21:19 +00002016 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00002017 ensure_valgrind("poll");
2018
sewardj5f07b662002-04-23 16:52:51 +00002019 /* Detect the current time and simultaneously find out if we are
2020 running on Valgrind. */
2021 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2022 VG_USERREQ__READ_MILLISECOND_TIMER,
2023 0, 0, 0, 0);
2024
sewardjf854f472002-04-21 12:19:41 +00002025 if (/* CHECK SIZES FOR struct pollfd */
2026 sizeof(struct timeval) != sizeof(struct vki_timeval))
2027 barf("valgrind's hacky non-blocking poll(): data sizes error");
2028
sewardj5f07b662002-04-23 16:52:51 +00002029 /* dummy initialisation to keep gcc -Wall happy */
2030 ms_end = 0;
2031
2032 /* If a zero timeout specified, this call is harmless. Also do
2033 this if not running on Valgrind. */
2034 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00002035 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
2036 if (is_kerror(res)) {
2037 * (__errno_location()) = -res;
2038 return -1;
2039 } else {
2040 return res;
2041 }
2042 }
2043
sewardj5f07b662002-04-23 16:52:51 +00002044 /* If a timeout was specified, set ms_end to be the end wallclock
2045 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002046 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002047 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002048 }
2049
2050 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2051
2052 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2053 in which case t_end holds the end time. */
sewardj2d94c112002-06-03 01:25:54 +00002054 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002055
sewardjf854f472002-04-21 12:19:41 +00002056 while (1) {
sewardjf854f472002-04-21 12:19:41 +00002057 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002058 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2059 VG_USERREQ__READ_MILLISECOND_TIMER,
2060 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002061 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002062 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002063 /* timeout; nothing interesting happened. */
2064 for (i = 0; i < __nfds; i++)
2065 __fds[i].revents = 0;
2066 return 0;
2067 }
2068 }
2069
sewardj5f07b662002-04-23 16:52:51 +00002070 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00002071 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2072 if (is_kerror(res)) {
2073 /* Some kind of error. Set errno and return. */
2074 * (__errno_location()) = -res;
2075 return -1;
2076 }
2077 if (res > 0) {
2078 /* One or more fds is ready. Return now. */
2079 return res;
2080 }
2081 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2082 /* nanosleep and go round again */
2083 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00002084 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00002085 /* It's critical here that valgrind's nanosleep implementation
2086 is nonblocking. */
2087 (void)my_do_syscall2(__NR_nanosleep,
2088 (int)(&nanosleep_interval), (int)NULL);
2089 }
2090}
sewardj3b13f0e2002-04-25 20:17:29 +00002091
2092
sewardj705d3cb2002-05-23 13:13:12 +00002093/* Helper function used to make accept() non-blocking. Idea is to use
2094 the above nonblocking poll() to make this thread ONLY wait for the
2095 specified fd to become ready, and then return. */
2096static void wait_for_fd_to_be_readable_or_erring ( int fd )
2097{
2098 struct pollfd pfd;
sewardj6e6cbaa2002-05-24 02:12:52 +00002099 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardj705d3cb2002-05-23 13:13:12 +00002100 pfd.fd = fd;
2101 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2102 /* ... but not POLLOUT, you may notice. */
2103 pfd.revents = 0;
2104 (void)poll(&pfd, 1, -1 /* forever */);
2105}
2106
2107
sewardj3b13f0e2002-04-25 20:17:29 +00002108/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002109 Hacky implementation of semaphores.
2110 ------------------------------------------------------------------ */
2111
2112#include <semaphore.h>
2113
2114/* This is a terrible way to do the remapping. Plan is to import an
2115 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002116
2117typedef
2118 struct {
2119 pthread_mutex_t se_mx;
2120 pthread_cond_t se_cv;
2121 int count;
2122 }
2123 vg_sem_t;
2124
2125static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2126
2127static int se_remap_used = 0;
2128static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2129static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2130
2131static vg_sem_t* se_remap ( sem_t* orig )
2132{
2133 int res, i;
2134 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002135 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002136
2137 for (i = 0; i < se_remap_used; i++) {
2138 if (se_remap_orig[i] == orig)
2139 break;
2140 }
2141 if (i == se_remap_used) {
2142 if (se_remap_used == VG_N_SEMAPHORES) {
2143 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002144 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002145 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002146 }
2147 se_remap_used++;
2148 se_remap_orig[i] = orig;
2149 /* printf("allocated semaphore %d\n", i); */
2150 }
2151 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002152 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002153 return &se_remap_new[i];
2154}
2155
2156
2157int sem_init(sem_t *sem, int pshared, unsigned int value)
2158{
2159 int res;
2160 vg_sem_t* vg_sem;
2161 ensure_valgrind("sem_init");
2162 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002163 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002164 errno = ENOSYS;
2165 return -1;
2166 }
2167 vg_sem = se_remap(sem);
2168 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002169 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002170 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002171 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002172 vg_sem->count = value;
2173 return 0;
2174}
2175
2176
2177int sem_wait ( sem_t* sem )
2178{
2179 int res;
2180 vg_sem_t* vg_sem;
2181 ensure_valgrind("sem_wait");
2182 vg_sem = se_remap(sem);
2183 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002184 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002185 while (vg_sem->count == 0) {
2186 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002187 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002188 }
2189 vg_sem->count--;
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 0;
2193}
2194
2195int sem_post ( sem_t* sem )
2196{
2197 int res;
2198 vg_sem_t* vg_sem;
2199 ensure_valgrind("sem_post");
2200 vg_sem = se_remap(sem);
2201 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002202 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002203 if (vg_sem->count == 0) {
2204 vg_sem->count++;
2205 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002206 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002207 } else {
2208 vg_sem->count++;
2209 }
2210 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002211 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002212 return 0;
2213}
2214
2215
2216int sem_trywait ( sem_t* sem )
2217{
2218 int ret, res;
2219 vg_sem_t* vg_sem;
2220 ensure_valgrind("sem_trywait");
2221 vg_sem = se_remap(sem);
2222 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002223 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002224 if (vg_sem->count > 0) {
2225 vg_sem->count--;
2226 ret = 0;
2227 } else {
2228 ret = -1;
2229 errno = EAGAIN;
2230 }
2231 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002232 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002233 return ret;
2234}
2235
2236
2237int sem_getvalue(sem_t* sem, int * sval)
2238{
2239 vg_sem_t* vg_sem;
2240 ensure_valgrind("sem_trywait");
2241 vg_sem = se_remap(sem);
2242 *sval = vg_sem->count;
2243 return 0;
2244}
2245
2246
2247int sem_destroy(sem_t * sem)
2248{
2249 kludged("sem_destroy");
2250 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2251 return 0;
2252}
2253
2254
2255/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002256 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002257 ------------------------------------------------------------------ */
2258
sewardj2d8b3f02002-06-01 14:14:19 +00002259typedef
2260 struct {
2261 int initted; /* != 0 --> in use; sanity check only */
2262 int prefer_w; /* != 0 --> prefer writer */
2263 int nwait_r; /* # of waiting readers */
2264 int nwait_w; /* # of waiting writers */
2265 pthread_cond_t cv_r; /* for signalling readers */
2266 pthread_cond_t cv_w; /* for signalling writers */
2267 pthread_mutex_t mx;
2268 int status;
2269 /* allowed range for status: >= -1. -1 means 1 writer currently
2270 active, >= 0 means N readers currently active. */
2271 }
2272 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002273
2274
2275static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2276
2277static int rw_remap_used = 0;
2278static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2279static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2280
sewardj2d8b3f02002-06-01 14:14:19 +00002281
2282static
2283void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2284{
2285 int res = 0;
2286 vg_rwl->initted = 1;
2287 vg_rwl->prefer_w = 1;
2288 vg_rwl->nwait_r = 0;
2289 vg_rwl->nwait_w = 0;
2290 vg_rwl->status = 0;
2291 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2292 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2293 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002294 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002295}
2296
2297
sewardja1ac5cb2002-05-27 13:00:05 +00002298/* Take the address of a LinuxThreads rwlock_t and return the shadow
2299 address of our version. Further, if the LinuxThreads version
2300 appears to have been statically initialised, do the same to the one
2301 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2302 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2303 uninitialised and non-zero meaning initialised.
2304*/
2305static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2306{
2307 int res, i;
2308 vg_rwlock_t* vg_rwl;
2309 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002310 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002311
2312 for (i = 0; i < rw_remap_used; i++) {
2313 if (rw_remap_orig[i] == orig)
2314 break;
2315 }
2316 if (i == rw_remap_used) {
2317 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002318 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002319 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002320 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2321 }
2322 rw_remap_used++;
2323 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002324 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002325 if (0) printf("allocated rwlock %d\n", i);
2326 }
2327 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002328 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002329 vg_rwl = &rw_remap_new[i];
2330
sewardj2d8b3f02002-06-01 14:14:19 +00002331 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002332 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002333 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002334 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002335 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002336 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002337 }
2338
2339 return vg_rwl;
2340}
2341
2342
sewardja1ac5cb2002-05-27 13:00:05 +00002343int pthread_rwlock_init ( pthread_rwlock_t* orig,
2344 const pthread_rwlockattr_t* attr )
2345{
sewardja1ac5cb2002-05-27 13:00:05 +00002346 vg_rwlock_t* rwl;
2347 if (0) printf ("pthread_rwlock_init\n");
2348 /* Force the remapper to initialise the shadow. */
2349 orig->__rw_readers = 0;
2350 /* Install the lock preference; the remapper needs to know it. */
2351 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2352 if (attr)
2353 orig->__rw_kind = attr->__lockkind;
2354 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002355 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002356}
2357
sewardj2d8b3f02002-06-01 14:14:19 +00002358
2359static
2360void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002361{
sewardj2d8b3f02002-06-01 14:14:19 +00002362 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2363 rwl->nwait_r--;
2364 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002365}
2366
sewardj2d8b3f02002-06-01 14:14:19 +00002367
sewardja1ac5cb2002-05-27 13:00:05 +00002368int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2369{
2370 int res;
2371 vg_rwlock_t* rwl;
2372 if (0) printf ("pthread_rwlock_rdlock\n");
2373 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002374 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002375 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002376 if (!rwl->initted) {
2377 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002378 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002379 return EINVAL;
2380 }
2381 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002382 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002383 rwl->nwait_r++;
2384 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2385 while (1) {
2386 if (rwl->status == 0) break;
2387 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002388 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002389 }
2390 pthread_cleanup_pop(0);
2391 rwl->nwait_r--;
2392 }
sewardj2d94c112002-06-03 01:25:54 +00002393 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002394 rwl->status++;
2395 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002396 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002397 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002398}
2399
sewardj2d8b3f02002-06-01 14:14:19 +00002400
sewardja1ac5cb2002-05-27 13:00:05 +00002401int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2402{
2403 int res;
2404 vg_rwlock_t* rwl;
2405 if (0) printf ("pthread_rwlock_tryrdlock\n");
2406 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002407 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002408 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002409 if (!rwl->initted) {
2410 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002411 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002412 return EINVAL;
2413 }
2414 if (rwl->status == -1) {
2415 /* Writer active; we have to give up. */
2416 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002417 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002418 return EBUSY;
2419 }
2420 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002421 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002422 rwl->status++;
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
2429static
2430void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2431{
2432 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2433 rwl->nwait_w--;
2434 pthread_mutex_unlock (&rwl->mx);
2435}
2436
2437
sewardja1ac5cb2002-05-27 13:00:05 +00002438int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2439{
2440 int res;
2441 vg_rwlock_t* rwl;
2442 if (0) printf ("pthread_rwlock_wrlock\n");
2443 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002444 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002445 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002446 if (!rwl->initted) {
2447 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002448 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002449 return EINVAL;
2450 }
2451 if (rwl->status != 0) {
2452 rwl->nwait_w++;
2453 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2454 while (1) {
2455 if (rwl->status == 0) break;
2456 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002457 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002458 }
2459 pthread_cleanup_pop(0);
2460 rwl->nwait_w--;
2461 }
sewardj2d94c112002-06-03 01:25:54 +00002462 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002463 rwl->status = -1;
2464 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002465 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002466 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002467}
2468
sewardj2d8b3f02002-06-01 14:14:19 +00002469
sewardja1ac5cb2002-05-27 13:00:05 +00002470int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2471{
2472 int res;
2473 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002474 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002475 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002476 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002477 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002478 if (!rwl->initted) {
2479 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002480 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002481 return EINVAL;
2482 }
2483 if (rwl->status != 0) {
2484 /* Reader(s) or a writer active; we have to give up. */
2485 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002486 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002487 return EBUSY;
2488 }
2489 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002490 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002491 rwl->status = -1;
2492 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002493 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002494 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002495}
2496
sewardj2d8b3f02002-06-01 14:14:19 +00002497
sewardja1ac5cb2002-05-27 13:00:05 +00002498int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2499{
2500 int res;
2501 vg_rwlock_t* rwl;
2502 if (0) printf ("pthread_rwlock_unlock\n");
2503 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002504 rwl = rw_remap ( orig );
2505 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002506 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002507 if (!rwl->initted) {
2508 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002509 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002510 return EINVAL;
2511 }
2512 if (rwl->status == 0) {
2513 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002514 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002515 return EPERM;
2516 }
sewardj2d94c112002-06-03 01:25:54 +00002517 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002518 if (rwl->status == -1) {
2519 rwl->status = 0;
2520 } else {
sewardj2d94c112002-06-03 01:25:54 +00002521 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002522 rwl->status--;
2523 }
2524
sewardj2d94c112002-06-03 01:25:54 +00002525 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002526
2527 if (rwl->prefer_w) {
2528
2529 /* Favour waiting writers, if any. */
2530 if (rwl->nwait_w > 0) {
2531 /* Writer(s) are waiting. */
2532 if (rwl->status == 0) {
2533 /* We can let a writer in. */
2534 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002535 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002536 } else {
2537 /* There are still readers active. Do nothing; eventually
2538 they will disappear, at which point a writer will be
2539 admitted. */
2540 }
2541 }
2542 else
2543 /* No waiting writers. */
2544 if (rwl->nwait_r > 0) {
2545 /* Let in a waiting reader. */
2546 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002547 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002548 }
2549
2550 } else {
2551
2552 /* Favour waiting readers, if any. */
2553 if (rwl->nwait_r > 0) {
2554 /* Reader(s) are waiting; let one in. */
2555 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002556 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002557 }
2558 else
2559 /* No waiting readers. */
2560 if (rwl->nwait_w > 0 && rwl->status == 0) {
2561 /* We have waiting writers and no active readers; let a
2562 writer in. */
2563 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002564 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002565 }
2566 }
2567
2568 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002569 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002570 return 0;
2571}
2572
2573
2574int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2575{
2576 int res;
2577 vg_rwlock_t* rwl;
2578 if (0) printf ("pthread_rwlock_destroy\n");
2579 rwl = rw_remap ( orig );
2580 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002581 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002582 if (!rwl->initted) {
2583 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002584 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002585 return EINVAL;
2586 }
2587 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2588 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002589 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002590 return EBUSY;
2591 }
2592 rwl->initted = 0;
2593 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002594 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002595 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002596}
2597
2598
sewardj47e4e312002-06-18 09:24:34 +00002599/* Copied directly from LinuxThreads. */
2600int
2601pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
2602{
2603 attr->__lockkind = 0;
2604 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
2605
2606 return 0;
2607}
2608
2609
sewardja1ac5cb2002-05-27 13:00:05 +00002610/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002611 B'stard.
2612 ------------------------------------------------------------------ */
2613
2614# define strong_alias(name, aliasname) \
2615 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2616
sewardj5905fae2002-04-26 13:25:00 +00002617# define weak_alias(name, aliasname) \
2618 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002619
sewardj5905fae2002-04-26 13:25:00 +00002620strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2621strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2622strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2623strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2624 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2625strong_alias(__pthread_mutex_init, pthread_mutex_init)
2626strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2627strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2628strong_alias(__pthread_once, pthread_once)
2629strong_alias(__pthread_atfork, pthread_atfork)
2630strong_alias(__pthread_key_create, pthread_key_create)
2631strong_alias(__pthread_getspecific, pthread_getspecific)
2632strong_alias(__pthread_setspecific, pthread_setspecific)
2633
sewardjd529a442002-05-04 19:49:21 +00002634#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002635strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002636#endif
2637
sewardj5905fae2002-04-26 13:25:00 +00002638strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002639strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002640strong_alias(lseek, __lseek)
2641strong_alias(open, __open)
2642strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002643strong_alias(read, __read)
2644strong_alias(wait, __wait)
2645strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002646strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002647strong_alias(send, __send)
2648
sewardj726c4122002-05-16 23:39:10 +00002649weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002650weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002651weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002652
sewardjf0b06452002-06-04 08:38:04 +00002653weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00002654
2655/*--------------------------------------------------*/
2656
sewardj5905fae2002-04-26 13:25:00 +00002657weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002658weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002659weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002660
sewardja1ac5cb2002-05-27 13:00:05 +00002661weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2662weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2663weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2664weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2665
sewardj060b04f2002-04-26 21:01:13 +00002666
sewardj3b13f0e2002-04-25 20:17:29 +00002667/* I've no idea what these are, but they get called quite a lot.
2668 Anybody know? */
2669
2670#undef _IO_flockfile
2671void _IO_flockfile ( _IO_FILE * file )
2672{
sewardj853f55d2002-04-26 00:27:53 +00002673 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002674}
sewardj5905fae2002-04-26 13:25:00 +00002675weak_alias(_IO_flockfile, flockfile);
2676
sewardj3b13f0e2002-04-25 20:17:29 +00002677
2678#undef _IO_funlockfile
2679void _IO_funlockfile ( _IO_FILE * file )
2680{
sewardj853f55d2002-04-26 00:27:53 +00002681 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002682}
sewardj5905fae2002-04-26 13:25:00 +00002683weak_alias(_IO_funlockfile, funlockfile);
2684
sewardj3b13f0e2002-04-25 20:17:29 +00002685
sewardjd4f2c712002-04-30 10:20:10 +00002686/* This doesn't seem to be needed to simulate libpthread.so's external
2687 interface, but many people complain about its absence. */
2688
2689strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2690weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002691
2692
2693/*--------------------------------------------------------------------*/
2694/*--- end vg_libpthread.c ---*/
2695/*--------------------------------------------------------------------*/