blob: b541d8b155f20b4e040f91c4f10d2dd478e4d697 [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
sewardj705d3cb2002-05-23 13:13:12 +000069
70/* ---------------------------------------------------------------------
71 Forwardses.
72 ------------------------------------------------------------------ */
73
74static void wait_for_fd_to_be_readable_or_erring ( int fd );
75
76
sewardje663cb92002-04-12 10:26:32 +000077/* ---------------------------------------------------------------------
78 Helpers. We have to be pretty self-sufficient.
79 ------------------------------------------------------------------ */
80
sewardj436e0582002-04-26 14:31:40 +000081/* Number of times any given error message is printed. */
82#define N_MOANS 3
83
sewardj45b4b372002-04-16 22:50:32 +000084/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
85 Returns 0 (none) if not running on Valgrind. */
86static
87int get_pt_trace_level ( void )
88{
89 int res;
90 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
91 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
92 0, 0, 0, 0);
93 return res;
94}
95
96
sewardje663cb92002-04-12 10:26:32 +000097static
98void myexit ( int arg )
99{
sewardj45b4b372002-04-16 22:50:32 +0000100 int __res;
sewardje663cb92002-04-12 10:26:32 +0000101 __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
102 : "=a" (__res)
103 : "0" (__NR_exit),
104 "c" (arg) );
sewardj45b4b372002-04-16 22:50:32 +0000105 /* We don't bother to mention the fact that this asm trashes %ebx,
106 since it won't return. If you ever do let it return ... fix
107 this! */
sewardje663cb92002-04-12 10:26:32 +0000108}
109
110
sewardj68b2dd92002-05-10 21:03:56 +0000111/* We need this guy -- it's in valgrind.so. */
112extern void VG_(startup) ( void );
113
114
115/* Just start up Valgrind if it's not already going. VG_(startup)()
116 detects and ignores second and subsequent calls. */
sewardj604ec3c2002-04-18 22:38:41 +0000117static __inline__
sewardje663cb92002-04-12 10:26:32 +0000118void ensure_valgrind ( char* caller )
119{
sewardj68b2dd92002-05-10 21:03:56 +0000120 VG_(startup)();
sewardje663cb92002-04-12 10:26:32 +0000121}
122
sewardjbea1caa2002-05-10 23:20:58 +0000123/* While we're at it ... hook our own startup function into this
124 game. */
125__asm__ (
126 ".section .init\n"
127 "\tcall vgPlain_startup"
128);
129
sewardje663cb92002-04-12 10:26:32 +0000130
131static
sewardj3b5d8862002-04-20 13:53:23 +0000132__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +0000133void barf ( char* str )
134{
135 char buf[100];
136 buf[0] = 0;
sewardj439d45e2002-05-03 20:43:10 +0000137 strcat(buf, "\nvalgrind's libpthread.so: ");
sewardje663cb92002-04-12 10:26:32 +0000138 strcat(buf, str);
139 strcat(buf, "\n\n");
140 write(2, buf, strlen(buf));
141 myexit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000142 /* We have to persuade gcc into believing this doesn't return. */
143 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000144}
145
146
sewardj2a3d28c2002-04-14 13:27:00 +0000147static void ignored ( char* msg )
148{
sewardj436e0582002-04-26 14:31:40 +0000149 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000150 char* ig = "valgrind's libpthread.so: IGNORED call to: ";
sewardj45b4b372002-04-16 22:50:32 +0000151 write(2, ig, strlen(ig));
152 write(2, msg, strlen(msg));
153 ig = "\n";
154 write(2, ig, strlen(ig));
155 }
sewardj2a3d28c2002-04-14 13:27:00 +0000156}
157
sewardj30671ff2002-04-21 00:13:57 +0000158static void kludged ( char* msg )
159{
sewardj436e0582002-04-26 14:31:40 +0000160 if (get_pt_trace_level() >= 0) {
sewardj439d45e2002-05-03 20:43:10 +0000161 char* ig = "valgrind's libpthread.so: KLUDGED call to: ";
162 write(2, ig, strlen(ig));
163 write(2, msg, strlen(msg));
164 ig = "\n";
165 write(2, ig, strlen(ig));
166 }
167}
168
169static void not_inside ( char* msg )
170{
sewardj68b2dd92002-05-10 21:03:56 +0000171 VG_(startup)();
sewardj30671ff2002-04-21 00:13:57 +0000172}
173
sewardj3b13f0e2002-04-25 20:17:29 +0000174void vgPlain_unimp ( char* what )
175{
sewardj439d45e2002-05-03 20:43:10 +0000176 char* ig = "valgrind's libpthread.so: UNIMPLEMENTED FUNCTION: ";
sewardj3b13f0e2002-04-25 20:17:29 +0000177 write(2, ig, strlen(ig));
178 write(2, what, strlen(what));
179 ig = "\n";
180 write(2, ig, strlen(ig));
181 barf("Please report this bug to me at: jseward@acm.org");
182}
183
sewardje663cb92002-04-12 10:26:32 +0000184
185/* ---------------------------------------------------------------------
186 Pass pthread_ calls to Valgrind's request mechanism.
187 ------------------------------------------------------------------ */
188
sewardjf8f819e2002-04-17 23:21:37 +0000189#include <stdio.h>
190#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000191#include <assert.h>
192#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000193
sewardja1ac5cb2002-05-27 13:00:05 +0000194
sewardjf8f819e2002-04-17 23:21:37 +0000195/* ---------------------------------------------------
196 THREAD ATTRIBUTES
197 ------------------------------------------------ */
198
sewardj6af4b5d2002-04-16 04:40:49 +0000199int pthread_attr_init(pthread_attr_t *attr)
200{
sewardj7989d0c2002-05-28 11:00:01 +0000201 /* Just initialise the fields which we might look at. */
202 attr->__detachstate = PTHREAD_CREATE_JOINABLE;
sewardj6af4b5d2002-04-16 04:40:49 +0000203 return 0;
204}
205
206int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
207{
sewardj7989d0c2002-05-28 11:00:01 +0000208 if (detachstate != PTHREAD_CREATE_JOINABLE
209 && detachstate != PTHREAD_CREATE_DETACHED)
210 return EINVAL;
211 attr->__detachstate = detachstate;
sewardj6af4b5d2002-04-16 04:40:49 +0000212 return 0;
213}
214
sewardj30671ff2002-04-21 00:13:57 +0000215int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
216{
sewardj436e0582002-04-26 14:31:40 +0000217 static int moans = N_MOANS;
218 if (moans-- > 0)
219 ignored("pthread_attr_setinheritsched");
sewardj30671ff2002-04-21 00:13:57 +0000220 return 0;
221}
sewardj6af4b5d2002-04-16 04:40:49 +0000222
sewardj0286dd52002-05-16 20:51:15 +0000223__attribute__((weak))
224int pthread_attr_setstacksize (pthread_attr_t *__attr,
225 size_t __stacksize)
226{
sewardja18e2102002-05-18 10:43:22 +0000227 size_t limit;
sewardj0286dd52002-05-16 20:51:15 +0000228 ensure_valgrind("pthread_attr_setstacksize");
sewardja18e2102002-05-18 10:43:22 +0000229 limit = VG_PTHREAD_STACK_SIZE - VG_AR_CLIENT_STACKBASE_REDZONE_SZB
230 - 1000; /* paranoia */
231 if (__stacksize < limit)
sewardj0286dd52002-05-16 20:51:15 +0000232 return 0;
233 barf("pthread_attr_setstacksize: "
234 "requested size >= VG_PTHREAD_STACK_SIZE\n "
235 "edit vg_include.h and rebuild.");
236}
237
238
sewardj30671ff2002-04-21 00:13:57 +0000239/* This is completely bogus. */
240int pthread_attr_getschedparam(const pthread_attr_t *attr,
241 struct sched_param *param)
242{
sewardj436e0582002-04-26 14:31:40 +0000243 static int moans = N_MOANS;
244 if (moans-- > 0)
245 kludged("pthread_attr_getschedparam");
sewardj72d58482002-04-24 02:20:20 +0000246# ifdef GLIBC_2_1
247 if (param) param->sched_priority = 0; /* who knows */
248# else
sewardj30671ff2002-04-21 00:13:57 +0000249 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000250# endif
sewardj30671ff2002-04-21 00:13:57 +0000251 return 0;
252}
253
254int pthread_attr_setschedparam(pthread_attr_t *attr,
255 const struct sched_param *param)
256{
sewardj436e0582002-04-26 14:31:40 +0000257 static int moans = N_MOANS;
258 if (moans-- > 0)
259 ignored("pthread_attr_setschedparam");
sewardj30671ff2002-04-21 00:13:57 +0000260 return 0;
261}
262
263int pthread_attr_destroy(pthread_attr_t *attr)
264{
sewardj436e0582002-04-26 14:31:40 +0000265 static int moans = N_MOANS;
266 if (moans-- > 0)
267 ignored("pthread_attr_destroy");
sewardj30671ff2002-04-21 00:13:57 +0000268 return 0;
269}
sewardjf8f819e2002-04-17 23:21:37 +0000270
sewardj20917d82002-05-28 01:36:45 +0000271/* ---------------------------------------------------
272 Helper functions for running a thread
273 and for clearing up afterwards.
274 ------------------------------------------------ */
275
276/* All exiting threads eventually pass through here, bearing the
277 return value, or PTHREAD_CANCELED, in ret_val. */
278static
279__attribute__((noreturn))
280void thread_exit_wrapper ( void* ret_val )
281{
282 int detached, res;
283 /* Run this thread's cleanup handlers. */
284 /* Run this thread's key finalizers. */
285
286 /* Decide on my final disposition. */
287 VALGRIND_MAGIC_SEQUENCE(detached, (-1) /* default */,
288 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000289 2 /* get */, pthread_self(), 0, 0);
sewardj20917d82002-05-28 01:36:45 +0000290 assert(detached == 0 || detached == 1);
291
292 if (detached) {
293 /* Detached; I just quit right now. */
294 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
295 VG_USERREQ__QUIT, 0, 0, 0, 0);
296 } else {
297 /* Not detached; so I wait for a joiner. */
298 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
299 VG_USERREQ__WAIT_JOINER, ret_val, 0, 0, 0);
300 }
301 /* NOTREACHED */
302 barf("thread_exit_wrapper: still alive?!");
303}
304
305
306/* This function is a wrapper function for running a thread. It runs
307 the root function specified in pthread_create, and then, should the
308 root function return a value, it arranges to run the thread's
309 cleanup handlers and exit correctly. */
310
311/* Struct used to convey info from pthread_create to
312 thread_wrapper. */
313typedef
314 struct {
315 pthread_attr_t* attr;
316 void* (*root_fn) ( void* );
317 void* arg;
318 }
319 NewThreadInfo;
320
321
322/* This is passed to the VG_USERREQ__APPLY_IN_NEW_THREAD and so must
323 not return. Note that this runs in the new thread, not the
324 parent. */
325static
326__attribute__((noreturn))
327void thread_wrapper ( NewThreadInfo* info )
328{
329 int res;
330 pthread_attr_t* attr;
331 void* (*root_fn) ( void* );
332 void* arg;
333 void* ret_val;
334
335 attr = info->attr;
336 root_fn = info->root_fn;
337 arg = info->arg;
338
sewardj20917d82002-05-28 01:36:45 +0000339 /* Free up the arg block that pthread_create malloced. */
340 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
341 VG_USERREQ__FREE, info, 0, 0, 0);
342 assert(res == 0);
343
sewardj7989d0c2002-05-28 11:00:01 +0000344 /* Minimally observe the attributes supplied. */
345 if (attr) {
346 assert(attr->__detachstate == PTHREAD_CREATE_DETACHED
347 || attr->__detachstate == PTHREAD_CREATE_JOINABLE);
348 if (attr->__detachstate == PTHREAD_CREATE_DETACHED)
349 pthread_detach(pthread_self());
350 }
351
sewardj20917d82002-05-28 01:36:45 +0000352 /* The root function might not return. But if it does we simply
353 move along to thread_exit_wrapper. All other ways out for the
354 thread (cancellation, or calling pthread_exit) lead there
355 too. */
356 ret_val = root_fn(arg);
357 thread_exit_wrapper(ret_val);
358 /* NOTREACHED */
359}
360
361
sewardjf8f819e2002-04-17 23:21:37 +0000362/* ---------------------------------------------------
363 THREADs
364 ------------------------------------------------ */
365
sewardjff42d1d2002-05-22 13:17:31 +0000366__attribute__((weak))
367int pthread_yield ( void )
368{
369 int res;
370 ensure_valgrind("pthread_yield");
371 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
372 VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
373 return 0;
374}
375
376
sewardj6072c362002-04-19 14:40:57 +0000377int pthread_equal(pthread_t thread1, pthread_t thread2)
378{
379 return thread1 == thread2 ? 1 : 0;
380}
381
382
sewardj20917d82002-05-28 01:36:45 +0000383/* Bundle up the args into a malloc'd block and create a new thread
384 consisting of thread_wrapper() applied to said malloc'd block. */
sewardje663cb92002-04-12 10:26:32 +0000385int
386pthread_create (pthread_t *__restrict __thread,
387 __const pthread_attr_t *__restrict __attr,
388 void *(*__start_routine) (void *),
389 void *__restrict __arg)
390{
sewardj20917d82002-05-28 01:36:45 +0000391 int tid_child;
392 NewThreadInfo* info;
sewardje663cb92002-04-12 10:26:32 +0000393
sewardj20917d82002-05-28 01:36:45 +0000394 ensure_valgrind("pthread_create");
395
396 /* Allocate space for the arg block. thread_wrapper will free
397 it. */
398 VALGRIND_MAGIC_SEQUENCE(info, NULL /* default */,
399 VG_USERREQ__MALLOC,
400 sizeof(NewThreadInfo), 0, 0, 0);
401 assert(info != NULL);
402
403 info->attr = (pthread_attr_t*)__attr;
404 info->root_fn = __start_routine;
405 info->arg = __arg;
406 VALGRIND_MAGIC_SEQUENCE(tid_child, VG_INVALID_THREADID /* default */,
407 VG_USERREQ__APPLY_IN_NEW_THREAD,
408 &thread_wrapper, info, 0, 0);
409 assert(tid_child != VG_INVALID_THREADID);
410
411 if (__thread)
412 *__thread = tid_child;
413 return 0; /* success */
414}
sewardje663cb92002-04-12 10:26:32 +0000415
416
417int
418pthread_join (pthread_t __th, void **__thread_return)
419{
420 int res;
421 ensure_valgrind("pthread_join");
422 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
423 VG_USERREQ__PTHREAD_JOIN,
424 __th, __thread_return, 0, 0);
425 return res;
426}
427
428
sewardj3b5d8862002-04-20 13:53:23 +0000429void pthread_exit(void *retval)
430{
sewardj3b5d8862002-04-20 13:53:23 +0000431 ensure_valgrind("pthread_exit");
sewardj20917d82002-05-28 01:36:45 +0000432 /* Simple! */
433 thread_exit_wrapper(retval);
sewardj3b5d8862002-04-20 13:53:23 +0000434}
435
sewardje663cb92002-04-12 10:26:32 +0000436
sewardj3b13f0e2002-04-25 20:17:29 +0000437pthread_t pthread_self(void)
sewardje663cb92002-04-12 10:26:32 +0000438{
439 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000440 ensure_valgrind("pthread_self");
sewardj439d45e2002-05-03 20:43:10 +0000441 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardje663cb92002-04-12 10:26:32 +0000442 VG_USERREQ__PTHREAD_GET_THREADID,
443 0, 0, 0, 0);
sewardj439d45e2002-05-03 20:43:10 +0000444 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000445 barf("pthread_self: invalid ThreadId");
446 return tid;
sewardje663cb92002-04-12 10:26:32 +0000447}
448
449
sewardj853f55d2002-04-26 00:27:53 +0000450int pthread_detach(pthread_t th)
451{
sewardj20917d82002-05-28 01:36:45 +0000452 int res;
453 ensure_valgrind("pthread_detach");
sewardj7989d0c2002-05-28 11:00:01 +0000454 /* First we enquire as to the current detach state. */
455 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
sewardj20917d82002-05-28 01:36:45 +0000456 VG_USERREQ__SET_OR_GET_DETACH,
sewardj7989d0c2002-05-28 11:00:01 +0000457 2 /* get */, th, 0, 0);
458 if (res == -1) /* not found */
459 return ESRCH;
460 if (res == 1) /* already detached */
461 return EINVAL;
462 if (res == 0) {
463 VALGRIND_MAGIC_SEQUENCE(res, (-2) /* default */,
464 VG_USERREQ__SET_OR_GET_DETACH,
465 1 /* set */, th, 0, 0);
466 assert(res == 0);
467 return 0;
468 }
469 barf("pthread_detach");
sewardj853f55d2002-04-26 00:27:53 +0000470}
471
472
sewardjf8f819e2002-04-17 23:21:37 +0000473/* ---------------------------------------------------
474 MUTEX ATTRIBUTES
475 ------------------------------------------------ */
476
sewardj5905fae2002-04-26 13:25:00 +0000477int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
sewardje663cb92002-04-12 10:26:32 +0000478{
sewardjf8f819e2002-04-17 23:21:37 +0000479 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000480 return 0;
sewardje663cb92002-04-12 10:26:32 +0000481}
482
sewardj5905fae2002-04-26 13:25:00 +0000483int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
sewardjf8f819e2002-04-17 23:21:37 +0000484{
485 switch (type) {
sewardj3b13f0e2002-04-25 20:17:29 +0000486# ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000487 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000488 case PTHREAD_MUTEX_ADAPTIVE_NP:
sewardj3b13f0e2002-04-25 20:17:29 +0000489# endif
sewardja1679dd2002-05-10 22:31:40 +0000490# ifdef GLIBC_2_1
sewardj68b2dd92002-05-10 21:03:56 +0000491 case PTHREAD_MUTEX_FAST_NP:
sewardja1679dd2002-05-10 22:31:40 +0000492# endif
sewardjf8f819e2002-04-17 23:21:37 +0000493 case PTHREAD_MUTEX_RECURSIVE_NP:
494 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000495 attr->__mutexkind = type;
496 return 0;
497 default:
498 return EINVAL;
499 }
500}
501
sewardj5905fae2002-04-26 13:25:00 +0000502int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
sewardjf8f819e2002-04-17 23:21:37 +0000503{
504 return 0;
505}
506
507
508/* ---------------------------------------------------
509 MUTEXes
510 ------------------------------------------------ */
511
sewardj5905fae2002-04-26 13:25:00 +0000512int __pthread_mutex_init(pthread_mutex_t *mutex,
513 const pthread_mutexattr_t *mutexattr)
sewardje663cb92002-04-12 10:26:32 +0000514{
sewardj604ec3c2002-04-18 22:38:41 +0000515 mutex->__m_count = 0;
516 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
517 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
518 if (mutexattr)
519 mutex->__m_kind = mutexattr->__mutexkind;
520 return 0;
sewardje663cb92002-04-12 10:26:32 +0000521}
522
sewardj439d45e2002-05-03 20:43:10 +0000523
sewardj5905fae2002-04-26 13:25:00 +0000524int __pthread_mutex_lock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000525{
526 int res;
sewardj436e0582002-04-26 14:31:40 +0000527 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000528 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000529 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
530 VG_USERREQ__PTHREAD_MUTEX_LOCK,
531 mutex, 0, 0, 0);
532 return res;
sewardj439d45e2002-05-03 20:43:10 +0000533 } else {
534 if (moans-- > 0)
535 not_inside("pthread_mutex_lock");
536 return 0; /* success */
sewardje663cb92002-04-12 10:26:32 +0000537 }
538}
539
sewardj439d45e2002-05-03 20:43:10 +0000540
sewardj5905fae2002-04-26 13:25:00 +0000541int __pthread_mutex_trylock(pthread_mutex_t *mutex)
sewardj30671ff2002-04-21 00:13:57 +0000542{
543 int res;
sewardj436e0582002-04-26 14:31:40 +0000544 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000545 if (RUNNING_ON_VALGRIND) {
sewardj30671ff2002-04-21 00:13:57 +0000546 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
547 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
548 mutex, 0, 0, 0);
549 return res;
sewardj439d45e2002-05-03 20:43:10 +0000550 } else {
551 if (moans-- > 0)
552 not_inside("pthread_mutex_trylock");
553 return 0;
sewardj30671ff2002-04-21 00:13:57 +0000554 }
555}
556
sewardj439d45e2002-05-03 20:43:10 +0000557
sewardj5905fae2002-04-26 13:25:00 +0000558int __pthread_mutex_unlock(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000559{
560 int res;
sewardj436e0582002-04-26 14:31:40 +0000561 static int moans = N_MOANS;
sewardj439d45e2002-05-03 20:43:10 +0000562 if (RUNNING_ON_VALGRIND) {
sewardje663cb92002-04-12 10:26:32 +0000563 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
564 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
565 mutex, 0, 0, 0);
566 return res;
sewardj439d45e2002-05-03 20:43:10 +0000567 } else {
568 if (moans-- > 0)
569 not_inside("pthread_mutex_unlock");
570 return 0;
sewardje663cb92002-04-12 10:26:32 +0000571 }
572}
573
sewardj439d45e2002-05-03 20:43:10 +0000574
sewardj5905fae2002-04-26 13:25:00 +0000575int __pthread_mutex_destroy(pthread_mutex_t *mutex)
sewardje663cb92002-04-12 10:26:32 +0000576{
sewardj604ec3c2002-04-18 22:38:41 +0000577 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
578 need to involve it. */
579 if (mutex->__m_count > 0)
580 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000581 mutex->__m_count = 0;
582 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
583 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000584 return 0;
sewardje663cb92002-04-12 10:26:32 +0000585}
586
587
sewardjf8f819e2002-04-17 23:21:37 +0000588/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000589 CONDITION VARIABLES
590 ------------------------------------------------ */
591
592/* LinuxThreads supports no attributes for conditions. Hence ... */
593
594int pthread_condattr_init(pthread_condattr_t *attr)
595{
596 return 0;
597}
598
sewardj0738a592002-04-20 13:59:33 +0000599int pthread_condattr_destroy(pthread_condattr_t *attr)
600{
601 return 0;
602}
sewardj6072c362002-04-19 14:40:57 +0000603
604int pthread_cond_init( pthread_cond_t *cond,
605 const pthread_condattr_t *cond_attr)
606{
607 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
608 return 0;
609}
610
sewardjf854f472002-04-21 12:19:41 +0000611int pthread_cond_destroy(pthread_cond_t *cond)
612{
613 /* should check that no threads are waiting on this CV */
sewardj436e0582002-04-26 14:31:40 +0000614 static int moans = N_MOANS;
615 if (moans-- > 0)
616 kludged("pthread_cond_destroy");
sewardjf854f472002-04-21 12:19:41 +0000617 return 0;
618}
sewardj6072c362002-04-19 14:40:57 +0000619
620/* ---------------------------------------------------
621 SCHEDULING
622 ------------------------------------------------ */
623
624/* This is completely bogus. */
625int pthread_getschedparam(pthread_t target_thread,
626 int *policy,
627 struct sched_param *param)
628{
sewardj436e0582002-04-26 14:31:40 +0000629 static int moans = N_MOANS;
630 if (moans-- > 0)
631 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000632 if (policy) *policy = SCHED_OTHER;
sewardj2a1dcce2002-04-22 12:45:25 +0000633# ifdef GLIBC_2_1
634 if (param) param->sched_priority = 0; /* who knows */
635# else
sewardj6072c362002-04-19 14:40:57 +0000636 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000637# endif
sewardj6072c362002-04-19 14:40:57 +0000638 return 0;
639}
640
641int pthread_setschedparam(pthread_t target_thread,
642 int policy,
643 const struct sched_param *param)
644{
sewardj436e0582002-04-26 14:31:40 +0000645 static int moans = N_MOANS;
646 if (moans-- > 0)
647 ignored("pthread_setschedparam");
sewardj6072c362002-04-19 14:40:57 +0000648 return 0;
649}
650
sewardj3b5d8862002-04-20 13:53:23 +0000651int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
652{
653 int res;
654 ensure_valgrind("pthread_cond_wait");
655 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
656 VG_USERREQ__PTHREAD_COND_WAIT,
657 cond, mutex, 0, 0);
658 return res;
659}
660
sewardj5f07b662002-04-23 16:52:51 +0000661int pthread_cond_timedwait ( pthread_cond_t *cond,
662 pthread_mutex_t *mutex,
663 const struct timespec *abstime )
664{
665 int res;
666 unsigned int ms_now, ms_end;
667 struct timeval timeval_now;
668 unsigned long long int ull_ms_now_after_1970;
669 unsigned long long int ull_ms_end_after_1970;
670
671 ensure_valgrind("pthread_cond_timedwait");
672 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
673 VG_USERREQ__READ_MILLISECOND_TIMER,
674 0, 0, 0, 0);
675 assert(ms_now != 0xFFFFFFFF);
676 res = gettimeofday(&timeval_now, NULL);
677 assert(res == 0);
678
679 ull_ms_now_after_1970
680 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
681 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
682 ull_ms_end_after_1970
683 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
684 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
685 assert(ull_ms_end_after_1970 >= ull_ms_now_after_1970);
686 ms_end
687 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
688 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
689 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
690 cond, mutex, ms_end, 0);
691 return res;
692}
693
694
sewardj3b5d8862002-04-20 13:53:23 +0000695int pthread_cond_signal(pthread_cond_t *cond)
696{
697 int res;
698 ensure_valgrind("pthread_cond_signal");
699 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
700 VG_USERREQ__PTHREAD_COND_SIGNAL,
701 cond, 0, 0, 0);
702 return res;
703}
704
705int pthread_cond_broadcast(pthread_cond_t *cond)
706{
707 int res;
708 ensure_valgrind("pthread_cond_broadcast");
709 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
710 VG_USERREQ__PTHREAD_COND_BROADCAST,
711 cond, 0, 0, 0);
712 return res;
713}
714
sewardj6072c362002-04-19 14:40:57 +0000715
716/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000717 CANCELLATION
718 ------------------------------------------------ */
719
sewardj853f55d2002-04-26 00:27:53 +0000720int pthread_setcancelstate(int state, int *oldstate)
721{
sewardj20917d82002-05-28 01:36:45 +0000722 int res;
723 ensure_valgrind("pthread_setcancelstate");
724 if (state != PTHREAD_CANCEL_ENABLE
725 && state != PTHREAD_CANCEL_DISABLE)
726 return EINVAL;
727 assert(-1 != PTHREAD_CANCEL_ENABLE);
728 assert(-1 != PTHREAD_CANCEL_DISABLE);
729 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
730 VG_USERREQ__SET_CANCELSTATE,
731 state, 0, 0, 0);
732 assert(res != -1);
733 if (oldstate)
734 *oldstate = res;
sewardj853f55d2002-04-26 00:27:53 +0000735 return 0;
736}
737
sewardje663cb92002-04-12 10:26:32 +0000738int pthread_setcanceltype(int type, int *oldtype)
739{
sewardj20917d82002-05-28 01:36:45 +0000740 int res;
741 ensure_valgrind("pthread_setcanceltype");
742 if (type != PTHREAD_CANCEL_DEFERRED
743 && type != PTHREAD_CANCEL_ASYNCHRONOUS)
744 return EINVAL;
745 assert(-1 != PTHREAD_CANCEL_DEFERRED);
746 assert(-1 != PTHREAD_CANCEL_ASYNCHRONOUS);
747 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
748 VG_USERREQ__SET_CANCELTYPE,
749 type, 0, 0, 0);
750 assert(res != -1);
751 if (oldtype)
752 *oldtype = res;
sewardje663cb92002-04-12 10:26:32 +0000753 return 0;
754}
755
sewardje663cb92002-04-12 10:26:32 +0000756int pthread_cancel(pthread_t thread)
757{
758 int res;
759 ensure_valgrind("pthread_cancel");
sewardj20917d82002-05-28 01:36:45 +0000760 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
761 VG_USERREQ__SET_CANCELPEND,
762 thread, &thread_exit_wrapper, 0, 0);
763 assert(res != -1);
sewardje663cb92002-04-12 10:26:32 +0000764 return res;
765}
766
sewardj20917d82002-05-28 01:36:45 +0000767__inline__
sewardj853f55d2002-04-26 00:27:53 +0000768void pthread_testcancel(void)
769{
sewardj20917d82002-05-28 01:36:45 +0000770 int res;
771 VALGRIND_MAGIC_SEQUENCE(res, (-1) /* default */,
772 VG_USERREQ__TESTCANCEL,
773 0, 0, 0, 0);
774 assert(res == 0);
sewardj853f55d2002-04-26 00:27:53 +0000775}
776
sewardj20917d82002-05-28 01:36:45 +0000777
sewardj853f55d2002-04-26 00:27:53 +0000778/*-------------------*/
779static pthread_mutex_t massacre_mx = PTHREAD_MUTEX_INITIALIZER;
780
781void __pthread_kill_other_threads_np ( void )
782{
783 int i, res, me;
sewardj68b2dd92002-05-10 21:03:56 +0000784 __pthread_mutex_lock(&massacre_mx);
sewardj853f55d2002-04-26 00:27:53 +0000785 me = pthread_self();
786 for (i = 1; i < VG_N_THREADS; i++) {
787 if (i == me) continue;
788 res = pthread_cancel(i);
sewardj436e0582002-04-26 14:31:40 +0000789 if (0 && res == 0)
sewardj853f55d2002-04-26 00:27:53 +0000790 printf("----------- NUKED %d\n", i);
791 }
sewardj68b2dd92002-05-10 21:03:56 +0000792 __pthread_mutex_unlock(&massacre_mx);
sewardj853f55d2002-04-26 00:27:53 +0000793}
794
sewardje663cb92002-04-12 10:26:32 +0000795
sewardjf8f819e2002-04-17 23:21:37 +0000796/* ---------------------------------------------------
sewardjb48e5002002-05-13 00:16:03 +0000797 SIGNALS
798 ------------------------------------------------ */
799
800#include <signal.h>
801
802int pthread_sigmask(int how, const sigset_t *newmask,
803 sigset_t *oldmask)
804{
805 int res;
806
807 /* A bit subtle, because the scheduler expects newmask and oldmask
808 to be vki_sigset_t* rather than sigset_t*, and the two are
809 different. Fortunately the first 64 bits of a sigset_t are
810 exactly a vki_sigset_t, so we just pass the pointers through
811 unmodified. Haaaack!
812
813 Also mash the how value so that the SIG_ constants from glibc
sewardj018f7622002-05-15 21:13:39 +0000814 constants to VKI_ constants, so that the former do not have to
815 be included into vg_scheduler.c. */
sewardjb48e5002002-05-13 00:16:03 +0000816
817 ensure_valgrind("pthread_sigmask");
818
819 switch (how) {
sewardj018f7622002-05-15 21:13:39 +0000820 case SIG_SETMASK: how = VKI_SIG_SETMASK; break;
821 case SIG_BLOCK: how = VKI_SIG_BLOCK; break;
822 case SIG_UNBLOCK: how = VKI_SIG_UNBLOCK; break;
sewardjb48e5002002-05-13 00:16:03 +0000823 default: return EINVAL;
824 }
825
826 /* Crude check */
827 if (newmask == NULL)
828 return EFAULT;
829
830 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
831 VG_USERREQ__PTHREAD_SIGMASK,
832 how, newmask, oldmask, 0);
833
834 /* The scheduler tells us of any memory violations. */
835 return res == 0 ? 0 : EFAULT;
836}
837
838
839int sigwait ( const sigset_t* set, int* sig )
840{
841 int res;
842 ensure_valgrind("sigwait");
843 /* As with pthread_sigmask we deliberately confuse sigset_t with
844 vki_ksigset_t. */
845 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
846 VG_USERREQ__SIGWAIT,
847 set, sig, 0, 0);
848 return res;
849}
850
851
sewardj018f7622002-05-15 21:13:39 +0000852int pthread_kill(pthread_t thread, int signo)
853{
854 int res;
855 ensure_valgrind("pthread_kill");
856 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
857 VG_USERREQ__PTHREAD_KILL,
858 thread, signo, 0, 0);
859 return res;
860}
861
862
sewardj3665ded2002-05-16 16:57:25 +0000863/* Copied verbatim from Linuxthreads */
864/* Redefine raise() to send signal to calling thread only,
865 as per POSIX 1003.1c */
866int raise (int sig)
867{
868 int retcode = pthread_kill(pthread_self(), sig);
869 if (retcode == 0)
870 return 0;
871 else {
872 errno = retcode;
873 return -1;
874 }
875}
876
877
sewardjb48e5002002-05-13 00:16:03 +0000878/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000879 THREAD-SPECIFICs
880 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000881
sewardj5905fae2002-04-26 13:25:00 +0000882int __pthread_key_create(pthread_key_t *key,
883 void (*destr_function) (void *))
sewardj5e5fa512002-04-14 13:13:05 +0000884{
sewardj5f07b662002-04-23 16:52:51 +0000885 int res;
886 ensure_valgrind("pthread_key_create");
887 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
888 VG_USERREQ__PTHREAD_KEY_CREATE,
889 key, destr_function, 0, 0);
890 return res;
sewardj5e5fa512002-04-14 13:13:05 +0000891}
892
893int pthread_key_delete(pthread_key_t key)
894{
sewardj436e0582002-04-26 14:31:40 +0000895 static int moans = N_MOANS;
896 if (moans-- > 0)
897 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000898 return 0;
899}
900
sewardj5905fae2002-04-26 13:25:00 +0000901int __pthread_setspecific(pthread_key_t key, const void *pointer)
sewardj5e5fa512002-04-14 13:13:05 +0000902{
sewardj5f07b662002-04-23 16:52:51 +0000903 int res;
904 ensure_valgrind("pthread_setspecific");
905 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
906 VG_USERREQ__PTHREAD_SETSPECIFIC,
907 key, pointer, 0, 0);
908 return res;
sewardj5e5fa512002-04-14 13:13:05 +0000909}
910
sewardj5905fae2002-04-26 13:25:00 +0000911void * __pthread_getspecific(pthread_key_t key)
sewardj5e5fa512002-04-14 13:13:05 +0000912{
sewardj5f07b662002-04-23 16:52:51 +0000913 int res;
914 ensure_valgrind("pthread_getspecific");
915 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
916 VG_USERREQ__PTHREAD_GETSPECIFIC,
917 key, 0 , 0, 0);
918 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +0000919}
920
sewardjf8f819e2002-04-17 23:21:37 +0000921
922/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +0000923 ONCEry
924 ------------------------------------------------ */
925
926static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
927
928
sewardj5905fae2002-04-26 13:25:00 +0000929int __pthread_once ( pthread_once_t *once_control,
930 void (*init_routine) (void) )
sewardj89d3d852002-04-24 19:21:39 +0000931{
932 int res;
933 ensure_valgrind("pthread_once");
934
sewardj68b2dd92002-05-10 21:03:56 +0000935 res = __pthread_mutex_lock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +0000936
sewardj68b2dd92002-05-10 21:03:56 +0000937 if (res != 0) {
938 printf("res = %d\n",res);
sewardj89d3d852002-04-24 19:21:39 +0000939 barf("pthread_once: Looks like your program's "
940 "init routine calls back to pthread_once() ?!");
sewardj68b2dd92002-05-10 21:03:56 +0000941 }
sewardj89d3d852002-04-24 19:21:39 +0000942
943 if (*once_control == 0) {
944 *once_control = 1;
945 init_routine();
946 }
947
sewardj68b2dd92002-05-10 21:03:56 +0000948 __pthread_mutex_unlock(&once_masterlock);
sewardj89d3d852002-04-24 19:21:39 +0000949
950 return 0;
951}
952
953
954/* ---------------------------------------------------
sewardj853f55d2002-04-26 00:27:53 +0000955 MISC
956 ------------------------------------------------ */
957
sewardj5905fae2002-04-26 13:25:00 +0000958int __pthread_atfork ( void (*prepare)(void),
959 void (*parent)(void),
960 void (*child)(void) )
sewardj853f55d2002-04-26 00:27:53 +0000961{
sewardj436e0582002-04-26 14:31:40 +0000962 static int moans = N_MOANS;
963 if (moans-- > 0)
964 ignored("pthread_atfork");
sewardj853f55d2002-04-26 00:27:53 +0000965 return 0;
966}
967
968
sewardjbb990782002-05-08 02:01:14 +0000969__attribute__((weak))
970void __pthread_initialize ( void )
971{
sewardjbea1caa2002-05-10 23:20:58 +0000972 ensure_valgrind("__pthread_initialize");
sewardjbb990782002-05-08 02:01:14 +0000973}
974
975
sewardj853f55d2002-04-26 00:27:53 +0000976/* ---------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +0000977 LIBRARY-PRIVATE THREAD SPECIFIC STATE
sewardjf8f819e2002-04-17 23:21:37 +0000978 ------------------------------------------------ */
979
sewardj3b13f0e2002-04-25 20:17:29 +0000980#include <resolv.h>
981static int thread_specific_errno[VG_N_THREADS];
982static int thread_specific_h_errno[VG_N_THREADS];
983static struct __res_state
984 thread_specific_res_state[VG_N_THREADS];
sewardjf8f819e2002-04-17 23:21:37 +0000985
sewardj3b13f0e2002-04-25 20:17:29 +0000986int* __errno_location ( void )
sewardjf8f819e2002-04-17 23:21:37 +0000987{
988 int tid;
sewardj3b13f0e2002-04-25 20:17:29 +0000989 /* ensure_valgrind("__errno_location"); */
990 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
sewardjf8f819e2002-04-17 23:21:37 +0000991 VG_USERREQ__PTHREAD_GET_THREADID,
992 0, 0, 0, 0);
sewardj3b13f0e2002-04-25 20:17:29 +0000993 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +0000994 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +0000995 barf("__errno_location: invalid ThreadId");
996 return & thread_specific_errno[tid];
997}
998
999int* __h_errno_location ( void )
1000{
1001 int tid;
1002 /* ensure_valgrind("__h_errno_location"); */
1003 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1004 VG_USERREQ__PTHREAD_GET_THREADID,
1005 0, 0, 0, 0);
1006 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001007 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001008 barf("__h_errno_location: invalid ThreadId");
1009 return & thread_specific_h_errno[tid];
1010}
1011
1012struct __res_state* __res_state ( void )
1013{
1014 int tid;
1015 /* ensure_valgrind("__res_state"); */
1016 VALGRIND_MAGIC_SEQUENCE(tid, 1 /* default */,
1017 VG_USERREQ__PTHREAD_GET_THREADID,
1018 0, 0, 0, 0);
1019 /* 'cos I'm paranoid ... */
sewardj439d45e2002-05-03 20:43:10 +00001020 if (tid < 1 || tid >= VG_N_THREADS)
sewardj3b13f0e2002-04-25 20:17:29 +00001021 barf("__res_state: invalid ThreadId");
1022 return & thread_specific_res_state[tid];
sewardjf8f819e2002-04-17 23:21:37 +00001023}
1024
1025
sewardj5716dbb2002-04-26 03:28:18 +00001026/* ---------------------------------------------------
1027 LIBC-PRIVATE SPECIFIC DATA
1028 ------------------------------------------------ */
1029
1030/* Relies on assumption that initial private data is NULL. This
1031 should be fixed somehow. */
1032
1033/* The allowable keys (indices) (all 2 of them).
1034 From sysdeps/pthread/bits/libc-tsd.h
1035*/
sewardj70adeb22002-04-27 01:35:38 +00001036#define N_LIBC_TSD_EXTRA_KEYS 1
1037
sewardj5716dbb2002-04-26 03:28:18 +00001038enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
1039 _LIBC_TSD_KEY_DL_ERROR,
1040 _LIBC_TSD_KEY_N };
1041
1042/* Auto-initialising subsystem. libc_specifics_inited is set
1043 after initialisation. libc_specifics_inited_mx guards it. */
1044static int libc_specifics_inited = 0;
1045static pthread_mutex_t libc_specifics_inited_mx = PTHREAD_MUTEX_INITIALIZER;
1046
1047/* These are the keys we must initialise the first time. */
sewardj70adeb22002-04-27 01:35:38 +00001048static pthread_key_t libc_specifics_keys[_LIBC_TSD_KEY_N
1049 + N_LIBC_TSD_EXTRA_KEYS];
sewardj5716dbb2002-04-26 03:28:18 +00001050
1051/* Initialise the keys, if they are not already initialise. */
1052static
1053void init_libc_tsd_keys ( void )
1054{
1055 int res, i;
1056 pthread_key_t k;
1057
1058 res = pthread_mutex_lock(&libc_specifics_inited_mx);
1059 if (res != 0) barf("init_libc_tsd_keys: lock");
1060
1061 if (libc_specifics_inited == 0) {
1062 /* printf("INIT libc specifics\n"); */
1063 libc_specifics_inited = 1;
sewardj70adeb22002-04-27 01:35:38 +00001064 for (i = 0; i < _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS; i++) {
sewardj5716dbb2002-04-26 03:28:18 +00001065 res = pthread_key_create(&k, NULL);
1066 if (res != 0) barf("init_libc_tsd_keys: create");
1067 libc_specifics_keys[i] = k;
1068 }
1069 }
1070
1071 res = pthread_mutex_unlock(&libc_specifics_inited_mx);
1072 if (res != 0) barf("init_libc_tsd_keys: unlock");
1073}
1074
1075
1076static int
1077libc_internal_tsd_set ( enum __libc_tsd_key_t key,
1078 const void * pointer )
1079{
sewardj70adeb22002-04-27 01:35:38 +00001080 int res;
1081 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001082 /* printf("SET SET SET key %d ptr %p\n", key, pointer); */
sewardj70adeb22002-04-27 01:35:38 +00001083 if (key < _LIBC_TSD_KEY_MALLOC
1084 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001085 barf("libc_internal_tsd_set: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001086 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1087 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001088 "valgrind's libpthread.so: libc_internal_tsd_set: "
1089 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001090 init_libc_tsd_keys();
1091 res = pthread_setspecific(libc_specifics_keys[key], pointer);
1092 if (res != 0) barf("libc_internal_tsd_set: setspecific failed");
1093 return 0;
1094}
1095
1096static void *
1097libc_internal_tsd_get ( enum __libc_tsd_key_t key )
1098{
sewardj70adeb22002-04-27 01:35:38 +00001099 void* v;
1100 static int moans = N_MOANS;
sewardj5716dbb2002-04-26 03:28:18 +00001101 /* printf("GET GET GET key %d\n", key); */
sewardj70adeb22002-04-27 01:35:38 +00001102 if (key < _LIBC_TSD_KEY_MALLOC
1103 || key >= _LIBC_TSD_KEY_N + N_LIBC_TSD_EXTRA_KEYS)
sewardj5716dbb2002-04-26 03:28:18 +00001104 barf("libc_internal_tsd_get: invalid key");
sewardj70adeb22002-04-27 01:35:38 +00001105 if (key >= _LIBC_TSD_KEY_N && moans-- > 0)
1106 fprintf(stderr,
sewardj439d45e2002-05-03 20:43:10 +00001107 "valgrind's libpthread.so: libc_internal_tsd_get: "
1108 "dubious key %d\n", key);
sewardj5716dbb2002-04-26 03:28:18 +00001109 init_libc_tsd_keys();
1110 v = pthread_getspecific(libc_specifics_keys[key]);
1111 /* if (v == NULL) barf("libc_internal_tsd_set: getspecific failed"); */
1112 return v;
1113}
1114
1115
1116
1117
sewardj70adeb22002-04-27 01:35:38 +00001118int (*__libc_internal_tsd_set)
1119 (enum __libc_tsd_key_t key, const void * pointer)
1120 = libc_internal_tsd_set;
sewardj5716dbb2002-04-26 03:28:18 +00001121
sewardj70adeb22002-04-27 01:35:38 +00001122void* (*__libc_internal_tsd_get)
1123 (enum __libc_tsd_key_t key)
1124 = libc_internal_tsd_get;
sewardj5716dbb2002-04-26 03:28:18 +00001125
1126
sewardje663cb92002-04-12 10:26:32 +00001127/* ---------------------------------------------------------------------
1128 These are here (I think) because they are deemed cancellation
1129 points by POSIX. For the moment we'll simply pass the call along
1130 to the corresponding thread-unaware (?) libc routine.
1131 ------------------------------------------------------------------ */
1132
sewardje663cb92002-04-12 10:26:32 +00001133#include <stdlib.h>
sewardje663cb92002-04-12 10:26:32 +00001134#include <sys/types.h>
1135#include <sys/socket.h>
1136
sewardjd529a442002-05-04 19:49:21 +00001137#ifdef GLIBC_2_1
1138extern
1139int __sigaction
1140 (int signum,
1141 const struct sigaction *act,
1142 struct sigaction *oldact);
1143#else
sewardje663cb92002-04-12 10:26:32 +00001144extern
1145int __libc_sigaction
1146 (int signum,
1147 const struct sigaction *act,
1148 struct sigaction *oldact);
sewardjd529a442002-05-04 19:49:21 +00001149#endif
sewardje663cb92002-04-12 10:26:32 +00001150int sigaction(int signum,
1151 const struct sigaction *act,
1152 struct sigaction *oldact)
1153{
sewardj2a1dcce2002-04-22 12:45:25 +00001154# ifdef GLIBC_2_1
1155 return __sigaction(signum, act, oldact);
1156# else
sewardj45b4b372002-04-16 22:50:32 +00001157 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +00001158# endif
sewardje663cb92002-04-12 10:26:32 +00001159}
1160
1161
1162extern
1163int __libc_connect(int sockfd,
1164 const struct sockaddr *serv_addr,
1165 socklen_t addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001166__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001167int connect(int sockfd,
1168 const struct sockaddr *serv_addr,
1169 socklen_t addrlen)
1170{
sewardj45b4b372002-04-16 22:50:32 +00001171 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001172}
1173
1174
1175extern
1176int __libc_fcntl(int fd, int cmd, long arg);
sewardj5905fae2002-04-26 13:25:00 +00001177__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001178int fcntl(int fd, int cmd, long arg)
1179{
sewardj45b4b372002-04-16 22:50:32 +00001180 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +00001181}
1182
1183
1184extern
1185ssize_t __libc_write(int fd, const void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001186__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001187ssize_t write(int fd, const void *buf, size_t count)
1188{
sewardj45b4b372002-04-16 22:50:32 +00001189 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001190}
1191
1192
1193extern
1194ssize_t __libc_read(int fd, void *buf, size_t count);
sewardj5905fae2002-04-26 13:25:00 +00001195__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001196ssize_t read(int fd, void *buf, size_t count)
1197{
sewardj45b4b372002-04-16 22:50:32 +00001198 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +00001199}
1200
sewardjbe32e452002-04-24 20:29:58 +00001201
1202extern
sewardj853f55d2002-04-26 00:27:53 +00001203int __libc_open64(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001204__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001205int open64(const char *pathname, int flags, mode_t mode)
sewardjbe32e452002-04-24 20:29:58 +00001206{
sewardj853f55d2002-04-26 00:27:53 +00001207 return __libc_open64(pathname, flags, mode);
sewardjbe32e452002-04-24 20:29:58 +00001208}
1209
sewardje663cb92002-04-12 10:26:32 +00001210
1211extern
sewardj853f55d2002-04-26 00:27:53 +00001212int __libc_open(const char *pathname, int flags, mode_t mode);
sewardj5905fae2002-04-26 13:25:00 +00001213__attribute__((weak))
sewardj853f55d2002-04-26 00:27:53 +00001214int open(const char *pathname, int flags, mode_t mode)
sewardje663cb92002-04-12 10:26:32 +00001215{
sewardj853f55d2002-04-26 00:27:53 +00001216 return __libc_open(pathname, flags, mode);
sewardje663cb92002-04-12 10:26:32 +00001217}
1218
1219
1220extern
1221int __libc_close(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001222__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001223int close(int fd)
1224{
sewardj45b4b372002-04-16 22:50:32 +00001225 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +00001226}
1227
1228
1229extern
1230int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
sewardj5905fae2002-04-26 13:25:00 +00001231__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001232int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1233{
sewardj705d3cb2002-05-23 13:13:12 +00001234 wait_for_fd_to_be_readable_or_erring(s);
sewardj45b4b372002-04-16 22:50:32 +00001235 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +00001236}
1237
1238
1239extern
1240pid_t __libc_fork(void);
sewardj5905fae2002-04-26 13:25:00 +00001241pid_t __fork(void)
sewardje663cb92002-04-12 10:26:32 +00001242{
sewardj45b4b372002-04-16 22:50:32 +00001243 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +00001244}
1245
1246
1247extern
1248pid_t __libc_waitpid(pid_t pid, int *status, int options);
sewardj5905fae2002-04-26 13:25:00 +00001249__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001250pid_t waitpid(pid_t pid, int *status, int options)
1251{
sewardj45b4b372002-04-16 22:50:32 +00001252 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +00001253}
1254
1255
1256extern
1257int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
sewardj5905fae2002-04-26 13:25:00 +00001258__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001259int nanosleep(const struct timespec *req, struct timespec *rem)
1260{
1261 return __libc_nanosleep(req, rem);
1262}
1263
sewardjbe32e452002-04-24 20:29:58 +00001264
sewardje663cb92002-04-12 10:26:32 +00001265extern
1266int __libc_fsync(int fd);
sewardj5905fae2002-04-26 13:25:00 +00001267__attribute__((weak))
sewardje663cb92002-04-12 10:26:32 +00001268int fsync(int fd)
1269{
sewardj45b4b372002-04-16 22:50:32 +00001270 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +00001271}
1272
sewardjbe32e452002-04-24 20:29:58 +00001273
sewardj70c75362002-04-13 04:18:32 +00001274extern
1275off_t __libc_lseek(int fildes, off_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001276__attribute__((weak))
sewardj70c75362002-04-13 04:18:32 +00001277off_t lseek(int fildes, off_t offset, int whence)
1278{
sewardj45b4b372002-04-16 22:50:32 +00001279 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +00001280}
1281
sewardjbe32e452002-04-24 20:29:58 +00001282
1283extern
1284__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
sewardj5905fae2002-04-26 13:25:00 +00001285__attribute__((weak))
sewardjbe32e452002-04-24 20:29:58 +00001286__off64_t lseek64(int fildes, __off64_t offset, int whence)
1287{
1288 return __libc_lseek64(fildes, offset, whence);
1289}
1290
1291
sewardj726c4122002-05-16 23:39:10 +00001292extern
1293ssize_t __libc_pread64 (int __fd, void *__buf, size_t __nbytes,
1294 __off64_t __offset);
1295ssize_t __pread64 (int __fd, void *__buf, size_t __nbytes,
1296 __off64_t __offset)
1297{
1298 return __libc_pread64(__fd, __buf, __nbytes, __offset);
1299}
1300
1301
sewardja18e2102002-05-18 10:43:22 +00001302extern
1303ssize_t __libc_pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1304 __off64_t __offset);
1305ssize_t __pwrite64 (int __fd, const void *__buf, size_t __nbytes,
1306 __off64_t __offset)
1307{
1308 return __libc_pwrite64(__fd, __buf, __nbytes, __offset);
1309}
1310
sewardj726c4122002-05-16 23:39:10 +00001311
sewardj39b93b12002-05-18 10:56:27 +00001312extern
1313ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset);
1314__attribute__((weak))
1315ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
1316{
1317 return __libc_pwrite(fd, buf, count, offset);
1318}
1319
1320
1321extern
1322ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset);
1323__attribute__((weak))
1324ssize_t pread(int fd, void *buf, size_t count, off_t offset)
1325{
1326 return __libc_pread(fd, buf, count, offset);
1327}
1328
1329
sewardj6af4b5d2002-04-16 04:40:49 +00001330extern
1331void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
sewardj5905fae2002-04-26 13:25:00 +00001332/* not weak: __attribute__((weak)) */
sewardj6af4b5d2002-04-16 04:40:49 +00001333void longjmp(jmp_buf env, int val)
1334{
1335 __libc_longjmp(env, val);
1336}
1337
sewardjbe32e452002-04-24 20:29:58 +00001338
sewardj6af4b5d2002-04-16 04:40:49 +00001339extern
1340int __libc_send(int s, const void *msg, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001341__attribute__((weak))
sewardj6af4b5d2002-04-16 04:40:49 +00001342int send(int s, const void *msg, size_t len, int flags)
1343{
1344 return __libc_send(s, msg, len, flags);
1345}
1346
sewardjbe32e452002-04-24 20:29:58 +00001347
sewardj1e8cdc92002-04-18 11:37:52 +00001348extern
1349int __libc_recv(int s, void *buf, size_t len, int flags);
sewardj5905fae2002-04-26 13:25:00 +00001350__attribute__((weak))
sewardj1e8cdc92002-04-18 11:37:52 +00001351int recv(int s, void *buf, size_t len, int flags)
1352{
1353 return __libc_recv(s, buf, len, flags);
1354}
1355
sewardjbe32e452002-04-24 20:29:58 +00001356
sewardj3665ded2002-05-16 16:57:25 +00001357extern
1358int __libc_sendmsg(int s, const struct msghdr *msg, int flags);
1359__attribute__((weak))
1360int sendmsg(int s, const struct msghdr *msg, int flags)
1361{
1362 return __libc_sendmsg(s, msg, flags);
1363}
1364
1365
sewardj796d6a22002-04-24 02:28:34 +00001366extern
sewardj436e0582002-04-26 14:31:40 +00001367int __libc_recvfrom(int s, void *buf, size_t len, int flags,
1368 struct sockaddr *from, socklen_t *fromlen);
1369__attribute__((weak))
1370int recvfrom(int s, void *buf, size_t len, int flags,
1371 struct sockaddr *from, socklen_t *fromlen)
1372{
1373 return __libc_recvfrom(s, buf, len, flags, from, fromlen);
1374}
1375
1376
1377extern
sewardj796d6a22002-04-24 02:28:34 +00001378int __libc_sendto(int s, const void *msg, size_t len, int flags,
1379 const struct sockaddr *to, socklen_t tolen);
sewardj5905fae2002-04-26 13:25:00 +00001380__attribute__((weak))
sewardj796d6a22002-04-24 02:28:34 +00001381int sendto(int s, const void *msg, size_t len, int flags,
1382 const struct sockaddr *to, socklen_t tolen)
1383{
1384 return __libc_sendto(s, msg, len, flags, to, tolen);
1385}
1386
sewardjbe32e452002-04-24 20:29:58 +00001387
sewardj369b1702002-04-24 13:28:15 +00001388extern
1389int __libc_system(const char* str);
sewardj5905fae2002-04-26 13:25:00 +00001390__attribute__((weak))
sewardj369b1702002-04-24 13:28:15 +00001391int system(const char* str)
1392{
1393 return __libc_system(str);
1394}
1395
sewardjbe32e452002-04-24 20:29:58 +00001396
sewardjab0b1c32002-04-24 19:26:47 +00001397extern
1398pid_t __libc_wait(int *status);
sewardj5905fae2002-04-26 13:25:00 +00001399__attribute__((weak))
sewardjab0b1c32002-04-24 19:26:47 +00001400pid_t wait(int *status)
1401{
1402 return __libc_wait(status);
1403}
1404
sewardj45b4b372002-04-16 22:50:32 +00001405
sewardj67f1d582002-05-24 02:11:32 +00001406extern
1407int __libc_msync(const void *start, size_t length, int flags);
1408__attribute__((weak))
1409int msync(const void *start, size_t length, int flags)
1410{
1411 return __libc_msync(start, length, flags);
1412}
1413
sewardj5905fae2002-04-26 13:25:00 +00001414
sewardj3b13f0e2002-04-25 20:17:29 +00001415/* ---------------------------------------------------------------------
1416 Nonblocking implementations of select() and poll(). This stuff will
1417 surely rot your mind.
1418 ------------------------------------------------------------------ */
sewardje663cb92002-04-12 10:26:32 +00001419
sewardj08a4c3f2002-04-13 03:45:44 +00001420/*--------------------------------------------------*/
1421
1422#include "vg_kerneliface.h"
1423
1424static
1425__inline__
1426int is_kerror ( int res )
1427{
1428 if (res >= -4095 && res <= -1)
1429 return 1;
1430 else
1431 return 0;
1432}
1433
1434
1435static
1436int my_do_syscall1 ( int syscallno, int arg1 )
1437{
1438 int __res;
1439 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1440 : "=a" (__res)
1441 : "0" (syscallno),
1442 "d" (arg1) );
1443 return __res;
1444}
1445
1446static
1447int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +00001448 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +00001449{
1450 int __res;
1451 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
1452 : "=a" (__res)
1453 : "0" (syscallno),
1454 "d" (arg1),
1455 "c" (arg2) );
1456 return __res;
1457}
1458
1459static
sewardjf854f472002-04-21 12:19:41 +00001460int my_do_syscall3 ( int syscallno,
1461 int arg1, int arg2, int arg3 )
1462{
1463 int __res;
1464 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
1465 : "=a" (__res)
1466 : "0" (syscallno),
1467 "S" (arg1),
1468 "c" (arg2),
1469 "d" (arg3) );
1470 return __res;
1471}
1472
1473static
sewardj08a4c3f2002-04-13 03:45:44 +00001474int do_syscall_select( int n,
1475 vki_fd_set* readfds,
1476 vki_fd_set* writefds,
1477 vki_fd_set* exceptfds,
1478 struct vki_timeval * timeout )
1479{
1480 int res;
1481 int args[5];
1482 args[0] = n;
1483 args[1] = (int)readfds;
1484 args[2] = (int)writefds;
1485 args[3] = (int)exceptfds;
1486 args[4] = (int)timeout;
1487 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +00001488 return res;
sewardj08a4c3f2002-04-13 03:45:44 +00001489}
1490
1491
1492/* This is a wrapper round select(), which makes it thread-safe,
1493 meaning that only this thread will block, rather than the entire
1494 process. This wrapper in turn depends on nanosleep() not to block
1495 the entire process, but I think (hope? suspect?) that POSIX
1496 pthreads guarantees that to be the case.
1497
1498 Basic idea is: modify the timeout parameter to select so that it
1499 returns immediately. Poll like this until select returns non-zero,
1500 indicating something interesting happened, or until our time is up.
1501 Space out the polls with nanosleeps of say 20 milliseconds, which
1502 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +00001503
1504 Assumes:
1505 * (checked via assert) types fd_set and vki_fd_set are identical.
1506 * (checked via assert) types timeval and vki_timeval are identical.
1507 * (unchecked) libc error numbers (EINTR etc) are the negation of the
1508 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +00001509*/
sewardj08a4c3f2002-04-13 03:45:44 +00001510
sewardj5905fae2002-04-26 13:25:00 +00001511/* __attribute__((weak)) */
sewardj08a4c3f2002-04-13 03:45:44 +00001512int select ( int n,
1513 fd_set *rfds,
1514 fd_set *wfds,
1515 fd_set *xfds,
1516 struct timeval *timeout )
1517{
sewardj5f07b662002-04-23 16:52:51 +00001518 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +00001519 int res;
1520 fd_set rfds_copy;
1521 fd_set wfds_copy;
1522 fd_set xfds_copy;
1523 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +00001524 struct vki_timeval zero_timeout;
1525 struct vki_timespec nanosleep_interval;
1526
sewardj5f07b662002-04-23 16:52:51 +00001527 /* gcc's complains about ms_end being used uninitialised -- classic
1528 case it can't understand, where ms_end is both defined and used
1529 only if timeout != NULL. Hence ... */
1530 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +00001531
1532 /* We assume that the kernel and libc data layouts are identical
1533 for the following types. These asserts provide a crude
1534 check. */
1535 if (sizeof(fd_set) != sizeof(vki_fd_set)
1536 || sizeof(struct timeval) != sizeof(struct vki_timeval))
1537 barf("valgrind's hacky non-blocking select(): data sizes error");
1538
sewardj5f07b662002-04-23 16:52:51 +00001539 /* Detect the current time and simultaneously find out if we are
1540 running on Valgrind. */
1541 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1542 VG_USERREQ__READ_MILLISECOND_TIMER,
1543 0, 0, 0, 0);
1544
1545 /* If a zero timeout specified, this call is harmless. Also go
1546 this route if we're not running on Valgrind, for whatever
1547 reason. */
1548 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
1549 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +00001550 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +00001551 (vki_fd_set*)wfds,
1552 (vki_fd_set*)xfds,
1553 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +00001554 if (is_kerror(res)) {
1555 * (__errno_location()) = -res;
1556 return -1;
1557 } else {
1558 return res;
1559 }
1560 }
sewardj08a4c3f2002-04-13 03:45:44 +00001561
sewardj5f07b662002-04-23 16:52:51 +00001562 /* If a timeout was specified, set ms_end to be the end millisecond
1563 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001564 if (timeout) {
1565 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
1566 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +00001567 ms_end = ms_now;
1568 ms_end += (timeout->tv_usec / 1000);
1569 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +00001570 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +00001571 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +00001572 }
1573
1574 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
1575
1576 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +00001577 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +00001578 while (1) {
1579 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +00001580 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1581 VG_USERREQ__READ_MILLISECOND_TIMER,
1582 0, 0, 0, 0);
1583 assert(ms_now != 0xFFFFFFFF);
1584 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +00001585 /* timeout; nothing interesting happened. */
1586 if (rfds) FD_ZERO(rfds);
1587 if (wfds) FD_ZERO(wfds);
1588 if (xfds) FD_ZERO(xfds);
1589 return 0;
1590 }
1591 }
1592
1593 /* These could be trashed each time round the loop, so restore
1594 them each time. */
1595 if (rfds) rfds_copy = *rfds;
1596 if (wfds) wfds_copy = *wfds;
1597 if (xfds) xfds_copy = *xfds;
1598
1599 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1600
1601 res = do_syscall_select( n,
1602 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1603 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1604 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1605 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001606 if (is_kerror(res)) {
1607 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001608 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001609 * (__errno_location()) = -res;
1610 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001611 }
1612 if (res > 0) {
1613 /* one or more fds is ready. Copy out resulting sets and
1614 return. */
1615 if (rfds) *rfds = rfds_copy;
1616 if (wfds) *wfds = wfds_copy;
1617 if (xfds) *xfds = xfds_copy;
1618 return res;
1619 }
1620 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1621 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001622 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001623 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001624 /* It's critical here that valgrind's nanosleep implementation
1625 is nonblocking. */
1626 (void)my_do_syscall2(__NR_nanosleep,
1627 (int)(&nanosleep_interval), (int)NULL);
1628 }
1629}
1630
1631
1632
1633
1634#include <sys/poll.h>
1635
sewardj72d58482002-04-24 02:20:20 +00001636#ifdef GLIBC_2_1
1637typedef unsigned long int nfds_t;
1638#endif
1639
sewardj705d3cb2002-05-23 13:13:12 +00001640
sewardj5905fae2002-04-26 13:25:00 +00001641/* __attribute__((weak)) */
sewardjf854f472002-04-21 12:19:41 +00001642int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1643{
sewardj5f07b662002-04-23 16:52:51 +00001644 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001645 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001646 struct vki_timespec nanosleep_interval;
1647
1648 ensure_valgrind("poll");
1649
sewardj5f07b662002-04-23 16:52:51 +00001650 /* Detect the current time and simultaneously find out if we are
1651 running on Valgrind. */
1652 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1653 VG_USERREQ__READ_MILLISECOND_TIMER,
1654 0, 0, 0, 0);
1655
sewardjf854f472002-04-21 12:19:41 +00001656 if (/* CHECK SIZES FOR struct pollfd */
1657 sizeof(struct timeval) != sizeof(struct vki_timeval))
1658 barf("valgrind's hacky non-blocking poll(): data sizes error");
1659
sewardj5f07b662002-04-23 16:52:51 +00001660 /* dummy initialisation to keep gcc -Wall happy */
1661 ms_end = 0;
1662
1663 /* If a zero timeout specified, this call is harmless. Also do
1664 this if not running on Valgrind. */
1665 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001666 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1667 if (is_kerror(res)) {
1668 * (__errno_location()) = -res;
1669 return -1;
1670 } else {
1671 return res;
1672 }
1673 }
1674
sewardj5f07b662002-04-23 16:52:51 +00001675 /* If a timeout was specified, set ms_end to be the end wallclock
1676 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001677 if (__timeout > 0) {
sewardj650ac002002-04-29 12:20:34 +00001678 ms_end = ms_now + (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001679 }
1680
1681 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1682
1683 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1684 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001685 assert(__timeout != 0);
1686
sewardjf854f472002-04-21 12:19:41 +00001687 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001688 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001689 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1690 VG_USERREQ__READ_MILLISECOND_TIMER,
1691 0, 0, 0, 0);
1692 assert(ms_now != 0xFFFFFFFF);
1693 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001694 /* timeout; nothing interesting happened. */
1695 for (i = 0; i < __nfds; i++)
1696 __fds[i].revents = 0;
1697 return 0;
1698 }
1699 }
1700
sewardj5f07b662002-04-23 16:52:51 +00001701 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001702 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1703 if (is_kerror(res)) {
1704 /* Some kind of error. Set errno and return. */
1705 * (__errno_location()) = -res;
1706 return -1;
1707 }
1708 if (res > 0) {
1709 /* One or more fds is ready. Return now. */
1710 return res;
1711 }
1712 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1713 /* nanosleep and go round again */
1714 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001715 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001716 /* It's critical here that valgrind's nanosleep implementation
1717 is nonblocking. */
1718 (void)my_do_syscall2(__NR_nanosleep,
1719 (int)(&nanosleep_interval), (int)NULL);
1720 }
1721}
sewardj3b13f0e2002-04-25 20:17:29 +00001722
1723
sewardj705d3cb2002-05-23 13:13:12 +00001724/* Helper function used to make accept() non-blocking. Idea is to use
1725 the above nonblocking poll() to make this thread ONLY wait for the
1726 specified fd to become ready, and then return. */
1727static void wait_for_fd_to_be_readable_or_erring ( int fd )
1728{
1729 struct pollfd pfd;
sewardj6e6cbaa2002-05-24 02:12:52 +00001730 /* fprintf(stderr, "wait_for_fd_to_be_readable_or_erring %d\n", fd); */
sewardj705d3cb2002-05-23 13:13:12 +00001731 pfd.fd = fd;
1732 pfd.events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
1733 /* ... but not POLLOUT, you may notice. */
1734 pfd.revents = 0;
1735 (void)poll(&pfd, 1, -1 /* forever */);
1736}
1737
1738
sewardj3b13f0e2002-04-25 20:17:29 +00001739/* ---------------------------------------------------------------------
sewardj8f253ff2002-05-19 00:13:34 +00001740 Hacky implementation of semaphores.
1741 ------------------------------------------------------------------ */
1742
1743#include <semaphore.h>
1744
1745/* This is a terrible way to do the remapping. Plan is to import an
1746 AVL tree at some point. */
sewardj8f253ff2002-05-19 00:13:34 +00001747
1748typedef
1749 struct {
1750 pthread_mutex_t se_mx;
1751 pthread_cond_t se_cv;
1752 int count;
1753 }
1754 vg_sem_t;
1755
1756static pthread_mutex_t se_remap_mx = PTHREAD_MUTEX_INITIALIZER;
1757
1758static int se_remap_used = 0;
1759static sem_t* se_remap_orig[VG_N_SEMAPHORES];
1760static vg_sem_t se_remap_new[VG_N_SEMAPHORES];
1761
1762static vg_sem_t* se_remap ( sem_t* orig )
1763{
1764 int res, i;
1765 res = __pthread_mutex_lock(&se_remap_mx);
1766 assert(res == 0);
1767
1768 for (i = 0; i < se_remap_used; i++) {
1769 if (se_remap_orig[i] == orig)
1770 break;
1771 }
1772 if (i == se_remap_used) {
1773 if (se_remap_used == VG_N_SEMAPHORES) {
1774 res = pthread_mutex_unlock(&se_remap_mx);
1775 assert(res == 0);
sewardja1ac5cb2002-05-27 13:00:05 +00001776 barf("VG_N_SEMAPHORES is too low. Increase and recompile.");
sewardj8f253ff2002-05-19 00:13:34 +00001777 }
1778 se_remap_used++;
1779 se_remap_orig[i] = orig;
1780 /* printf("allocated semaphore %d\n", i); */
1781 }
1782 res = __pthread_mutex_unlock(&se_remap_mx);
1783 assert(res == 0);
1784 return &se_remap_new[i];
1785}
1786
1787
1788int sem_init(sem_t *sem, int pshared, unsigned int value)
1789{
1790 int res;
1791 vg_sem_t* vg_sem;
1792 ensure_valgrind("sem_init");
1793 if (pshared != 0) {
1794 errno = ENOSYS;
1795 return -1;
1796 }
1797 vg_sem = se_remap(sem);
1798 res = pthread_mutex_init(&vg_sem->se_mx, NULL);
1799 assert(res == 0);
1800 res = pthread_cond_init(&vg_sem->se_cv, NULL);
1801 assert(res == 0);
1802 vg_sem->count = value;
1803 return 0;
1804}
1805
1806
1807int sem_wait ( sem_t* sem )
1808{
1809 int res;
1810 vg_sem_t* vg_sem;
1811 ensure_valgrind("sem_wait");
1812 vg_sem = se_remap(sem);
1813 res = __pthread_mutex_lock(&vg_sem->se_mx);
1814 assert(res == 0);
1815 while (vg_sem->count == 0) {
1816 res = pthread_cond_wait(&vg_sem->se_cv, &vg_sem->se_mx);
1817 assert(res == 0);
1818 }
1819 vg_sem->count--;
1820 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1821 assert(res == 0);
1822 return 0;
1823}
1824
1825int sem_post ( sem_t* sem )
1826{
1827 int res;
1828 vg_sem_t* vg_sem;
1829 ensure_valgrind("sem_post");
1830 vg_sem = se_remap(sem);
1831 res = __pthread_mutex_lock(&vg_sem->se_mx);
1832 assert(res == 0);
1833 if (vg_sem->count == 0) {
1834 vg_sem->count++;
1835 res = pthread_cond_broadcast(&vg_sem->se_cv);
1836 assert(res == 0);
1837 } else {
1838 vg_sem->count++;
1839 }
1840 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1841 assert(res == 0);
1842 return 0;
1843}
1844
1845
1846int sem_trywait ( sem_t* sem )
1847{
1848 int ret, res;
1849 vg_sem_t* vg_sem;
1850 ensure_valgrind("sem_trywait");
1851 vg_sem = se_remap(sem);
1852 res = __pthread_mutex_lock(&vg_sem->se_mx);
1853 assert(res == 0);
1854 if (vg_sem->count > 0) {
1855 vg_sem->count--;
1856 ret = 0;
1857 } else {
1858 ret = -1;
1859 errno = EAGAIN;
1860 }
1861 res = __pthread_mutex_unlock(&vg_sem->se_mx);
1862 assert(res == 0);
1863 return ret;
1864}
1865
1866
1867int sem_getvalue(sem_t* sem, int * sval)
1868{
1869 vg_sem_t* vg_sem;
1870 ensure_valgrind("sem_trywait");
1871 vg_sem = se_remap(sem);
1872 *sval = vg_sem->count;
1873 return 0;
1874}
1875
1876
1877int sem_destroy(sem_t * sem)
1878{
1879 kludged("sem_destroy");
1880 /* if someone waiting on this semaphore, errno = EBUSY, return -1 */
1881 return 0;
1882}
1883
1884
1885/* ---------------------------------------------------------------------
sewardja1ac5cb2002-05-27 13:00:05 +00001886 Hacky implementation of reader-writer locks.
1887 ------------------------------------------------------------------ */
1888
1889/*
1890Errata from 7th printing:
1891
1892 Page 259, rwlock.c, line 27, the two "!=" should be ">", for
1893 consistency with other similar tests. (The values should never be
1894 negative; this isn't a fix, but an improvement to clarity and
1895 consistency.)
1896
1897 [27] if (rwl->r_wait > 0 || rwl->w_wait > 0) {
1898
1899 Page 259, rwlock.c, lines 39 and 40, in both lines, "==" should
1900 become "!=":
1901
1902 [39] return (status != 0 ? status
1903 [40] : (status1 != 0 ? status1 : status2));
1904*/
1905
1906/*
1907 * rwlock.h
1908 *
1909 * This header file describes the "reader/writer lock" synchronization
1910 * construct. The type rwlock_t describes the full state of the lock
1911 * including the POSIX 1003.1c synchronization objects necessary.
1912 *
1913 * A reader/writer lock allows a thread to lock shared data either for shared
1914 * read access or exclusive write access.
1915 *
1916 * The rwl_init() and rwl_destroy() functions, respectively, allow you to
1917 * initialize/create and destroy/free the reader/writer lock.
1918 */
1919
sewardja1ac5cb2002-05-27 13:00:05 +00001920/*
1921 * Structure describing a read-write lock.
1922 */
1923typedef struct {
1924 pthread_mutex_t mutex;
1925 pthread_cond_t read; /* wait for read */
1926 pthread_cond_t write; /* wait for write */
1927 int valid; /* set when valid */
1928 int r_active; /* readers active */
1929 int w_active; /* writer active */
1930 int r_wait; /* readers waiting */
1931 int w_wait; /* writers waiting */
1932 int pref_writer; /* != 0 --> prefer writer */
1933} vg_rwlock_t;
1934
1935#define VG_RWLOCK_VALID 0xfacade
1936
1937
1938/*
1939 * Support static initialization of barriers
1940 */
1941#define VG_RWL_INITIALIZER \
1942 {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, \
1943 PTHREAD_COND_INITIALIZER, VG_RWLOCK_VALID, 0, 0, 0, 0, 1}
1944
1945
1946static pthread_mutex_t rw_remap_mx = PTHREAD_MUTEX_INITIALIZER;
1947
1948static int rw_remap_used = 0;
1949static pthread_rwlock_t* rw_remap_orig[VG_N_RWLOCKS];
1950static vg_rwlock_t rw_remap_new[VG_N_RWLOCKS];
1951
1952/* Take the address of a LinuxThreads rwlock_t and return the shadow
1953 address of our version. Further, if the LinuxThreads version
1954 appears to have been statically initialised, do the same to the one
1955 we allocate here. The pthread_rwlock_t.__rw_readers field is set
1956 to zero by PTHREAD_RWLOCK_INITIALIZER, so we take zero as meaning
1957 uninitialised and non-zero meaning initialised.
1958*/
1959static vg_rwlock_t* rw_remap ( pthread_rwlock_t* orig )
1960{
1961 int res, i;
1962 vg_rwlock_t* vg_rwl;
1963 res = __pthread_mutex_lock(&rw_remap_mx);
1964 assert(res == 0);
1965
1966 for (i = 0; i < rw_remap_used; i++) {
1967 if (rw_remap_orig[i] == orig)
1968 break;
1969 }
1970 if (i == rw_remap_used) {
1971 if (rw_remap_used == VG_N_RWLOCKS) {
1972 res = pthread_mutex_unlock(&rw_remap_mx);
1973 assert(res == 0);
1974 barf("VG_N_RWLOCKS is too low. Increase and recompile.");
1975 }
1976 rw_remap_used++;
1977 rw_remap_orig[i] = orig;
1978 if (0) printf("allocated rwlock %d\n", i);
1979 }
1980 res = __pthread_mutex_unlock(&rw_remap_mx);
1981 assert(res == 0);
1982 vg_rwl = &rw_remap_new[i];
1983
1984 /* Mimic static initialisation of the original. */
1985 if (orig->__rw_readers == 0) {
1986 const vg_rwlock_t default_rwl = VG_RWL_INITIALIZER;
1987 orig->__rw_readers = 1;
1988 *vg_rwl = default_rwl;
1989 vg_rwl->pref_writer = 1;
1990 if (orig->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
1991 vg_rwl->pref_writer = 0;
1992 }
1993
1994 return vg_rwl;
1995}
1996
1997
1998/*
1999 * rwlock.c
2000 *
2001 * This file implements the "read-write lock" synchronization
2002 * construct.
2003 *
2004 * A read-write lock allows a thread to lock shared data either
2005 * for shared read access or exclusive write access.
2006 *
2007 * The rwl_init() and rwl_destroy() functions, respectively,
2008 * allow you to initialize/create and destroy/free the
2009 * read-write lock.
2010 *
2011 * The rwl_readlock() function locks a read-write lock for
2012 * shared read access, and rwl_readunlock() releases the
2013 * lock. rwl_readtrylock() attempts to lock a read-write lock
2014 * for read access, and returns EBUSY instead of blocking.
2015 *
2016 * The rwl_writelock() function locks a read-write lock for
2017 * exclusive write access, and rwl_writeunlock() releases the
2018 * lock. rwl_writetrylock() attempts to lock a read-write lock
2019 * for write access, and returns EBUSY instead of blocking.
2020 */
2021
2022
2023/*
2024 * Initialize a read-write lock
2025 */
2026static int rwl_init ( vg_rwlock_t *rwl )
2027{
2028 int status;
2029
2030 rwl->r_active = 0;
2031 rwl->r_wait = rwl->w_wait = 0;
2032 rwl->w_active = 0;
2033 status = pthread_mutex_init (&rwl->mutex, NULL);
2034 if (status != 0)
2035 return status;
2036 status = pthread_cond_init (&rwl->read, NULL);
2037 if (status != 0) {
2038 /* if unable to create read CV, destroy mutex */
2039 pthread_mutex_destroy (&rwl->mutex);
2040 return status;
2041 }
2042 status = pthread_cond_init (&rwl->write, NULL);
2043 if (status != 0) {
2044 /* if unable to create write CV, destroy read CV and mutex */
2045 pthread_cond_destroy (&rwl->read);
2046 pthread_mutex_destroy (&rwl->mutex);
2047 return status;
2048 }
2049 rwl->valid = VG_RWLOCK_VALID;
2050 return 0;
2051}
2052
2053/*
2054 * Destroy a read-write lock
2055 */
2056static int rwl_destroy (vg_rwlock_t *rwl)
2057{
2058 int status, status1, status2;
2059
2060 if (rwl->valid != VG_RWLOCK_VALID)
2061 return EINVAL;
2062 status = pthread_mutex_lock (&rwl->mutex);
2063 if (status != 0)
2064 return status;
2065
2066 /*
2067 * Check whether any threads own the lock; report "BUSY" if
2068 * so.
2069 */
2070 if (rwl->r_active > 0 || rwl->w_active) {
2071 pthread_mutex_unlock (&rwl->mutex);
2072 return EBUSY;
2073 }
2074
2075 /*
2076 * Check whether any threads are known to be waiting; report
2077 * EBUSY if so.
2078 */
2079 if (rwl->r_wait > 0 || rwl->w_wait > 0) {
2080 pthread_mutex_unlock (&rwl->mutex);
2081 return EBUSY;
2082 }
2083
2084 rwl->valid = 0;
2085 status = pthread_mutex_unlock (&rwl->mutex);
2086 if (status != 0)
2087 return status;
2088 status = pthread_mutex_destroy (&rwl->mutex);
2089 status1 = pthread_cond_destroy (&rwl->read);
2090 status2 = pthread_cond_destroy (&rwl->write);
2091 return (status != 0 ? status : (status1 != 0 ? status1 : status2));
2092}
2093
2094/*
2095 * Handle cleanup when the read lock condition variable
2096 * wait is cancelled.
2097 *
2098 * Simply record that the thread is no longer waiting,
2099 * and unlock the mutex.
2100 */
2101static void rwl_readcleanup (void *arg)
2102{
2103 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2104
2105 rwl->r_wait--;
2106 pthread_mutex_unlock (&rwl->mutex);
2107}
2108
2109/*
2110 * Lock a read-write lock for read access.
2111 */
2112static int rwl_readlock (vg_rwlock_t *rwl)
2113{
2114 int status;
2115
2116 if (rwl->valid != VG_RWLOCK_VALID)
2117 return EINVAL;
2118 status = pthread_mutex_lock (&rwl->mutex);
2119 if (status != 0)
2120 return status;
2121 if (rwl->w_active) {
2122 rwl->r_wait++;
2123 pthread_cleanup_push (rwl_readcleanup, (void*)rwl);
2124 while (rwl->w_active) {
2125 status = pthread_cond_wait (&rwl->read, &rwl->mutex);
2126 if (status != 0)
2127 break;
2128 }
2129 pthread_cleanup_pop (0);
2130 rwl->r_wait--;
2131 }
2132 if (status == 0)
2133 rwl->r_active++;
2134 pthread_mutex_unlock (&rwl->mutex);
2135 return status;
2136}
2137
2138/*
2139 * Attempt to lock a read-write lock for read access (don't
2140 * block if unavailable).
2141 */
2142static int rwl_readtrylock (vg_rwlock_t *rwl)
2143{
2144 int status, status2;
2145
2146 if (rwl->valid != VG_RWLOCK_VALID)
2147 return EINVAL;
2148 status = pthread_mutex_lock (&rwl->mutex);
2149 if (status != 0)
2150 return status;
2151 if (rwl->w_active)
2152 status = EBUSY;
2153 else
2154 rwl->r_active++;
2155 status2 = pthread_mutex_unlock (&rwl->mutex);
2156 return (status2 != 0 ? status2 : status);
2157}
2158
2159/*
2160 * Handle cleanup when the write lock condition variable
2161 * wait is cancelled.
2162 *
2163 * Simply record that the thread is no longer waiting,
2164 * and unlock the mutex.
2165 */
2166static void rwl_writecleanup (void *arg)
2167{
2168 vg_rwlock_t *rwl = (vg_rwlock_t *)arg;
2169
2170 rwl->w_wait--;
2171 pthread_mutex_unlock (&rwl->mutex);
2172}
2173
2174/*
2175 * Lock a read-write lock for write access.
2176 */
2177static int rwl_writelock (vg_rwlock_t *rwl)
2178{
2179 int status;
2180
2181 if (rwl->valid != VG_RWLOCK_VALID)
2182 return EINVAL;
2183 status = pthread_mutex_lock (&rwl->mutex);
2184 if (status != 0)
2185 return status;
2186 if (rwl->w_active || rwl->r_active > 0) {
2187 rwl->w_wait++;
2188 pthread_cleanup_push (rwl_writecleanup, (void*)rwl);
2189 while (rwl->w_active || rwl->r_active > 0) {
2190 status = pthread_cond_wait (&rwl->write, &rwl->mutex);
2191 if (status != 0)
2192 break;
2193 }
2194 pthread_cleanup_pop (0);
2195 rwl->w_wait--;
2196 }
2197 if (status == 0)
2198 rwl->w_active = 1;
2199 pthread_mutex_unlock (&rwl->mutex);
2200 return status;
2201}
2202
2203/*
2204 * Attempt to lock a read-write lock for write access. Don't
2205 * block if unavailable.
2206 */
2207static int rwl_writetrylock (vg_rwlock_t *rwl)
2208{
2209 int status, status2;
2210
2211 if (rwl->valid != VG_RWLOCK_VALID)
2212 return EINVAL;
2213 status = pthread_mutex_lock (&rwl->mutex);
2214 if (status != 0)
2215 return status;
2216 if (rwl->w_active || rwl->r_active > 0)
2217 status = EBUSY;
2218 else
2219 rwl->w_active = 1;
2220 status2 = pthread_mutex_unlock (&rwl->mutex);
2221 return (status != 0 ? status : status2);
2222}
2223
2224/*
2225 * Unlock a read-write lock, using the r_active and w_active fields to
2226 * decide whether we're in a read or write lock.
2227 */
2228static int rwl_unlock (vg_rwlock_t *rwl)
2229{
2230 int status, status2;
2231
2232 if (rwl->valid != VG_RWLOCK_VALID)
2233 return EINVAL;
2234 status = pthread_mutex_lock (&rwl->mutex);
2235 if (status != 0)
2236 return status;
2237
2238 if (rwl->r_active > 0) {
2239
2240 /* READ case */
2241 assert(!rwl->w_active);
2242 rwl->r_active--;
2243 if (rwl->r_active == 0 && rwl->w_wait > 0)
2244 status = pthread_cond_signal (&rwl->write);
2245 /* END READ case */
2246
2247 } else {
2248
2249 /* WRITE case */
2250 assert(rwl->w_active);
2251 assert(rwl->r_active == 0);
2252 rwl->w_active = 0;
2253
2254 if (rwl->pref_writer) {
2255 /* Do writer-preference wakeups. */
2256 if (rwl->w_wait > 0) {
2257 status = pthread_cond_signal (&rwl->write);
2258 if (status != 0) {
2259 pthread_mutex_unlock (&rwl->mutex);
2260 return status;
2261 }
2262 } else if (rwl->r_wait > 0) {
2263 status = pthread_cond_broadcast (&rwl->read);
2264 if (status != 0) {
2265 pthread_mutex_unlock (&rwl->mutex);
2266 return status;
2267 }
2268 }
2269 } else {
2270 /* Do reader-preference wakeups. */
2271 if (rwl->r_wait > 0) {
2272 status = pthread_cond_broadcast (&rwl->read);
2273 if (status != 0) {
2274 pthread_mutex_unlock (&rwl->mutex);
2275 return status;
2276 }
2277 } else if (rwl->w_wait > 0) {
2278 status = pthread_cond_signal (&rwl->write);
2279 if (status != 0) {
2280 pthread_mutex_unlock (&rwl->mutex);
2281 return status;
2282 }
2283 }
2284 }
2285 /* END WRITE case */
2286
2287 }
2288
2289 status2 = pthread_mutex_unlock (&rwl->mutex);
2290 return (status2 == 0 ? status : status2);
2291}
2292
2293/* -------------------------------- */
2294
2295int pthread_rwlock_init ( pthread_rwlock_t* orig,
2296 const pthread_rwlockattr_t* attr )
2297{
2298 int res;
2299 vg_rwlock_t* rwl;
2300 if (0) printf ("pthread_rwlock_init\n");
2301 /* Force the remapper to initialise the shadow. */
2302 orig->__rw_readers = 0;
2303 /* Install the lock preference; the remapper needs to know it. */
2304 orig->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
2305 if (attr)
2306 orig->__rw_kind = attr->__lockkind;
2307 rwl = rw_remap ( orig );
2308 res = rwl_init ( rwl );
2309 return res;
2310}
2311
2312int pthread_rwlock_destroy ( pthread_rwlock_t *orig )
2313{
2314 int res;
2315 vg_rwlock_t* rwl;
2316 if (0) printf ("pthread_rwlock_destroy\n");
2317 rwl = rw_remap ( orig );
2318 res = rwl_destroy ( rwl );
2319 return res;
2320}
2321
2322int pthread_rwlock_rdlock ( pthread_rwlock_t* orig )
2323{
2324 int res;
2325 vg_rwlock_t* rwl;
2326 if (0) printf ("pthread_rwlock_rdlock\n");
2327 rwl = rw_remap ( orig );
2328 res = rwl_readlock ( rwl );
2329 return res;
2330}
2331
2332int pthread_rwlock_tryrdlock ( pthread_rwlock_t* orig )
2333{
2334 int res;
2335 vg_rwlock_t* rwl;
2336 if (0) printf ("pthread_rwlock_tryrdlock\n");
2337 rwl = rw_remap ( orig );
2338 res = rwl_readtrylock ( rwl );
2339 return res;
2340}
2341
2342int pthread_rwlock_wrlock ( pthread_rwlock_t* orig )
2343{
2344 int res;
2345 vg_rwlock_t* rwl;
2346 if (0) printf ("pthread_rwlock_wrlock\n");
2347 rwl = rw_remap ( orig );
2348 res = rwl_writelock ( rwl );
2349 return res;
2350}
2351
2352int pthread_rwlock_trywrlock ( pthread_rwlock_t* orig )
2353{
2354 int res;
2355 vg_rwlock_t* rwl;
2356 if (0) printf ("pthread_rwlock_trywrlock\n");
2357 rwl = rw_remap ( orig );
2358 res = rwl_writetrylock ( rwl );
2359 return res;
2360}
2361
2362int pthread_rwlock_unlock ( pthread_rwlock_t* orig )
2363{
2364 int res;
2365 vg_rwlock_t* rwl;
2366 if (0) printf ("pthread_rwlock_unlock\n");
2367 rwl = rw_remap ( orig );
2368 res = rwl_unlock ( rwl );
2369 return res;
2370}
2371
2372
2373/* ---------------------------------------------------------------------
sewardj3b13f0e2002-04-25 20:17:29 +00002374 B'stard.
2375 ------------------------------------------------------------------ */
2376
2377# define strong_alias(name, aliasname) \
2378 extern __typeof (name) aliasname __attribute__ ((alias (#name)));
2379
sewardj5905fae2002-04-26 13:25:00 +00002380# define weak_alias(name, aliasname) \
2381 extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
sewardj3b13f0e2002-04-25 20:17:29 +00002382
sewardj5905fae2002-04-26 13:25:00 +00002383strong_alias(__pthread_mutex_lock, pthread_mutex_lock)
2384strong_alias(__pthread_mutex_trylock, pthread_mutex_trylock)
2385strong_alias(__pthread_mutex_unlock, pthread_mutex_unlock)
2386strong_alias(__pthread_mutexattr_init, pthread_mutexattr_init)
2387 weak_alias(__pthread_mutexattr_settype, pthread_mutexattr_settype)
2388strong_alias(__pthread_mutex_init, pthread_mutex_init)
2389strong_alias(__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
2390strong_alias(__pthread_mutex_destroy, pthread_mutex_destroy)
2391strong_alias(__pthread_once, pthread_once)
2392strong_alias(__pthread_atfork, pthread_atfork)
2393strong_alias(__pthread_key_create, pthread_key_create)
2394strong_alias(__pthread_getspecific, pthread_getspecific)
2395strong_alias(__pthread_setspecific, pthread_setspecific)
2396
sewardjd529a442002-05-04 19:49:21 +00002397#ifndef GLIBC_2_1
sewardj3b13f0e2002-04-25 20:17:29 +00002398strong_alias(sigaction, __sigaction)
sewardjd529a442002-05-04 19:49:21 +00002399#endif
2400
sewardj5905fae2002-04-26 13:25:00 +00002401strong_alias(close, __close)
sewardj3b13f0e2002-04-25 20:17:29 +00002402strong_alias(fcntl, __fcntl)
sewardj5905fae2002-04-26 13:25:00 +00002403strong_alias(lseek, __lseek)
2404strong_alias(open, __open)
2405strong_alias(open64, __open64)
sewardj5905fae2002-04-26 13:25:00 +00002406strong_alias(read, __read)
2407strong_alias(wait, __wait)
2408strong_alias(write, __write)
sewardj3b13f0e2002-04-25 20:17:29 +00002409strong_alias(connect, __connect)
sewardj5905fae2002-04-26 13:25:00 +00002410strong_alias(send, __send)
2411
sewardj726c4122002-05-16 23:39:10 +00002412weak_alias (__pread64, pread64)
sewardja18e2102002-05-18 10:43:22 +00002413weak_alias (__pwrite64, pwrite64)
sewardj5905fae2002-04-26 13:25:00 +00002414weak_alias(__fork, fork)
sewardj7f6456d2002-05-21 00:51:21 +00002415
sewardj5905fae2002-04-26 13:25:00 +00002416
sewardj3b13f0e2002-04-25 20:17:29 +00002417
2418/*--------------------------------------------------*/
2419
sewardj5905fae2002-04-26 13:25:00 +00002420weak_alias(pthread_rwlock_rdlock, __pthread_rwlock_rdlock)
sewardj5905fae2002-04-26 13:25:00 +00002421weak_alias(pthread_rwlock_unlock, __pthread_rwlock_unlock)
sewardj262b0292002-05-01 00:03:16 +00002422weak_alias(pthread_rwlock_wrlock, __pthread_rwlock_wrlock)
sewardj060b04f2002-04-26 21:01:13 +00002423
sewardja1ac5cb2002-05-27 13:00:05 +00002424weak_alias(pthread_rwlock_destroy, __pthread_rwlock_destroy)
2425weak_alias(pthread_rwlock_init, __pthread_rwlock_init)
2426weak_alias(pthread_rwlock_tryrdlock, __pthread_rwlock_tryrdlock)
2427weak_alias(pthread_rwlock_trywrlock, __pthread_rwlock_trywrlock)
2428
sewardj060b04f2002-04-26 21:01:13 +00002429
sewardj3b13f0e2002-04-25 20:17:29 +00002430/* I've no idea what these are, but they get called quite a lot.
2431 Anybody know? */
2432
2433#undef _IO_flockfile
2434void _IO_flockfile ( _IO_FILE * file )
2435{
sewardj853f55d2002-04-26 00:27:53 +00002436 pthread_mutex_lock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002437}
sewardj5905fae2002-04-26 13:25:00 +00002438weak_alias(_IO_flockfile, flockfile);
2439
sewardj3b13f0e2002-04-25 20:17:29 +00002440
2441#undef _IO_funlockfile
2442void _IO_funlockfile ( _IO_FILE * file )
2443{
sewardj853f55d2002-04-26 00:27:53 +00002444 pthread_mutex_unlock(file->_lock);
sewardj3b13f0e2002-04-25 20:17:29 +00002445}
sewardj5905fae2002-04-26 13:25:00 +00002446weak_alias(_IO_funlockfile, funlockfile);
2447
sewardj3b13f0e2002-04-25 20:17:29 +00002448
2449void _pthread_cleanup_push_defer ( void )
2450{
sewardj439d45e2002-05-03 20:43:10 +00002451 static int moans = N_MOANS;
2452 if (moans-- > 0)
2453 ignored("_pthread_cleanup_push_defer");
sewardj3b13f0e2002-04-25 20:17:29 +00002454}
2455
2456void _pthread_cleanup_pop_restore ( void )
2457{
sewardj439d45e2002-05-03 20:43:10 +00002458 static int moans = N_MOANS;
2459 if (moans-- > 0)
2460 ignored("_pthread_cleanup_pop_restore");
sewardj3b13f0e2002-04-25 20:17:29 +00002461}
sewardjd4f2c712002-04-30 10:20:10 +00002462
sewardj60e38422002-05-08 14:08:22 +00002463/*--------*/
2464void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
2465 void (*__routine) (void *),
2466 void *__arg)
2467{
2468 static int moans = N_MOANS;
2469 if (moans-- > 0)
2470 ignored("_pthread_cleanup_push");
2471}
2472
2473void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
2474 int __execute)
2475{
2476 static int moans = N_MOANS;
2477 if (moans-- > 0) {
2478 if (__execute)
2479 ignored("_pthread_cleanup_pop-EXECUTE");
2480 else
2481 ignored("_pthread_cleanup_pop-NO-EXECUTE");
2482 }
2483}
2484
sewardjd4f2c712002-04-30 10:20:10 +00002485
2486/* This doesn't seem to be needed to simulate libpthread.so's external
2487 interface, but many people complain about its absence. */
2488
2489strong_alias(__pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
2490weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
sewardj439d45e2002-05-03 20:43:10 +00002491
2492
2493/*--------------------------------------------------------------------*/
2494/*--- end vg_libpthread.c ---*/
2495/*--------------------------------------------------------------------*/