blob: cca2d887c94f861ae49aed0ca094012677c7e4fa [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
sewardj728a5272002-06-20 10:25:37 +0000475/* Struct used to convey info from pthread_create to thread_wrapper.
476 Must be careful not to pass to the child thread any pointers to
477 objects which might be on the parent's stack. */
sewardj20917d82002-05-28 01:36:45 +0000478typedef
479 struct {
sewardj728a5272002-06-20 10:25:37 +0000480 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000481 void* (*root_fn) ( void* );
482 void* arg;
483 }
484 NewThreadInfo;
485
486
487/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
488 not return. Note that this runs in the new thread, not the
489 parent. */
490static
491__attribute__((noreturn))
492void thread_wrapper ( NewThreadInfo* info )
493{
sewardj728a5272002-06-20 10:25:37 +0000494 int res;
495 int attr__detachstate;
sewardj20917d82002-05-28 01:36:45 +0000496 void* (*root_fn) ( void* );
497 void* arg;
498 void* ret_val;
499
sewardj728a5272002-06-20 10:25:37 +0000500 attr__detachstate = info->attr__detachstate;
501 root_fn = info->root_fn;
502 arg = info->arg;
sewardj20917d82002-05-28 01:36:45 +0000503
sewardj20917d82002-05-28 01:36:45 +0000504 /* Free up the arg block that pthread_create malloced. */
505 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
506 VG_USERREQ__FREE, info, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000507 my_assert(res == 0);
sewardj20917d82002-05-28 01:36:45 +0000508
sewardj7989d0c2002-05-28 11:00:01 +0000509 /* Minimally observe the attributes supplied. */
sewardj728a5272002-06-20 10:25:37 +0000510 if (attr__detachstate != PTHREAD_CREATE_DETACHED
511 && attr__detachstate != PTHREAD_CREATE_JOINABLE)
512 pthread_error("thread_wrapper: invalid attr->__detachstate");
513 if (attr__detachstate == PTHREAD_CREATE_DETACHED)
514 pthread_detach(pthread_self());
sewardj7989d0c2002-05-28 11:00:01 +0000515
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
sewardj728a5272002-06-20 10:25:37 +0000567 if (__attr)
568 info->attr__detachstate = __attr->__detachstate;
569 else
570 info->attr__detachstate = PTHREAD_CREATE_JOINABLE;
571
sewardj20917d82002-05-28 01:36:45 +0000572 info->root_fn = __start_routine;
573 info->arg = __arg;
574 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
575 VG_USERREQ__APPLY_IN_NEW_THREAD,
576 &thread_wrapper, info, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000577 my_assert(tid_child != VG_INVALID_THREADID);
sewardj20917d82002-05-28 01:36:45 +0000578
579 if (__thread)
580 *__thread = tid_child;
581 return 0; /* success */
582}
sewardje663cb92002-04-12 10:26:32 +0000583
584
585int
586pthread_join (pthread_t __th, void **__thread_return)
587{
588 int res;
589 ensure_valgrind("pthread_join");
590 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
591 VG_USERREQ__PTHREAD_JOIN,
592 __th, __thread_return, 0, 0);
593 return res;
594}
595
596
sewardj3b5d8862002-04-20 13:53:23 +0000597void pthread_exit(void *retval)
598{
sewardj3b5d8862002-04-20 13:53:23 +0000599 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000600 /* Simple! */
601 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000602}
603
sewardje663cb92002-04-12 10:26:32 +0000604
sewardj3b13f0e2002-04-25 20:17:29 +0000605pthread_t pthread_self(void)
sewardje663cb92002-04-12 10:26:32 +0000606{
607 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000608 ensure_valgrind("pthread_self");
sewardj439d45e2002-05-03 20:43:10 +0000609 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardje663cb92002-04-12 10:26:32 +0000610 VG_USERREQ__PTHREAD_GET_THREADID,
611 0, 0, 0, 0);
sewardj439d45e2002-05-03 20:43:10 +0000612 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000613 barf("pthread_self: invalid ThreadId");
614 return tid;
sewardje663cb92002-04-12 10:26:32 +0000615}
616
617
sewardj853f55d2002-04-26 00:27:53 +0000618int pthread_detach(pthread_t th)
619{
sewardj20917d82002-05-28 01:36:45 +0000620 int res;
621 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000622 /* First we enquire as to the current detach state. */
623 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000624 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000625 2 /* get */, th, 0, 0);
sewardj4dced352002-06-04 22:54:20 +0000626 if (res == -1) {
627 /* not found */
628 pthread_error("pthread_detach: "
629 "invalid target thread");
sewardj7989d0c2002-05-28 11:00:01 +0000630 return ESRCH;
sewardj4dced352002-06-04 22:54:20 +0000631 }
632 if (res == 1) {
633 /* already detached */
634 pthread_error("pthread_detach: "
635 "target thread is already detached");
sewardj7989d0c2002-05-28 11:00:01 +0000636 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000637 }
sewardj7989d0c2002-05-28 11:00:01 +0000638 if (res == 0) {
639 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
640 VG_USERREQ__SET_OR_GET_DETACH,
641 1 /* set */, th, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000642 my_assert(res == 0);
sewardj7989d0c2002-05-28 11:00:01 +0000643 return 0;
644 }
645 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000646}
647
648
sewardjf8f819e2002-04-17 23:21:37 +0000649/* ---------------------------------------------------
sewardj8ad94e12002-05-29 00:10:20 +0000650 CLEANUP STACKS
651 ------------------------------------------------ */
652
653void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
654 void (*__routine) (void *),
655 void *__arg)
656{
657 int res;
658 CleanupEntry cu;
659 ensure_valgrind("_pthread_cleanup_push");
660 cu.fn = __routine;
661 cu.arg = __arg;
662 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
663 VG_USERREQ__CLEANUP_PUSH,
664 &cu, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000665 my_assert(res == 0);
sewardj8ad94e12002-05-29 00:10:20 +0000666}
667
668
669void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
670 void (*__routine) (void *),
671 void *__arg)
672{
673 /* As _pthread_cleanup_push, but first save the thread's original
674 cancellation type in __buffer and set it to Deferred. */
675 int orig_ctype;
676 ensure_valgrind("_pthread_cleanup_push_defer");
677 /* Set to Deferred, and put the old cancellation type in res. */
sewardj2d94c112002-06-03 01:25:54 +0000678 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
679 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
680 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000681 VALGRIND_MAGIC_SEQUENCE(orig_ctype, (-1) /* default */,
682 VG_USERREQ__SET_CANCELTYPE,
683 PTHREAD_CANCEL_DEFERRED, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000684 my_assert(orig_ctype != -1);
sewardj8ad94e12002-05-29 00:10:20 +0000685 *((int*)(__buffer)) = orig_ctype;
686 /* Now push the cleanup. */
687 _pthread_cleanup_push(NULL, __routine, __arg);
688}
689
690
691void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
692 int __execute)
693{
694 int res;
695 CleanupEntry cu;
696 ensure_valgrind("_pthread_cleanup_push");
697 cu.fn = cu.arg = NULL; /* paranoia */
698 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
699 VG_USERREQ__CLEANUP_POP,
700 &cu, 0, 0, 0);
701 if (res == 0) {
702 /* pop succeeded */
703 if (__execute) {
704 cu.fn ( cu.arg );
705 }
706 return;
707 }
708 if (res == -1) {
709 /* stack underflow */
710 return;
711 }
712 barf("_pthread_cleanup_pop");
713}
714
715
716void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
717 int __execute)
718{
719 int orig_ctype, fake_ctype;
720 /* As _pthread_cleanup_pop, but after popping/running the handler,
721 restore the thread's original cancellation type from the first
722 word of __buffer. */
723 _pthread_cleanup_pop(NULL, __execute);
724 orig_ctype = *((int*)(__buffer));
sewardj2d94c112002-06-03 01:25:54 +0000725 my_assert(orig_ctype == PTHREAD_CANCEL_DEFERRED
sewardj8ad94e12002-05-29 00:10:20 +0000726 || orig_ctype == PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj2d94c112002-06-03 01:25:54 +0000727 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
728 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
729 my_assert(sizeof(struct _pthread_cleanup_buffer) >= sizeof(int));
sewardj8ad94e12002-05-29 00:10:20 +0000730 VALGRIND_MAGIC_SEQUENCE(fake_ctype, (-1) /* default */,
731 VG_USERREQ__SET_CANCELTYPE,
732 orig_ctype, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000733 my_assert(fake_ctype == PTHREAD_CANCEL_DEFERRED);
sewardj8ad94e12002-05-29 00:10:20 +0000734}
735
736
737/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000738 MUTEX ATTRIBUTES
739 ------------------------------------------------ */
740
sewardj5905fae2002-04-26 13:25:00 +0000741int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000742{
sewardjf8f819e2002-04-17 23:21:37 +0000743 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000744 return 0;
sewardje663cb92002-04-12 10:26:32 +0000745}
746
sewardj5905fae2002-04-26 13:25:00 +0000747int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000748{
749 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000750# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000751 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000752 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000753# endif
sewardja1679dd2002-05-10 22:31:40 +0000754# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000755 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000756# endif
sewardjf8f819e2002-04-17 23:21:37 +0000757 case PTHREAD_MUTEX_RECURSIVE_NP:
758 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000759 attr->__mutexkind = type;
760 return 0;
761 default:
sewardj4dced352002-06-04 22:54:20 +0000762 pthread_error("pthread_mutexattr_settype: "
763 "invalid type");
sewardjf8f819e2002-04-17 23:21:37 +0000764 return EINVAL;
765 }
766}
767
sewardj5905fae2002-04-26 13:25:00 +0000768int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000769{
770 return 0;
771}
772
773
774/* ---------------------------------------------------
775 MUTEXes
776 ------------------------------------------------ */
777
sewardj5905fae2002-04-26 13:25:00 +0000778int __pthread_mutex_init(pthread_mutex_t *mutex,
779 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000780{
sewardj604ec3c2002-04-18 22:38:41 +0000781 mutex->__m_count = 0;
782 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
783 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
784 if (mutexattr)
785 mutex->__m_kind = mutexattr->__mutexkind;
786 return 0;
sewardje663cb92002-04-12 10:26:32 +0000787}
788
sewardj439d45e2002-05-03 20:43:10 +0000789
sewardj5905fae2002-04-26 13:25:00 +0000790int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000791{
792 int res;
sewardj436e0582002-04-26 14:31:40 +0000793 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000794 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000795 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
796 VG_USERREQ__PTHREAD_MUTEX_LOCK,
797 mutex, 0, 0, 0);
798 return res;
sewardj439d45e2002-05-03 20:43:10 +0000799 } else {
800 if (moans-- > 0)
801 not_inside("pthread_mutex_lock");
802 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000803 }
804}
805
sewardj439d45e2002-05-03 20:43:10 +0000806
sewardj5905fae2002-04-26 13:25:00 +0000807int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000808{
809 int res;
sewardj436e0582002-04-26 14:31:40 +0000810 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000811 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000812 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
813 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
814 mutex, 0, 0, 0);
815 return res;
sewardj439d45e2002-05-03 20:43:10 +0000816 } else {
817 if (moans-- > 0)
818 not_inside("pthread_mutex_trylock");
819 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000820 }
821}
822
sewardj439d45e2002-05-03 20:43:10 +0000823
sewardj5905fae2002-04-26 13:25:00 +0000824int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000825{
826 int res;
sewardj436e0582002-04-26 14:31:40 +0000827 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000828 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000829 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
830 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
831 mutex, 0, 0, 0);
832 return res;
sewardj439d45e2002-05-03 20:43:10 +0000833 } else {
834 if (moans-- > 0)
835 not_inside("pthread_mutex_unlock");
836 return 0;
sewardje663cb92002-04-12 10:26:32 +0000837 }
838}
839
sewardj439d45e2002-05-03 20:43:10 +0000840
sewardj5905fae2002-04-26 13:25:00 +0000841int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000842{
sewardj604ec3c2002-04-18 22:38:41 +0000843 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
844 need to involve it. */
sewardj4dced352002-06-04 22:54:20 +0000845 if (mutex->__m_count > 0) {
846 pthread_error("pthread_mutex_destroy: "
847 "mutex is still in use");
sewardj604ec3c2002-04-18 22:38:41 +0000848 return EBUSY;
sewardj4dced352002-06-04 22:54:20 +0000849 }
850 mutex->__m_count = 0;
851 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
852 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
853 return 0;
sewardje663cb92002-04-12 10:26:32 +0000854}
855
856
sewardjf8f819e2002-04-17 23:21:37 +0000857/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000858 CONDITION VARIABLES
859 ------------------------------------------------ */
860
861/* LinuxThreads supports no attributes for conditions. Hence ... */
862
863int pthread_condattr_init(pthread_condattr_t *attr)
864{
865 return 0;
866}
867
sewardj0738a592002-04-20 13:59:33 +0000868int pthread_condattr_destroy(pthread_condattr_t *attr)
869{
870 return 0;
871}
sewardj6072c362002-04-19 14:40:57 +0000872
873int pthread_cond_init( pthread_cond_t *cond,
874 const pthread_condattr_t *cond_attr)
875{
876 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
877 return 0;
878}
879
sewardjf854f472002-04-21 12:19:41 +0000880int pthread_cond_destroy(pthread_cond_t *cond)
881{
882 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000883 static int moans = N_MOANS;
884 if (moans-- > 0)
885 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000886 return 0;
887}
sewardj6072c362002-04-19 14:40:57 +0000888
889/* ---------------------------------------------------
890 SCHEDULING
891 ------------------------------------------------ */
892
893/* This is completely bogus. */
894int pthread_getschedparam(pthread_t target_thread,
895 int *policy,
896 struct sched_param *param)
897{
sewardj436e0582002-04-26 14:31:40 +0000898 static int moans = N_MOANS;
899 if (moans-- > 0)
900 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000901 if (policy) *policy = SCHED_OTHER;
sewardj3e909ce2002-06-03 13:27:15 +0000902# ifdef HAVE_SCHED_PRIORITY
sewardj2a1dcce2002-04-22 12:45:25 +0000903 if (param) param->sched_priority = 0; /* who knows */
904# else
sewardj6072c362002-04-19 14:40:57 +0000905 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000906# endif
sewardj6072c362002-04-19 14:40:57 +0000907 return 0;
908}
909
910int pthread_setschedparam(pthread_t target_thread,
911 int policy,
912 const struct sched_param *param)
913{
sewardj436e0582002-04-26 14:31:40 +0000914 static int moans = N_MOANS;
915 if (moans-- > 0)
916 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000917 return 0;
918}
919
sewardj3b5d8862002-04-20 13:53:23 +0000920int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
921{
922 int res;
923 ensure_valgrind("pthread_cond_wait");
924 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
925 VG_USERREQ__PTHREAD_COND_WAIT,
926 cond, mutex, 0, 0);
927 return res;
928}
929
sewardj5f07b662002-04-23 16:52:51 +0000930int pthread_cond_timedwait ( pthread_cond_t *cond,
931 pthread_mutex_t *mutex,
932 const struct timespec *abstime )
933{
934 int res;
935 unsigned int ms_now, ms_end;
936 struct timeval timeval_now;
937 unsigned long long int ull_ms_now_after_1970;
938 unsigned long long int ull_ms_end_after_1970;
939
940 ensure_valgrind("pthread_cond_timedwait");
941 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
942 VG_USERREQ__READ_MILLISECOND_TIMER,
943 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +0000944 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +0000945 res = gettimeofday(&timeval_now, NULL);
sewardj2d94c112002-06-03 01:25:54 +0000946 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +0000947
948 ull_ms_now_after_1970
949 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
950 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
951 ull_ms_end_after_1970
952 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
953 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
sewardjd8e919e2002-05-29 20:13:53 +0000954 if (ull_ms_end_after_1970 < ull_ms_now_after_1970)
955 ull_ms_end_after_1970 = ull_ms_now_after_1970;
sewardj5f07b662002-04-23 16:52:51 +0000956 ms_end
957 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
958 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
959 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
960 cond, mutex, ms_end, 0);
961 return res;
962}
963
964
sewardj3b5d8862002-04-20 13:53:23 +0000965int pthread_cond_signal(pthread_cond_t *cond)
966{
967 int res;
968 ensure_valgrind("pthread_cond_signal");
969 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
970 VG_USERREQ__PTHREAD_COND_SIGNAL,
971 cond, 0, 0, 0);
972 return res;
973}
974
975int pthread_cond_broadcast(pthread_cond_t *cond)
976{
977 int res;
978 ensure_valgrind("pthread_cond_broadcast");
979 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
980 VG_USERREQ__PTHREAD_COND_BROADCAST,
981 cond, 0, 0, 0);
982 return res;
983}
984
sewardj6072c362002-04-19 14:40:57 +0000985
986/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000987 CANCELLATION
988 ------------------------------------------------ */
989
sewardj853f55d2002-04-26 00:27:53 +0000990int pthread_setcancelstate(int state, int *oldstate)
991{
sewardj20917d82002-05-28 01:36:45 +0000992 int res;
993 ensure_valgrind("pthread_setcancelstate");
994 if (state != PTHREAD_CANCEL_ENABLE
sewardj4dced352002-06-04 22:54:20 +0000995 && state != PTHREAD_CANCEL_DISABLE) {
996 pthread_error("pthread_setcancelstate: "
997 "invalid state");
sewardj20917d82002-05-28 01:36:45 +0000998 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +0000999 }
sewardj2d94c112002-06-03 01:25:54 +00001000 my_assert(-1 != PTHREAD_CANCEL_ENABLE);
1001 my_assert(-1 != PTHREAD_CANCEL_DISABLE);
sewardj20917d82002-05-28 01:36:45 +00001002 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1003 VG_USERREQ__SET_CANCELSTATE,
1004 state, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001005 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001006 if (oldstate)
1007 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +00001008 return 0;
1009}
1010
sewardje663cb92002-04-12 10:26:32 +00001011int pthread_setcanceltype(int type, int *oldtype)
1012{
sewardj20917d82002-05-28 01:36:45 +00001013 int res;
1014 ensure_valgrind("pthread_setcanceltype");
1015 if (type != PTHREAD_CANCEL_DEFERRED
sewardj4dced352002-06-04 22:54:20 +00001016 && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
1017 pthread_error("pthread_setcanceltype: "
1018 "invalid type");
sewardj20917d82002-05-28 01:36:45 +00001019 return EINVAL;
sewardj4dced352002-06-04 22:54:20 +00001020 }
sewardj2d94c112002-06-03 01:25:54 +00001021 my_assert(-1 != PTHREAD_CANCEL_DEFERRED);
1022 my_assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
sewardj20917d82002-05-28 01:36:45 +00001023 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1024 VG_USERREQ__SET_CANCELTYPE,
1025 type, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001026 my_assert(res != -1);
sewardj20917d82002-05-28 01:36:45 +00001027 if (oldtype)
1028 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +00001029 return 0;
1030}
1031
sewardje663cb92002-04-12 10:26:32 +00001032int pthread_cancel(pthread_t thread)
1033{
1034 int res;
1035 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +00001036 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1037 VG_USERREQ__SET_CANCELPEND,
1038 thread, &thread_exit_wrapper, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001039 my_assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +00001040 return res;
1041}
1042
sewardjd140e442002-05-29 01:21:19 +00001043static __inline__
1044void __my_pthread_testcancel(void)
sewardj853f55d2002-04-26 00:27:53 +00001045{
sewardj20917d82002-05-28 01:36:45 +00001046 int res;
1047 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1048 VG_USERREQ__TESTCANCEL,
1049 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001050 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001051}
1052
sewardjd140e442002-05-29 01:21:19 +00001053void pthread_testcancel ( void )
1054{
1055 __my_pthread_testcancel();
1056}
1057
sewardj20917d82002-05-28 01:36:45 +00001058
sewardjef037c72002-05-30 00:40:03 +00001059/* Not really sure what this is for. I suspect for doing the POSIX
1060 requirements for fork() and exec(). We do this internally anyway
1061 whenever those syscalls are observed, so this could be superfluous,
1062 but hey ...
1063*/
sewardj853f55d2002-04-26 00:27:53 +00001064void __pthread_kill_other_threads_np ( void )
1065{
sewardjef037c72002-05-30 00:40:03 +00001066 int res;
1067 ensure_valgrind("__pthread_kill_other_threads_np");
1068 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
1069 VG_USERREQ__NUKE_OTHER_THREADS,
1070 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00001071 my_assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +00001072}
1073
sewardje663cb92002-04-12 10:26:32 +00001074
sewardjf8f819e2002-04-17 23:21:37 +00001075/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +00001076 SIGNALS
1077 ------------------------------------------------ */
1078
1079#include <signal.h>
1080
1081int pthread_sigmask(int how, const sigset_t *newmask,
1082 sigset_t *oldmask)
1083{
1084 int res;
1085
1086 /* A bit subtle, because the scheduler expects newmask and oldmask
1087 to be vki_sigset_t* rather than sigset_t*, and the two are
1088 different. Fortunately the first 64 bits of a sigset_t are
1089 exactly a vki_sigset_t, so we just pass the pointers through
1090 unmodified. Haaaack!
1091
1092 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +00001093 constants to VKI_ constants, so that the former do not have to
1094 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +00001095
1096 ensure_valgrind("pthread_sigmask");
1097
1098 switch (how) {
sewardj018f7622002-05-15 21:13:39 +00001099 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
1100 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
1101 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardj4dced352002-06-04 22:54:20 +00001102 default: pthread_error("pthread_sigmask: invalid how");
1103 return EINVAL;
sewardjb48e5002002-05-13 00:16:03 +00001104 }
1105
1106 /* Crude check */
1107 if (newmask == NULL)
1108 return EFAULT;
1109
1110 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1111 VG_USERREQ__PTHREAD_SIGMASK,
1112 how, newmask, oldmask, 0);
1113
1114 /* The scheduler tells us of any memory violations. */
1115 return res == 0 ? 0 : EFAULT;
1116}
1117
1118
1119int sigwait ( const sigset_t* set, int* sig )
1120{
1121 int res;
1122 ensure_valgrind("sigwait");
1123 /* As with pthread_sigmask we deliberately confuse sigset_t with
1124 vki_ksigset_t. */
1125 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1126 VG_USERREQ__SIGWAIT,
1127 set, sig, 0, 0);
1128 return res;
1129}
1130
1131
sewardj018f7622002-05-15 21:13:39 +00001132int pthread_kill(pthread_t thread, int signo)
1133{
1134 int res;
1135 ensure_valgrind("pthread_kill");
1136 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1137 VG_USERREQ__PTHREAD_KILL,
1138 thread, signo, 0, 0);
1139 return res;
1140}
1141
1142
sewardj3665ded2002-05-16 16:57:25 +00001143/* Copied verbatim from Linuxthreads */
1144/* Redefine raise() to send signal to calling thread only,
1145 as per POSIX 1003.1c */
1146int raise (int sig)
1147{
1148 int retcode = pthread_kill(pthread_self(), sig);
sewardj4dced352002-06-04 22:54:20 +00001149 if (retcode == 0) {
sewardj3665ded2002-05-16 16:57:25 +00001150 return 0;
sewardj4dced352002-06-04 22:54:20 +00001151 } else {
sewardj3665ded2002-05-16 16:57:25 +00001152 errno = retcode;
1153 return -1;
1154 }
1155}
1156
1157
sewardj9a2224b2002-06-19 10:17:40 +00001158int pause ( void )
1159{
1160 unsigned int n_orig, n_now;
1161 struct vki_timespec nanosleep_interval;
1162 ensure_valgrind("pause");
1163
1164 /* This is surely a cancellation point. */
1165 __my_pthread_testcancel();
1166
1167 VALGRIND_MAGIC_SEQUENCE(n_orig, 0xFFFFFFFF /* default */,
1168 VG_USERREQ__GET_N_SIGS_RETURNED,
1169 0, 0, 0, 0);
1170 my_assert(n_orig != 0xFFFFFFFF);
1171
1172 while (1) {
1173 VALGRIND_MAGIC_SEQUENCE(n_now, 0xFFFFFFFF /* default */,
1174 VG_USERREQ__GET_N_SIGS_RETURNED,
1175 0, 0, 0, 0);
1176 my_assert(n_now != 0xFFFFFFFF);
1177 my_assert(n_now >= n_orig);
1178 if (n_now != n_orig) break;
1179
1180 nanosleep_interval.tv_sec = 0;
1181 nanosleep_interval.tv_nsec = 52 * 1000 * 1000; /* 52 milliseconds */
1182 /* It's critical here that valgrind's nanosleep implementation
1183 is nonblocking. */
1184 (void)my_do_syscall2(__NR_nanosleep,
1185 (int)(&nanosleep_interval), (int)NULL);
1186 }
1187
1188 * (__errno_location()) = EINTR;
1189 return -1;
1190}
1191
1192
sewardjb48e5002002-05-13 00:16:03 +00001193/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +00001194 THREAD-SPECIFICs
1195 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +00001196
sewardj5905fae2002-04-26 13:25:00 +00001197int __pthread_key_create(pthread_key_t *key,
1198 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +00001199{
sewardj5f07b662002-04-23 16:52:51 +00001200 int res;
1201 ensure_valgrind("pthread_key_create");
1202 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1203 VG_USERREQ__PTHREAD_KEY_CREATE,
1204 key, destr_function, 0, 0);
1205 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001206}
1207
1208int pthread_key_delete(pthread_key_t key)
1209{
sewardj436e0582002-04-26 14:31:40 +00001210 static int moans = N_MOANS;
1211 if (moans-- > 0)
1212 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +00001213 return 0;
1214}
1215
sewardj5905fae2002-04-26 13:25:00 +00001216int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +00001217{
sewardj5f07b662002-04-23 16:52:51 +00001218 int res;
1219 ensure_valgrind("pthread_setspecific");
1220 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1221 VG_USERREQ__PTHREAD_SETSPECIFIC,
1222 key, pointer, 0, 0);
1223 return res;
sewardj5e5fa512002-04-14 13:13:05 +00001224}
1225
sewardj5905fae2002-04-26 13:25:00 +00001226void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +00001227{
sewardj5f07b662002-04-23 16:52:51 +00001228 int res;
1229 ensure_valgrind("pthread_getspecific");
1230 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
1231 VG_USERREQ__PTHREAD_GETSPECIFIC,
1232 key, 0 , 0, 0);
1233 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +00001234}
1235
sewardjf8f819e2002-04-17 23:21:37 +00001236
1237/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +00001238 ONCEry
1239 ------------------------------------------------ */
1240
1241static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
1242
1243
sewardj5905fae2002-04-26 13:25:00 +00001244int __pthread_once ( pthread_once_t *once_control,
1245 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +00001246{
1247 int res;
1248 ensure_valgrind("pthread_once");
1249
sewardj68b2dd92002-05-10 21:03:56 +00001250 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001251
sewardj68b2dd92002-05-10 21:03:56 +00001252 if (res != 0) {
sewardj89d3d852002-04-24 19:21:39 +00001253 barf("pthread_once: Looks like your program's "
1254 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +00001255 }
sewardj89d3d852002-04-24 19:21:39 +00001256
1257 if (*once_control == 0) {
1258 *once_control = 1;
1259 init_routine();
1260 }
1261
sewardj68b2dd92002-05-10 21:03:56 +00001262 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +00001263
1264 return 0;
1265}
1266
1267
1268/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +00001269 MISC
1270 ------------------------------------------------ */
1271
sewardj5905fae2002-04-26 13:25:00 +00001272int __pthread_atfork ( void (*prepare)(void),
1273 void (*parent)(void),
1274 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +00001275{
sewardjccef2e62002-05-29 19:26:32 +00001276 /* We have to do this properly or not at all; faking it isn't an
1277 option. */
1278 vgPlain_unimp("__pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +00001279}
1280
1281
sewardjbb990782002-05-08 02:01:14 +00001282__attribute__((weak))
1283void __pthread_initialize ( void )
1284{
sewardjbea1caa2002-05-10 23:20:58 +00001285 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +00001286}
1287
1288
sewardj853f55d2002-04-26 00:27:53 +00001289/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00001290 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +00001291 ------------------------------------------------ */
1292
sewardj3b13f0e2002-04-25 20:17:29 +00001293#include <resolv.h>
1294static int thread_specific_errno[VG_N_THREADS];
1295static int thread_specific_h_errno[VG_N_THREADS];
1296static struct __res_state
1297 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +00001298
sewardj3b13f0e2002-04-25 20:17:29 +00001299int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +00001300{
1301 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +00001302 /* ensure_valgrind("__errno_location"); */
1303 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +00001304 VG_USERREQ__PTHREAD_GET_THREADID,
1305 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +00001306 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001307 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001308 barf("__errno_location: invalid ThreadId");
1309 return & thread_specific_errno[tid];
1310}
1311
1312int* __h_errno_location ( void )
1313{
1314 int tid;
1315 /* ensure_valgrind("__h_errno_location"); */
1316 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1317 VG_USERREQ__PTHREAD_GET_THREADID,
1318 0, 0, 0, 0);
1319 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001320 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001321 barf("__h_errno_location: invalid ThreadId");
1322 return & thread_specific_h_errno[tid];
1323}
1324
1325struct __res_state* __res_state ( void )
1326{
1327 int tid;
1328 /* ensure_valgrind("__res_state"); */
1329 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1330 VG_USERREQ__PTHREAD_GET_THREADID,
1331 0, 0, 0, 0);
1332 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001333 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001334 barf("__res_state: invalid ThreadId");
1335 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001336}
1337
1338
sewardj5716dbb2002-04-26 03:28:18 +00001339/* ---------------------------------------------------
1340 LIBC-PRIVATE SPECIFIC DATA
1341 ------------------------------------------------ */
1342
1343/* Relies on assumption that initial private data is NULL. This
1344 should be fixed somehow. */
1345
1346/* The allowable keys (indices) (all 2 of them).
1347 From sysdeps/pthread/bits/libc-tsd.h
1348*/
sewardj70adeb22002-04-27 01:35:38 +00001349#define N_LIBC_TSD_EXTRA_KEYS 1
1350
sewardj5716dbb2002-04-26 03:28:18 +00001351enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1352 _LIBC_TSD_KEY_DL_ERROR,
1353 _LIBC_TSD_KEY_N };
1354
1355/* Auto-initialising subsystem. libc_specifics_inited is set
1356 after initialisation. libc_specifics_inited_mx guards it. */
1357static int libc_specifics_inited = 0;
1358static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1359
1360/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001361static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1362 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001363
1364/* Initialise the keys, if they are not already initialise. */
1365static
1366void init_libc_tsd_keys ( void )
1367{
1368 int res, i;
1369 pthread_key_t k;
1370
1371 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1372 if (res != 0) barf("init_libc_tsd_keys: lock");
1373
1374 if (libc_specifics_inited == 0) {
1375 /* printf("INIT libc specifics\n"); */
1376 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001377 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001378 res = pthread_key_create(&k, NULL);
1379 if (res != 0) barf("init_libc_tsd_keys: create");
1380 libc_specifics_keys[i] = k;
1381 }
1382 }
1383
1384 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1385 if (res != 0) barf("init_libc_tsd_keys: unlock");
1386}
1387
1388
1389static int
1390libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1391 const void * pointer )
1392{
sewardj70adeb22002-04-27 01:35:38 +00001393 int res;
1394 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001395 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001396 if (key < _LIBC_TSD_KEY_MALLOC
1397 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001398 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001399 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1400 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001401 "valgrind's libpthread.so: libc_internal_tsd_set: "
1402 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001403 init_libc_tsd_keys();
1404 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1405 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1406 return 0;
1407}
1408
1409static void *
1410libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1411{
sewardj70adeb22002-04-27 01:35:38 +00001412 void* v;
1413 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001414 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001415 if (key < _LIBC_TSD_KEY_MALLOC
1416 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001417 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001418 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1419 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001420 "valgrind's libpthread.so: libc_internal_tsd_get: "
1421 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001422 init_libc_tsd_keys();
1423 v = pthread_getspecific(libc_specifics_keys[key]);
1424 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1425 return v;
1426}
1427
1428
1429
1430
sewardj70adeb22002-04-27 01:35:38 +00001431int (*__libc_internal_tsd_set)
1432 (enum __libc_tsd_key_t key, const void * pointer)
1433 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001434
sewardj70adeb22002-04-27 01:35:38 +00001435void* (*__libc_internal_tsd_get)
1436 (enum __libc_tsd_key_t key)
1437 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001438
1439
sewardje663cb92002-04-12 10:26:32 +00001440/* ---------------------------------------------------------------------
1441 These are here (I think) because they are deemed cancellation
1442 points by POSIX. For the moment we'll simply pass the call along
1443 to the corresponding thread-unaware (?) libc routine.
1444 ------------------------------------------------------------------ */
1445
sewardje663cb92002-04-12 10:26:32 +00001446#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001447#include <sys/types.h>
1448#include <sys/socket.h>
1449
sewardjd529a442002-05-04 19:49:21 +00001450#ifdef GLIBC_2_1
1451extern
1452int __sigaction
1453 (int signum,
1454 const struct sigaction *act,
1455 struct sigaction *oldact);
1456#else
sewardje663cb92002-04-12 10:26:32 +00001457extern
1458int __libc_sigaction
1459 (int signum,
1460 const struct sigaction *act,
1461 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001462#endif
sewardje663cb92002-04-12 10:26:32 +00001463int sigaction(int signum,
1464 const struct sigaction *act,
1465 struct sigaction *oldact)
1466{
sewardjd140e442002-05-29 01:21:19 +00001467 __my_pthread_testcancel();
sewardj2a1dcce2002-04-22 12:45:25 +00001468# ifdef GLIBC_2_1
1469 return __sigaction(signum, act, oldact);
1470# else
sewardj45b4b372002-04-16 22:50:32 +00001471 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001472# endif
sewardje663cb92002-04-12 10:26:32 +00001473}
1474
1475
1476extern
1477int __libc_connect(int sockfd,
1478 const struct sockaddr *serv_addr,
1479 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001480__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001481int connect(int sockfd,
1482 const struct sockaddr *serv_addr,
1483 socklen_t addrlen)
1484{
sewardjd140e442002-05-29 01:21:19 +00001485 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001486 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001487}
1488
1489
1490extern
1491int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001492__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001493int fcntl(int fd, int cmd, long arg)
1494{
sewardjd140e442002-05-29 01:21:19 +00001495 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001496 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001497}
1498
1499
1500extern
1501ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001502__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001503ssize_t write(int fd, const void *buf, size_t count)
1504{
sewardjd140e442002-05-29 01:21:19 +00001505 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001506 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001507}
1508
1509
1510extern
1511ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001512__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001513ssize_t read(int fd, void *buf, size_t count)
1514{
sewardjd140e442002-05-29 01:21:19 +00001515 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001516 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001517}
1518
sewardjbe32e452002-04-24 20:29:58 +00001519
1520extern
sewardj853f55d2002-04-26 00:27:53 +00001521int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001522__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001523int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001524{
sewardjd140e442002-05-29 01:21:19 +00001525 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001526 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001527}
1528
sewardje663cb92002-04-12 10:26:32 +00001529
1530extern
sewardj853f55d2002-04-26 00:27:53 +00001531int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001532__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001533int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001534{
sewardjd140e442002-05-29 01:21:19 +00001535 __my_pthread_testcancel();
sewardj853f55d2002-04-26 00:27:53 +00001536 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001537}
1538
1539
1540extern
1541int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001542__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001543int close(int fd)
1544{
sewardjd140e442002-05-29 01:21:19 +00001545 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001546 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001547}
1548
1549
1550extern
1551int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001552__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001553int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1554{
sewardjd140e442002-05-29 01:21:19 +00001555 __my_pthread_testcancel();
sewardj705d3cb2002-05-23 13:13:12 +00001556 wait_for_fd_to_be_readable_or_erring(s);
sewardjd140e442002-05-29 01:21:19 +00001557 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001558 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001559}
1560
1561
1562extern
1563pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001564pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001565{
sewardjd140e442002-05-29 01:21:19 +00001566 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001567 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001568}
1569
1570
1571extern
1572pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001573__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001574pid_t waitpid(pid_t pid, int *status, int options)
1575{
sewardjd140e442002-05-29 01:21:19 +00001576 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001577 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001578}
1579
1580
1581extern
1582int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001583__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001584int nanosleep(const struct timespec *req, struct timespec *rem)
1585{
sewardjd140e442002-05-29 01:21:19 +00001586 __my_pthread_testcancel();
sewardje663cb92002-04-12 10:26:32 +00001587 return __libc_nanosleep(req, rem);
1588}
1589
sewardjbe32e452002-04-24 20:29:58 +00001590
sewardje663cb92002-04-12 10:26:32 +00001591extern
1592int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001593__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001594int fsync(int fd)
1595{
sewardjd140e442002-05-29 01:21:19 +00001596 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001597 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001598}
1599
sewardjbe32e452002-04-24 20:29:58 +00001600
sewardj70c75362002-04-13 04:18:32 +00001601extern
1602off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001603__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001604off_t lseek(int fildes, off_t offset, int whence)
1605{
sewardjd140e442002-05-29 01:21:19 +00001606 __my_pthread_testcancel();
sewardj45b4b372002-04-16 22:50:32 +00001607 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001608}
1609
sewardjbe32e452002-04-24 20:29:58 +00001610
1611extern
1612__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001613__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001614__off64_t lseek64(int fildes, __off64_t offset, int whence)
1615{
sewardjd140e442002-05-29 01:21:19 +00001616 __my_pthread_testcancel();
sewardjbe32e452002-04-24 20:29:58 +00001617 return __libc_lseek64(fildes, offset, whence);
1618}
1619
1620
sewardj726c4122002-05-16 23:39:10 +00001621extern
1622ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1623 __off64_t __offset);
1624ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1625 __off64_t __offset)
1626{
sewardjd140e442002-05-29 01:21:19 +00001627 __my_pthread_testcancel();
sewardj726c4122002-05-16 23:39:10 +00001628 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1629}
1630
1631
sewardja18e2102002-05-18 10:43:22 +00001632extern
1633ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1634 __off64_t __offset);
1635ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1636 __off64_t __offset)
1637{
sewardjd140e442002-05-29 01:21:19 +00001638 __my_pthread_testcancel();
sewardja18e2102002-05-18 10:43:22 +00001639 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1640}
1641
sewardj726c4122002-05-16 23:39:10 +00001642
sewardj39b93b12002-05-18 10:56:27 +00001643extern
1644ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1645__attribute__((weak))
1646ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1647{
sewardjd140e442002-05-29 01:21:19 +00001648 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001649 return __libc_pwrite(fd, buf, count, offset);
1650}
1651
1652
1653extern
1654ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1655__attribute__((weak))
1656ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1657{
sewardjd140e442002-05-29 01:21:19 +00001658 __my_pthread_testcancel();
sewardj39b93b12002-05-18 10:56:27 +00001659 return __libc_pread(fd, buf, count, offset);
1660}
1661
1662
sewardj6af4b5d2002-04-16 04:40:49 +00001663extern
1664void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001665/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001666void longjmp(jmp_buf env, int val)
1667{
1668 __libc_longjmp(env, val);
1669}
1670
sewardjbe32e452002-04-24 20:29:58 +00001671
sewardj436c2db2002-06-18 09:07:54 +00001672extern void __libc_siglongjmp (sigjmp_buf env, int val)
1673 __attribute__ ((noreturn));
1674void siglongjmp(sigjmp_buf env, int val)
1675{
1676 kludged("siglongjmp (cleanup handlers are ignored)");
1677 __libc_siglongjmp(env, val);
1678}
1679
1680
sewardj6af4b5d2002-04-16 04:40:49 +00001681extern
1682int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001683__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001684int send(int s, const void *msg, size_t len, int flags)
1685{
sewardjd140e442002-05-29 01:21:19 +00001686 __my_pthread_testcancel();
sewardj6af4b5d2002-04-16 04:40:49 +00001687 return __libc_send(s, msg, len, flags);
1688}
1689
sewardjbe32e452002-04-24 20:29:58 +00001690
sewardj1e8cdc92002-04-18 11:37:52 +00001691extern
1692int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001693__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001694int recv(int s, void *buf, size_t len, int flags)
1695{
sewardjd140e442002-05-29 01:21:19 +00001696 __my_pthread_testcancel();
sewardj1d6b3a22002-06-20 07:58:33 +00001697 wait_for_fd_to_be_readable_or_erring(s);
1698 __my_pthread_testcancel();
sewardj1e8cdc92002-04-18 11:37:52 +00001699 return __libc_recv(s, buf, len, flags);
1700}
1701
sewardjbe32e452002-04-24 20:29:58 +00001702
sewardj3665ded2002-05-16 16:57:25 +00001703extern
1704int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1705__attribute__((weak))
1706int sendmsg(int s, const struct msghdr *msg, int flags)
1707{
sewardjd140e442002-05-29 01:21:19 +00001708 __my_pthread_testcancel();
sewardj3665ded2002-05-16 16:57:25 +00001709 return __libc_sendmsg(s, msg, flags);
1710}
1711
1712
sewardj796d6a22002-04-24 02:28:34 +00001713extern
sewardj59da27a2002-06-06 08:33:54 +00001714int __libc_recvmsg(int s, struct msghdr *msg, int flags);
1715__attribute__((weak))
1716int recvmsg(int s, struct msghdr *msg, int flags)
1717{
1718 __my_pthread_testcancel();
1719 return __libc_recvmsg(s, msg, flags);
1720}
1721
1722
1723extern
sewardj436e0582002-04-26 14:31:40 +00001724int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1725 struct sockaddr *from, socklen_t *fromlen);
1726__attribute__((weak))
1727int recvfrom(int s, void *buf, size_t len, int flags,
1728 struct sockaddr *from, socklen_t *fromlen)
1729{
sewardjd140e442002-05-29 01:21:19 +00001730 __my_pthread_testcancel();
sewardj2e207632002-06-13 17:29:53 +00001731 wait_for_fd_to_be_readable_or_erring(s);
1732 __my_pthread_testcancel();
sewardj436e0582002-04-26 14:31:40 +00001733 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1734}
1735
1736
1737extern
sewardj796d6a22002-04-24 02:28:34 +00001738int __libc_sendto(int s, const void *msg, size_t len, int flags,
1739 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001740__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001741int sendto(int s, const void *msg, size_t len, int flags,
1742 const struct sockaddr *to, socklen_t tolen)
1743{
sewardjd140e442002-05-29 01:21:19 +00001744 __my_pthread_testcancel();
sewardj796d6a22002-04-24 02:28:34 +00001745 return __libc_sendto(s, msg, len, flags, to, tolen);
1746}
1747
sewardjbe32e452002-04-24 20:29:58 +00001748
sewardj369b1702002-04-24 13:28:15 +00001749extern
1750int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001751__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001752int system(const char* str)
1753{
sewardjd140e442002-05-29 01:21:19 +00001754 __my_pthread_testcancel();
sewardj369b1702002-04-24 13:28:15 +00001755 return __libc_system(str);
1756}
1757
sewardjbe32e452002-04-24 20:29:58 +00001758
sewardjab0b1c32002-04-24 19:26:47 +00001759extern
1760pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001761__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001762pid_t wait(int *status)
1763{
sewardjd140e442002-05-29 01:21:19 +00001764 __my_pthread_testcancel();
sewardjab0b1c32002-04-24 19:26:47 +00001765 return __libc_wait(status);
1766}
1767
sewardj45b4b372002-04-16 22:50:32 +00001768
sewardj67f1d582002-05-24 02:11:32 +00001769extern
1770int __libc_msync(const void *start, size_t length, int flags);
1771__attribute__((weak))
1772int msync(const void *start, size_t length, int flags)
1773{
sewardjd140e442002-05-29 01:21:19 +00001774 __my_pthread_testcancel();
sewardj67f1d582002-05-24 02:11:32 +00001775 return __libc_msync(start, length, flags);
1776}
1777
sewardj5905fae2002-04-26 13:25:00 +00001778
sewardj3b13f0e2002-04-25 20:17:29 +00001779/* ---------------------------------------------------------------------
1780 Nonblocking implementations of select() and poll(). This stuff will
1781 surely rot your mind.
1782 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001783
sewardj08a4c3f2002-04-13 03:45:44 +00001784/*--------------------------------------------------*/
1785
1786#include "vg_kerneliface.h"
1787
1788static
1789__inline__
1790int is_kerror ( int res )
1791{
1792 if (res >= -4095 && res <= -1)
1793 return 1;
1794 else
1795 return 0;
1796}
1797
1798
1799static
1800int my_do_syscall1 ( int syscallno, int arg1 )
1801{
1802 int __res;
1803 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1804 : "=a" (__res)
1805 : "0" (syscallno),
1806 "d" (arg1) );
1807 return __res;
1808}
1809
1810static
1811int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001812 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001813{
1814 int __res;
1815 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1816 : "=a" (__res)
1817 : "0" (syscallno),
1818 "d" (arg1),
1819 "c" (arg2) );
1820 return __res;
1821}
1822
1823static
sewardjf854f472002-04-21 12:19:41 +00001824int my_do_syscall3 ( int syscallno,
1825 int arg1, int arg2, int arg3 )
1826{
1827 int __res;
1828 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1829 : "=a" (__res)
1830 : "0" (syscallno),
1831 "S" (arg1),
1832 "c" (arg2),
1833 "d" (arg3) );
1834 return __res;
1835}
1836
1837static
sewardj08a4c3f2002-04-13 03:45:44 +00001838int do_syscall_select( int n,
1839 vki_fd_set* readfds,
1840 vki_fd_set* writefds,
1841 vki_fd_set* exceptfds,
1842 struct vki_timeval * timeout )
1843{
1844 int res;
1845 int args[5];
1846 args[0] = n;
1847 args[1] = (int)readfds;
1848 args[2] = (int)writefds;
1849 args[3] = (int)exceptfds;
1850 args[4] = (int)timeout;
1851 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001852 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001853}
1854
1855
1856/* This is a wrapper round select(), which makes it thread-safe,
1857 meaning that only this thread will block, rather than the entire
1858 process. This wrapper in turn depends on nanosleep() not to block
1859 the entire process, but I think (hope? suspect?) that POSIX
1860 pthreads guarantees that to be the case.
1861
1862 Basic idea is: modify the timeout parameter to select so that it
1863 returns immediately. Poll like this until select returns non-zero,
1864 indicating something interesting happened, or until our time is up.
1865 Space out the polls with nanosleeps of say 20 milliseconds, which
1866 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001867
1868 Assumes:
sewardj2d94c112002-06-03 01:25:54 +00001869 * (checked via my_assert) types fd_set and vki_fd_set are identical.
1870 * (checked via my_assert) types timeval and vki_timeval are identical.
sewardj02535bc2002-04-21 01:08:26 +00001871 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1872 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001873*/
sewardj08a4c3f2002-04-13 03:45:44 +00001874
sewardj5905fae2002-04-26 13:25:00 +00001875/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001876int select ( int n,
1877 fd_set *rfds,
1878 fd_set *wfds,
1879 fd_set *xfds,
1880 struct timeval *timeout )
1881{
sewardj5f07b662002-04-23 16:52:51 +00001882 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001883 int res;
1884 fd_set rfds_copy;
1885 fd_set wfds_copy;
1886 fd_set xfds_copy;
1887 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001888 struct vki_timeval zero_timeout;
1889 struct vki_timespec nanosleep_interval;
1890
sewardjd140e442002-05-29 01:21:19 +00001891 __my_pthread_testcancel();
1892
sewardj5f07b662002-04-23 16:52:51 +00001893 /* gcc's complains about ms_end being used uninitialised -- classic
1894 case it can't understand, where ms_end is both defined and used
1895 only if timeout != NULL. Hence ... */
1896 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001897
1898 /* We assume that the kernel and libc data layouts are identical
1899 for the following types. These asserts provide a crude
1900 check. */
1901 if (sizeof(fd_set) != sizeof(vki_fd_set)
1902 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1903 barf("valgrind's hacky non-blocking select(): data sizes error");
1904
sewardj5f07b662002-04-23 16:52:51 +00001905 /* Detect the current time and simultaneously find out if we are
1906 running on Valgrind. */
1907 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1908 VG_USERREQ__READ_MILLISECOND_TIMER,
1909 0, 0, 0, 0);
1910
1911 /* If a zero timeout specified, this call is harmless. Also go
1912 this route if we're not running on Valgrind, for whatever
1913 reason. */
1914 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1915 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001916 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001917 (vki_fd_set*)wfds,
1918 (vki_fd_set*)xfds,
1919 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001920 if (is_kerror(res)) {
1921 * (__errno_location()) = -res;
1922 return -1;
1923 } else {
1924 return res;
1925 }
1926 }
sewardj08a4c3f2002-04-13 03:45:44 +00001927
sewardj5f07b662002-04-23 16:52:51 +00001928 /* If a timeout was specified, set ms_end to be the end millisecond
1929 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001930 if (timeout) {
1931 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
sewardj2d94c112002-06-03 01:25:54 +00001932 my_assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001933 ms_end = ms_now;
1934 ms_end += (timeout->tv_usec / 1000);
1935 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001936 /* Stay sane ... */
sewardj2d94c112002-06-03 01:25:54 +00001937 my_assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001938 }
1939
1940 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1941
1942 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001943 NULL, in which case ms_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00001944
sewardj08a4c3f2002-04-13 03:45:44 +00001945 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00001946
1947 /* First, do a return-immediately select(). */
sewardj08a4c3f2002-04-13 03:45:44 +00001948
1949 /* These could be trashed each time round the loop, so restore
1950 them each time. */
1951 if (rfds) rfds_copy = *rfds;
1952 if (wfds) wfds_copy = *wfds;
1953 if (xfds) xfds_copy = *xfds;
1954
1955 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1956
1957 res = do_syscall_select( n,
1958 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1959 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1960 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1961 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001962 if (is_kerror(res)) {
1963 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001964 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001965 * (__errno_location()) = -res;
1966 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001967 }
1968 if (res > 0) {
1969 /* one or more fds is ready. Copy out resulting sets and
1970 return. */
1971 if (rfds) *rfds = rfds_copy;
1972 if (wfds) *wfds = wfds_copy;
1973 if (xfds) *xfds = xfds_copy;
1974 return res;
1975 }
sewardj05bb2c92002-06-26 00:47:17 +00001976
1977 /* Nothing interesting happened, so we go to sleep for a
1978 while. */
1979
sewardj08a4c3f2002-04-13 03:45:44 +00001980 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1981 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001982 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001983 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001984 /* It's critical here that valgrind's nanosleep implementation
1985 is nonblocking. */
sewardj645030e2002-06-06 01:27:39 +00001986 res = my_do_syscall2(__NR_nanosleep,
sewardjf854f472002-04-21 12:19:41 +00001987 (int)(&nanosleep_interval), (int)NULL);
sewardj645030e2002-06-06 01:27:39 +00001988 if (res == -VKI_EINTR) {
1989 /* The nanosleep was interrupted by a signal. So we do the
1990 same. */
1991 * (__errno_location()) = EINTR;
1992 return -1;
1993 }
sewardj05bb2c92002-06-26 00:47:17 +00001994
1995 /* Sleeping finished. If a finite timeout, check to see if it
1996 has expired yet. */
1997 if (timeout) {
1998 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1999 VG_USERREQ__READ_MILLISECOND_TIMER,
2000 0, 0, 0, 0);
2001 my_assert(ms_now != 0xFFFFFFFF);
2002 if (ms_now >= ms_end) {
2003 /* timeout; nothing interesting happened. */
2004 if (rfds) FD_ZERO(rfds);
2005 if (wfds) FD_ZERO(wfds);
2006 if (xfds) FD_ZERO(xfds);
2007 return 0;
2008 }
2009 }
2010
sewardjf854f472002-04-21 12:19:41 +00002011 }
2012}
2013
2014
2015
2016
2017#include <sys/poll.h>
2018
sewardj3e909ce2002-06-03 13:27:15 +00002019#ifndef HAVE_NFDS_T
sewardj72d58482002-04-24 02:20:20 +00002020typedef unsigned long int nfds_t;
2021#endif
2022
sewardj705d3cb2002-05-23 13:13:12 +00002023
sewardj5905fae2002-04-26 13:25:00 +00002024/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00002025int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
2026{
sewardj5f07b662002-04-23 16:52:51 +00002027 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00002028 int res, i;
sewardjf854f472002-04-21 12:19:41 +00002029 struct vki_timespec nanosleep_interval;
2030
sewardjd140e442002-05-29 01:21:19 +00002031 __my_pthread_testcancel();
sewardjf854f472002-04-21 12:19:41 +00002032 ensure_valgrind("poll");
2033
sewardj5f07b662002-04-23 16:52:51 +00002034 /* Detect the current time and simultaneously find out if we are
2035 running on Valgrind. */
2036 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2037 VG_USERREQ__READ_MILLISECOND_TIMER,
2038 0, 0, 0, 0);
2039
sewardjf854f472002-04-21 12:19:41 +00002040 if (/* CHECK SIZES FOR struct pollfd */
2041 sizeof(struct timeval) != sizeof(struct vki_timeval))
2042 barf("valgrind's hacky non-blocking poll(): data sizes error");
2043
sewardj5f07b662002-04-23 16:52:51 +00002044 /* dummy initialisation to keep gcc -Wall happy */
2045 ms_end = 0;
2046
2047 /* If a zero timeout specified, this call is harmless. Also do
2048 this if not running on Valgrind. */
2049 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00002050 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
2051 if (is_kerror(res)) {
2052 * (__errno_location()) = -res;
2053 return -1;
2054 } else {
2055 return res;
2056 }
2057 }
2058
sewardj5f07b662002-04-23 16:52:51 +00002059 /* If a timeout was specified, set ms_end to be the end wallclock
2060 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00002061 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00002062 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00002063 }
2064
2065 /* fprintf(stderr, "MY_POLL: before loop\n"); */
2066
2067 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
2068 in which case t_end holds the end time. */
sewardj05bb2c92002-06-26 00:47:17 +00002069
sewardj2d94c112002-06-03 01:25:54 +00002070 my_assert(__timeout != 0);
sewardj5f07b662002-04-23 16:52:51 +00002071
sewardjf854f472002-04-21 12:19:41 +00002072 while (1) {
sewardj05bb2c92002-06-26 00:47:17 +00002073
2074 /* Do a return-immediately poll. */
2075
2076 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
2077 if (is_kerror(res)) {
2078 /* Some kind of error. Set errno and return. */
2079 * (__errno_location()) = -res;
2080 return -1;
2081 }
2082 if (res > 0) {
2083 /* One or more fds is ready. Return now. */
2084 return res;
2085 }
2086
2087 /* Nothing interesting happened, so we go to sleep for a
2088 while. */
2089
2090 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
2091 /* nanosleep and go round again */
2092 nanosleep_interval.tv_sec = 0;
2093 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
2094 /* It's critical here that valgrind's nanosleep implementation
2095 is nonblocking. */
2096 (void)my_do_syscall2(__NR_nanosleep,
2097 (int)(&nanosleep_interval), (int)NULL);
2098
2099 /* Sleeping finished. If a finite timeout, check to see if it
2100 has expired yet. */
sewardjf854f472002-04-21 12:19:41 +00002101 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00002102 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
2103 VG_USERREQ__READ_MILLISECOND_TIMER,
2104 0, 0, 0, 0);
sewardj2d94c112002-06-03 01:25:54 +00002105 my_assert(ms_now != 0xFFFFFFFF);
sewardj5f07b662002-04-23 16:52:51 +00002106 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00002107 /* timeout; nothing interesting happened. */
2108 for (i = 0; i < __nfds; i++)
2109 __fds[i].revents = 0;
2110 return 0;
2111 }
2112 }
2113
sewardj08a4c3f2002-04-13 03:45:44 +00002114 }
2115}
sewardj3b13f0e2002-04-25 20:17:29 +00002116
2117
sewardj705d3cb2002-05-23 13:13:12 +00002118/* Helper function used to make accept() non-blocking. Idea is to use
2119 the above nonblocking poll() to make this thread ONLY wait for the
2120 specified fd to become ready, and then return. */
sewardjd1c1cf22002-06-26 00:13:36 +00002121
2122/* Sigh -- a hack. We're not supposed to include this file directly;
2123 should do it via /usr/include/fcntl.h, but that introduces a
2124 varargs prototype for fcntl itself, which we can't mimic. */
2125#define _FCNTL_H
2126#include <bits/fcntl.h>
2127
sewardj705d3cb2002-05-23 13:13:12 +00002128static void wait_for_fd_to_be_readable_or_erring ( int fd )
2129{
2130 struct pollfd pfd;
sewardjd1c1cf22002-06-26 00:13:36 +00002131 int res;
2132
sewardj6e6cbaa2002-05-24 02:12:52 +00002133 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardjd1c1cf22002-06-26 00:13:36 +00002134
2135 /* First check to see if the fd is nonblocking, and/or invalid. In
2136 either case return immediately. */
2137 res = __libc_fcntl(fd, F_GETFL, 0);
2138 if (res == -1) return; /* fd is invalid somehow */
2139 if (res & O_NONBLOCK) return; /* fd is nonblocking */
2140
2141 /* Ok, we'd better wait with poll. */
sewardj705d3cb2002-05-23 13:13:12 +00002142 pfd.fd = fd;
2143 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
2144 /* ... but not POLLOUT, you may notice. */
2145 pfd.revents = 0;
2146 (void)poll(&pfd, 1, -1 /* forever */);
2147}
2148
2149
sewardj3b13f0e2002-04-25 20:17:29 +00002150/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00002151 Hacky implementation of semaphores.
2152 ------------------------------------------------------------------ */
2153
2154#include <semaphore.h>
2155
2156/* This is a terrible way to do the remapping. Plan is to import an
2157 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00002158
2159typedef
2160 struct {
2161 pthread_mutex_t se_mx;
2162 pthread_cond_t se_cv;
2163 int count;
2164 }
2165 vg_sem_t;
2166
2167static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2168
2169static int se_remap_used = 0;
2170static sem_t* se_remap_orig[VG_N_SEMAPHORES];
2171static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
2172
2173static vg_sem_t* se_remap ( sem_t* orig )
2174{
2175 int res, i;
2176 res = __pthread_mutex_lock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002177 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002178
2179 for (i = 0; i < se_remap_used; i++) {
2180 if (se_remap_orig[i] == orig)
2181 break;
2182 }
2183 if (i == se_remap_used) {
2184 if (se_remap_used == VG_N_SEMAPHORES) {
2185 res = pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002186 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002187 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00002188 }
2189 se_remap_used++;
2190 se_remap_orig[i] = orig;
2191 /* printf("allocated semaphore %d\n", i); */
2192 }
2193 res = __pthread_mutex_unlock(&se_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002194 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002195 return &se_remap_new[i];
2196}
2197
2198
2199int sem_init(sem_t *sem, int pshared, unsigned int value)
2200{
2201 int res;
2202 vg_sem_t* vg_sem;
2203 ensure_valgrind("sem_init");
2204 if (pshared != 0) {
sewardj4dced352002-06-04 22:54:20 +00002205 pthread_error("sem_init: unsupported pshared value");
sewardj8f253ff2002-05-19 00:13:34 +00002206 errno = ENOSYS;
2207 return -1;
2208 }
2209 vg_sem = se_remap(sem);
2210 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002211 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002212 res = pthread_cond_init(&vg_sem->se_cv, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002213 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002214 vg_sem->count = value;
2215 return 0;
2216}
2217
2218
2219int sem_wait ( sem_t* sem )
2220{
2221 int res;
2222 vg_sem_t* vg_sem;
2223 ensure_valgrind("sem_wait");
2224 vg_sem = se_remap(sem);
2225 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002226 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002227 while (vg_sem->count == 0) {
2228 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002229 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002230 }
2231 vg_sem->count--;
2232 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002233 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002234 return 0;
2235}
2236
2237int sem_post ( sem_t* sem )
2238{
2239 int res;
2240 vg_sem_t* vg_sem;
2241 ensure_valgrind("sem_post");
2242 vg_sem = se_remap(sem);
2243 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002244 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002245 if (vg_sem->count == 0) {
2246 vg_sem->count++;
2247 res = pthread_cond_broadcast(&vg_sem->se_cv);
sewardj2d94c112002-06-03 01:25:54 +00002248 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002249 } else {
2250 vg_sem->count++;
2251 }
2252 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002253 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002254 return 0;
2255}
2256
2257
2258int sem_trywait ( sem_t* sem )
2259{
2260 int ret, res;
2261 vg_sem_t* vg_sem;
2262 ensure_valgrind("sem_trywait");
2263 vg_sem = se_remap(sem);
2264 res = __pthread_mutex_lock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002265 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002266 if (vg_sem->count > 0) {
2267 vg_sem->count--;
2268 ret = 0;
2269 } else {
2270 ret = -1;
2271 errno = EAGAIN;
2272 }
2273 res = __pthread_mutex_unlock(&vg_sem->se_mx);
sewardj2d94c112002-06-03 01:25:54 +00002274 my_assert(res == 0);
sewardj8f253ff2002-05-19 00:13:34 +00002275 return ret;
2276}
2277
2278
2279int sem_getvalue(sem_t* sem, int * sval)
2280{
2281 vg_sem_t* vg_sem;
2282 ensure_valgrind("sem_trywait");
2283 vg_sem = se_remap(sem);
2284 *sval = vg_sem->count;
2285 return 0;
2286}
2287
2288
2289int sem_destroy(sem_t * sem)
2290{
2291 kludged("sem_destroy");
2292 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
2293 return 0;
2294}
2295
2296
2297/* ---------------------------------------------------------------------
sewardj2d8b3f02002-06-01 14:14:19 +00002298 Reader-writer locks.
sewardja1ac5cb2002-05-27 13:00:05 +00002299 ------------------------------------------------------------------ */
2300
sewardj2d8b3f02002-06-01 14:14:19 +00002301typedef
2302 struct {
2303 int initted; /* != 0 --> in use; sanity check only */
2304 int prefer_w; /* != 0 --> prefer writer */
2305 int nwait_r; /* # of waiting readers */
2306 int nwait_w; /* # of waiting writers */
2307 pthread_cond_t cv_r; /* for signalling readers */
2308 pthread_cond_t cv_w; /* for signalling writers */
2309 pthread_mutex_t mx;
2310 int status;
2311 /* allowed range for status: >= -1. -1 means 1 writer currently
2312 active, >= 0 means N readers currently active. */
2313 }
2314 vg_rwlock_t;
sewardja1ac5cb2002-05-27 13:00:05 +00002315
2316
2317static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
2318
2319static int rw_remap_used = 0;
2320static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
2321static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
2322
sewardj2d8b3f02002-06-01 14:14:19 +00002323
2324static
2325void init_vg_rwlock ( vg_rwlock_t* vg_rwl )
2326{
2327 int res = 0;
2328 vg_rwl->initted = 1;
2329 vg_rwl->prefer_w = 1;
2330 vg_rwl->nwait_r = 0;
2331 vg_rwl->nwait_w = 0;
2332 vg_rwl->status = 0;
2333 res = pthread_mutex_init(&vg_rwl->mx, NULL);
2334 res |= pthread_cond_init(&vg_rwl->cv_r, NULL);
2335 res |= pthread_cond_init(&vg_rwl->cv_w, NULL);
sewardj2d94c112002-06-03 01:25:54 +00002336 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002337}
2338
2339
sewardja1ac5cb2002-05-27 13:00:05 +00002340/* Take the address of a LinuxThreads rwlock_t and return the shadow
2341 address of our version. Further, if the LinuxThreads version
2342 appears to have been statically initialised, do the same to the one
2343 we allocate here. The pthread_rwlock_t.__rw_readers field is set
2344 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
2345 uninitialised and non-zero meaning initialised.
2346*/
2347static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
2348{
2349 int res, i;
2350 vg_rwlock_t* vg_rwl;
2351 res = __pthread_mutex_lock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002352 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002353
2354 for (i = 0; i < rw_remap_used; i++) {
2355 if (rw_remap_orig[i] == orig)
2356 break;
2357 }
2358 if (i == rw_remap_used) {
2359 if (rw_remap_used == VG_N_RWLOCKS) {
sewardj2d8b3f02002-06-01 14:14:19 +00002360 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002361 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002362 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
2363 }
2364 rw_remap_used++;
2365 rw_remap_orig[i] = orig;
sewardj2d8b3f02002-06-01 14:14:19 +00002366 rw_remap_new[i].initted = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002367 if (0) printf("allocated rwlock %d\n", i);
2368 }
2369 res = __pthread_mutex_unlock(&rw_remap_mx);
sewardj2d94c112002-06-03 01:25:54 +00002370 my_assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00002371 vg_rwl = &rw_remap_new[i];
2372
sewardj2d8b3f02002-06-01 14:14:19 +00002373 /* Initialise the shadow, if required. */
sewardja1ac5cb2002-05-27 13:00:05 +00002374 if (orig->__rw_readers == 0) {
sewardja1ac5cb2002-05-27 13:00:05 +00002375 orig->__rw_readers = 1;
sewardj2d8b3f02002-06-01 14:14:19 +00002376 init_vg_rwlock(vg_rwl);
sewardja1ac5cb2002-05-27 13:00:05 +00002377 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
sewardj2d8b3f02002-06-01 14:14:19 +00002378 vg_rwl->prefer_w = 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002379 }
2380
2381 return vg_rwl;
2382}
2383
2384
sewardja1ac5cb2002-05-27 13:00:05 +00002385int pthread_rwlock_init ( pthread_rwlock_t* orig,
2386 const pthread_rwlockattr_t* attr )
2387{
sewardja1ac5cb2002-05-27 13:00:05 +00002388 vg_rwlock_t* rwl;
2389 if (0) printf ("pthread_rwlock_init\n");
2390 /* Force the remapper to initialise the shadow. */
2391 orig->__rw_readers = 0;
2392 /* Install the lock preference; the remapper needs to know it. */
2393 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2394 if (attr)
2395 orig->__rw_kind = attr->__lockkind;
2396 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002397 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002398}
2399
sewardj2d8b3f02002-06-01 14:14:19 +00002400
2401static
2402void pthread_rwlock_rdlock_CANCEL_HDLR ( void* rwl_v )
sewardja1ac5cb2002-05-27 13:00:05 +00002403{
sewardj2d8b3f02002-06-01 14:14:19 +00002404 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2405 rwl->nwait_r--;
2406 pthread_mutex_unlock (&rwl->mx);
sewardja1ac5cb2002-05-27 13:00:05 +00002407}
2408
sewardj2d8b3f02002-06-01 14:14:19 +00002409
sewardja1ac5cb2002-05-27 13:00:05 +00002410int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2411{
2412 int res;
2413 vg_rwlock_t* rwl;
2414 if (0) printf ("pthread_rwlock_rdlock\n");
2415 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002416 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002417 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002418 if (!rwl->initted) {
2419 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002420 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002421 return EINVAL;
2422 }
2423 if (rwl->status < 0) {
sewardj2d94c112002-06-03 01:25:54 +00002424 my_assert(rwl->status == -1);
sewardj2d8b3f02002-06-01 14:14:19 +00002425 rwl->nwait_r++;
2426 pthread_cleanup_push( pthread_rwlock_rdlock_CANCEL_HDLR, rwl );
2427 while (1) {
2428 if (rwl->status == 0) break;
2429 res = pthread_cond_wait(&rwl->cv_r, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002430 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002431 }
2432 pthread_cleanup_pop(0);
2433 rwl->nwait_r--;
2434 }
sewardj2d94c112002-06-03 01:25:54 +00002435 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002436 rwl->status++;
2437 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002438 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002439 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002440}
2441
sewardj2d8b3f02002-06-01 14:14:19 +00002442
sewardja1ac5cb2002-05-27 13:00:05 +00002443int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2444{
2445 int res;
2446 vg_rwlock_t* rwl;
2447 if (0) printf ("pthread_rwlock_tryrdlock\n");
2448 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002449 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002450 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002451 if (!rwl->initted) {
2452 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002453 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002454 return EINVAL;
2455 }
2456 if (rwl->status == -1) {
2457 /* Writer active; we have to give up. */
2458 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002459 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002460 return EBUSY;
2461 }
2462 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002463 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002464 rwl->status++;
2465 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002466 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002467 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002468}
2469
sewardj2d8b3f02002-06-01 14:14:19 +00002470
2471static
2472void pthread_rwlock_wrlock_CANCEL_HDLR ( void* rwl_v )
2473{
2474 vg_rwlock_t* rwl = (vg_rwlock_t*)rwl_v;
2475 rwl->nwait_w--;
2476 pthread_mutex_unlock (&rwl->mx);
2477}
2478
2479
sewardja1ac5cb2002-05-27 13:00:05 +00002480int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2481{
2482 int res;
2483 vg_rwlock_t* rwl;
2484 if (0) printf ("pthread_rwlock_wrlock\n");
2485 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002486 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002487 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002488 if (!rwl->initted) {
2489 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002490 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002491 return EINVAL;
2492 }
2493 if (rwl->status != 0) {
2494 rwl->nwait_w++;
2495 pthread_cleanup_push( pthread_rwlock_wrlock_CANCEL_HDLR, rwl );
2496 while (1) {
2497 if (rwl->status == 0) break;
2498 res = pthread_cond_wait(&rwl->cv_w, &rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002499 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002500 }
2501 pthread_cleanup_pop(0);
2502 rwl->nwait_w--;
2503 }
sewardj2d94c112002-06-03 01:25:54 +00002504 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002505 rwl->status = -1;
2506 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002507 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002508 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002509}
2510
sewardj2d8b3f02002-06-01 14:14:19 +00002511
sewardja1ac5cb2002-05-27 13:00:05 +00002512int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2513{
2514 int res;
2515 vg_rwlock_t* rwl;
sewardj2d8b3f02002-06-01 14:14:19 +00002516 if (0) printf ("pthread_wrlock_trywrlock\n");
sewardja1ac5cb2002-05-27 13:00:05 +00002517 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002518 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002519 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002520 if (!rwl->initted) {
2521 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002522 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002523 return EINVAL;
2524 }
2525 if (rwl->status != 0) {
2526 /* Reader(s) or a writer active; we have to give up. */
2527 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002528 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002529 return EBUSY;
2530 }
2531 /* Success */
sewardj2d94c112002-06-03 01:25:54 +00002532 my_assert(rwl->status == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002533 rwl->status = -1;
2534 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002535 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002536 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002537}
2538
sewardj2d8b3f02002-06-01 14:14:19 +00002539
sewardja1ac5cb2002-05-27 13:00:05 +00002540int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2541{
2542 int res;
2543 vg_rwlock_t* rwl;
2544 if (0) printf ("pthread_rwlock_unlock\n");
2545 rwl = rw_remap ( orig );
sewardj2d8b3f02002-06-01 14:14:19 +00002546 rwl = rw_remap ( orig );
2547 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002548 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002549 if (!rwl->initted) {
2550 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002551 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002552 return EINVAL;
2553 }
2554 if (rwl->status == 0) {
2555 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002556 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002557 return EPERM;
2558 }
sewardj2d94c112002-06-03 01:25:54 +00002559 my_assert(rwl->status != 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002560 if (rwl->status == -1) {
2561 rwl->status = 0;
2562 } else {
sewardj2d94c112002-06-03 01:25:54 +00002563 my_assert(rwl->status > 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002564 rwl->status--;
2565 }
2566
sewardj2d94c112002-06-03 01:25:54 +00002567 my_assert(rwl->status >= 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002568
2569 if (rwl->prefer_w) {
2570
2571 /* Favour waiting writers, if any. */
2572 if (rwl->nwait_w > 0) {
2573 /* Writer(s) are waiting. */
2574 if (rwl->status == 0) {
2575 /* We can let a writer in. */
2576 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002577 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002578 } else {
2579 /* There are still readers active. Do nothing; eventually
2580 they will disappear, at which point a writer will be
2581 admitted. */
2582 }
2583 }
2584 else
2585 /* No waiting writers. */
2586 if (rwl->nwait_r > 0) {
2587 /* Let in a waiting reader. */
2588 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002589 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002590 }
2591
2592 } else {
2593
2594 /* Favour waiting readers, if any. */
2595 if (rwl->nwait_r > 0) {
2596 /* Reader(s) are waiting; let one in. */
2597 res = pthread_cond_signal(&rwl->cv_r);
sewardj2d94c112002-06-03 01:25:54 +00002598 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002599 }
2600 else
2601 /* No waiting readers. */
2602 if (rwl->nwait_w > 0 && rwl->status == 0) {
2603 /* We have waiting writers and no active readers; let a
2604 writer in. */
2605 res = pthread_cond_signal(&rwl->cv_w);
sewardj2d94c112002-06-03 01:25:54 +00002606 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002607 }
2608 }
2609
2610 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002611 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002612 return 0;
2613}
2614
2615
2616int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2617{
2618 int res;
2619 vg_rwlock_t* rwl;
2620 if (0) printf ("pthread_rwlock_destroy\n");
2621 rwl = rw_remap ( orig );
2622 res = __pthread_mutex_lock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002623 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002624 if (!rwl->initted) {
2625 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002626 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002627 return EINVAL;
2628 }
2629 if (rwl->status != 0 || rwl->nwait_r > 0 || rwl->nwait_w > 0) {
2630 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002631 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002632 return EBUSY;
2633 }
2634 rwl->initted = 0;
2635 res = __pthread_mutex_unlock(&rwl->mx);
sewardj2d94c112002-06-03 01:25:54 +00002636 my_assert(res == 0);
sewardj2d8b3f02002-06-01 14:14:19 +00002637 return 0;
sewardja1ac5cb2002-05-27 13:00:05 +00002638}
2639
2640
sewardj47e4e312002-06-18 09:24:34 +00002641/* Copied directly from LinuxThreads. */
2642int
2643pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
2644{
2645 attr->__lockkind = 0;
2646 attr->__pshared = PTHREAD_PROCESS_PRIVATE;
2647
2648 return 0;
2649}
2650
2651
sewardja1ac5cb2002-05-27 13:00:05 +00002652/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002653 B'stard.
2654 ------------------------------------------------------------------ */
2655
2656# define strong_alias(name, aliasname) \
2657 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2658
sewardj5905fae2002-04-26 13:25:00 +00002659# define weak_alias(name, aliasname) \
2660 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002661
sewardj5905fae2002-04-26 13:25:00 +00002662strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2663strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2664strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2665strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2666 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2667strong_alias(__pthread_mutex_init, pthread_mutex_init)
2668strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2669strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2670strong_alias(__pthread_once, pthread_once)
2671strong_alias(__pthread_atfork, pthread_atfork)
2672strong_alias(__pthread_key_create, pthread_key_create)
2673strong_alias(__pthread_getspecific, pthread_getspecific)
2674strong_alias(__pthread_setspecific, pthread_setspecific)
2675
sewardjd529a442002-05-04 19:49:21 +00002676#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002677strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002678#endif
2679
sewardj5905fae2002-04-26 13:25:00 +00002680strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002681strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002682strong_alias(lseek, __lseek)
2683strong_alias(open, __open)
2684strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002685strong_alias(read, __read)
2686strong_alias(wait, __wait)
2687strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002688strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002689strong_alias(send, __send)
2690
sewardj726c4122002-05-16 23:39:10 +00002691weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002692weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002693weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002694
sewardjf0b06452002-06-04 08:38:04 +00002695weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
sewardj3b13f0e2002-04-25 20:17:29 +00002696
2697/*--------------------------------------------------*/
2698
sewardj5905fae2002-04-26 13:25:00 +00002699weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002700weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002701weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002702
sewardja1ac5cb2002-05-27 13:00:05 +00002703weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2704weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2705weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2706weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2707
sewardj060b04f2002-04-26 21:01:13 +00002708
sewardj3b13f0e2002-04-25 20:17:29 +00002709/* I've no idea what these are, but they get called quite a lot.
2710 Anybody know? */
2711
2712#undef _IO_flockfile
2713void _IO_flockfile ( _IO_FILE * file )
2714{
sewardj853f55d2002-04-26 00:27:53 +00002715 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002716}
sewardj5905fae2002-04-26 13:25:00 +00002717weak_alias(_IO_flockfile, flockfile);
2718
sewardj3b13f0e2002-04-25 20:17:29 +00002719
2720#undef _IO_funlockfile
2721void _IO_funlockfile ( _IO_FILE * file )
2722{
sewardj853f55d2002-04-26 00:27:53 +00002723 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002724}
sewardj5905fae2002-04-26 13:25:00 +00002725weak_alias(_IO_funlockfile, funlockfile);
2726
sewardj3b13f0e2002-04-25 20:17:29 +00002727
sewardjd4f2c712002-04-30 10:20:10 +00002728/* This doesn't seem to be needed to simulate libpthread.so's external
2729 interface, but many people complain about its absence. */
2730
2731strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2732weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002733
2734
2735/*--------------------------------------------------------------------*/
2736/*--- end vg_libpthread.c ---*/
2737/*--------------------------------------------------------------------*/