blob: 8ee3ccb10e657143c265ce38133365fe726a5b72 [file] [log] [blame]
sewardje663cb92002-04-12 10:26:32 +00001
2/* This is a replacement for the standard libpthread.so. It is loaded
3 as part of the client's image (if required) and directs pthread
4 calls through to Valgrind's request mechanism.
5
6 A couple of caveats.
7
8 1. Since it's a binary-compatible replacement for an existing library,
9 we must take care to used exactly the same data layouts, etc, as
10 the standard pthread.so does.
11
12 2. Since this runs as part of the client, there are no specific
13 restrictions on what headers etc we can include, so long as
14 this libpthread.so does not end up having dependencies on .so's
15 which the real one doesn't.
16
17 Later ... it appears we cannot call file-related stuff in libc here,
18 perhaps fair enough. Be careful what you call from here. Even exit()
19 doesn't work (gives infinite recursion and then stack overflow); hence
20 myexit(). Also fprintf doesn't seem safe.
21*/
22
23#include "valgrind.h" /* For the request-passing mechanism */
24#include "vg_include.h" /* For the VG_USERREQ__* constants */
25
sewardje663cb92002-04-12 10:26:32 +000026#include <unistd.h>
27#include <string.h>
28
29
30/* ---------------------------------------------------------------------
31 Helpers. We have to be pretty self-sufficient.
32 ------------------------------------------------------------------ */
33
sewardj45b4b372002-04-16 22:50:32 +000034/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
35 Returns 0 (none) if not running on Valgrind. */
36static
37int get_pt_trace_level ( void )
38{
39 int res;
40 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
41 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
42 0, 0, 0, 0);
43 return res;
44}
45
46
47
sewardje663cb92002-04-12 10:26:32 +000048static
49void myexit ( int arg )
50{
sewardj45b4b372002-04-16 22:50:32 +000051 int __res;
sewardje663cb92002-04-12 10:26:32 +000052 __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
53 : "=a" (__res)
54 : "0" (__NR_exit),
55 "c" (arg) );
sewardj45b4b372002-04-16 22:50:32 +000056 /* We don't bother to mention the fact that this asm trashes %ebx,
57 since it won't return. If you ever do let it return ... fix
58 this! */
sewardje663cb92002-04-12 10:26:32 +000059}
60
61
62/* Give up without using printf etc, since they seem to give
63 segfaults. */
64static
65void ensure_valgrind ( char* caller )
66{
67 char* str;
68 int is_valgrind = RUNNING_ON_VALGRIND;
69 if (!is_valgrind) {
70 str = "\nvalgrind-ed process: vg_libpthread.so: "
71 "pthread call when\n";
72 write(2, str, strlen(str));
73 str = "not running on valgrind; aborting! "
74 "This is probably a bug in\n";
75 write(2, str, strlen(str));
76 str = "valgrind. Please report it to me at: "
77 "jseward@acm.org. Thanks.\n";
78 write(2, str, strlen(str));
79 str = "unexpectedly called function is: ";
80 write(2, str, strlen(str));
81 write(2, caller, strlen(caller));
82 str = "\n\n";
83 write(2, str, strlen(str));
84 myexit(1);
85 }
86}
87
88
89static
90void barf ( char* str )
91{
92 char buf[100];
93 buf[0] = 0;
94 strcat(buf, "\nvg_libpthread.so: ");
95 strcat(buf, str);
96 strcat(buf, "\n\n");
97 write(2, buf, strlen(buf));
98 myexit(1);
99}
100
101
sewardj2a3d28c2002-04-14 13:27:00 +0000102static void ignored ( char* msg )
103{
sewardj45b4b372002-04-16 22:50:32 +0000104 if (get_pt_trace_level() >= 1) {
105 char* ig = "vg_libpthread.so: IGNORED call to: ";
106 write(2, ig, strlen(ig));
107 write(2, msg, strlen(msg));
108 ig = "\n";
109 write(2, ig, strlen(ig));
110 }
sewardj2a3d28c2002-04-14 13:27:00 +0000111}
112
sewardje663cb92002-04-12 10:26:32 +0000113
114/* ---------------------------------------------------------------------
115 Pass pthread_ calls to Valgrind's request mechanism.
116 ------------------------------------------------------------------ */
117
sewardjf8f819e2002-04-17 23:21:37 +0000118#include <pthread.h>
119#include <stdio.h>
120#include <errno.h>
121
122/* ---------------------------------------------------
123 THREAD ATTRIBUTES
124 ------------------------------------------------ */
125
sewardj6af4b5d2002-04-16 04:40:49 +0000126int pthread_attr_init(pthread_attr_t *attr)
127{
128 ignored("pthread_attr_init");
129 return 0;
130}
131
132int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
133{
134 ignored("pthread_attr_setdetachstate");
135 return 0;
136}
137
138
sewardjf8f819e2002-04-17 23:21:37 +0000139
140/* ---------------------------------------------------
141 THREADs
142 ------------------------------------------------ */
143
sewardje663cb92002-04-12 10:26:32 +0000144int
145pthread_create (pthread_t *__restrict __thread,
146 __const pthread_attr_t *__restrict __attr,
147 void *(*__start_routine) (void *),
148 void *__restrict __arg)
149{
150 int res;
151 ensure_valgrind("pthread_create");
152 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
153 VG_USERREQ__PTHREAD_CREATE,
154 __thread, __attr, __start_routine, __arg);
155 return res;
156}
157
158
159
160int
161pthread_join (pthread_t __th, void **__thread_return)
162{
163 int res;
164 ensure_valgrind("pthread_join");
165 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
166 VG_USERREQ__PTHREAD_JOIN,
167 __th, __thread_return, 0, 0);
168 return res;
169}
170
171
sewardje663cb92002-04-12 10:26:32 +0000172
173static int thread_specific_errno[VG_N_THREADS];
174
175int* __errno_location ( void )
176{
177 int tid;
178 ensure_valgrind("__errno_location");
179 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
180 VG_USERREQ__PTHREAD_GET_THREADID,
181 0, 0, 0, 0);
182 /* 'cos I'm paranoid ... */
183 if (tid < 0 || tid >= VG_N_THREADS)
184 barf("__errno_location: invalid ThreadId");
185 return & thread_specific_errno[tid];
186}
187
188
sewardjf8f819e2002-04-17 23:21:37 +0000189/* ---------------------------------------------------
190 MUTEX ATTRIBUTES
191 ------------------------------------------------ */
192
sewardje663cb92002-04-12 10:26:32 +0000193int pthread_mutexattr_init(pthread_mutexattr_t *attr)
194{
sewardjf8f819e2002-04-17 23:21:37 +0000195 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000196 return 0;
sewardje663cb92002-04-12 10:26:32 +0000197}
198
sewardjf8f819e2002-04-17 23:21:37 +0000199int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
200{
201 switch (type) {
202 case PTHREAD_MUTEX_TIMED_NP:
203 case PTHREAD_MUTEX_RECURSIVE_NP:
204 case PTHREAD_MUTEX_ERRORCHECK_NP:
205 case PTHREAD_MUTEX_ADAPTIVE_NP:
206 attr->__mutexkind = type;
207 return 0;
208 default:
209 return EINVAL;
210 }
211}
212
213int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
214{
215 return 0;
216}
217
218
219/* ---------------------------------------------------
220 MUTEXes
221 ------------------------------------------------ */
222
sewardje663cb92002-04-12 10:26:32 +0000223int pthread_mutex_init(pthread_mutex_t *mutex,
224 const pthread_mutexattr_t *mutexattr)
225{
226 int res;
sewardje663cb92002-04-12 10:26:32 +0000227 ensure_valgrind("pthread_mutex_init");
228 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
229 VG_USERREQ__PTHREAD_MUTEX_INIT,
230 mutex, mutexattr, 0, 0);
231 return res;
232}
233
sewardje663cb92002-04-12 10:26:32 +0000234int pthread_mutex_lock(pthread_mutex_t *mutex)
235{
236 int res;
sewardj45b4b372002-04-16 22:50:32 +0000237 static int moans = 5;
238 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000239 char* str = "pthread_mutex_lock-NOT-INSIDE-VALGRIND\n";
240 write(2, str, strlen(str));
241 return 0;
242 } else {
243 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
244 VG_USERREQ__PTHREAD_MUTEX_LOCK,
245 mutex, 0, 0, 0);
246 return res;
247 }
248}
249
250int pthread_mutex_unlock(pthread_mutex_t *mutex)
251{
252 int res;
sewardj45b4b372002-04-16 22:50:32 +0000253 static int moans = 5;
254 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000255 char* str = "pthread_mutex_unlock-NOT-INSIDE-VALGRIND\n";
256 write(2, str, strlen(str));
257 return 0;
258 } else {
259 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
260 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
261 mutex, 0, 0, 0);
262 return res;
263 }
264}
265
sewardje663cb92002-04-12 10:26:32 +0000266int pthread_mutex_destroy(pthread_mutex_t *mutex)
267{
268 int res;
sewardj45b4b372002-04-16 22:50:32 +0000269 static int moans = 5;
270 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000271 char* str = "pthread_mutex_destroy-NOT-INSIDE-VALGRIND\n";
272 write(2, str, strlen(str));
273 return 0;
274 } else {
275 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
276 VG_USERREQ__PTHREAD_MUTEX_DESTROY,
277 mutex, 0, 0, 0);
278 }
279 return res;
280}
281
282
sewardjf8f819e2002-04-17 23:21:37 +0000283/* ---------------------------------------------------
284 CANCELLATION
285 ------------------------------------------------ */
286
sewardje663cb92002-04-12 10:26:32 +0000287int pthread_setcanceltype(int type, int *oldtype)
288{
sewardj2a3d28c2002-04-14 13:27:00 +0000289 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000290 return 0;
291}
292
293
294int pthread_cancel(pthread_t thread)
295{
296 int res;
297 ensure_valgrind("pthread_cancel");
298 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
299 VG_USERREQ__PTHREAD_CANCEL,
300 thread, 0, 0, 0);
301 return res;
302}
303
304
sewardjf8f819e2002-04-17 23:21:37 +0000305/* ---------------------------------------------------
306 THREAD-SPECIFICs
307 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000308
309int pthread_key_create(pthread_key_t *key,
310 void (*destr_function) (void *))
311{
sewardj2a3d28c2002-04-14 13:27:00 +0000312 ignored("pthread_key_create");
sewardj5e5fa512002-04-14 13:13:05 +0000313 return 0;
314}
315
316int pthread_key_delete(pthread_key_t key)
317{
sewardj2a3d28c2002-04-14 13:27:00 +0000318 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000319 return 0;
320}
321
322int pthread_setspecific(pthread_key_t key, const void *pointer)
323{
sewardj2a3d28c2002-04-14 13:27:00 +0000324 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000325 return 0;
326}
327
328void * pthread_getspecific(pthread_key_t key)
329{
sewardj2a3d28c2002-04-14 13:27:00 +0000330 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000331 return NULL;
332}
333
sewardjf8f819e2002-04-17 23:21:37 +0000334
335/* ---------------------------------------------------
336 MISC
337 ------------------------------------------------ */
338
339/* What are these? Anybody know? I don't. */
340
341void _pthread_cleanup_push_defer ( void )
342{
343 // char* str = "_pthread_cleanup_push_defer\n";
344 // write(2, str, strlen(str));
345}
346
347void _pthread_cleanup_pop_restore ( void )
348{
349 // char* str = "_pthread_cleanup_pop_restore\n";
350 // write(2, str, strlen(str));
351}
352
353
354pthread_t pthread_self(void)
355{
356 int tid;
357 ensure_valgrind("pthread_self");
358 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
359 VG_USERREQ__PTHREAD_GET_THREADID,
360 0, 0, 0, 0);
361 if (tid < 0 || tid >= VG_N_THREADS)
362 barf("pthread_self: invalid ThreadId");
363 return tid;
364}
365
366
sewardje663cb92002-04-12 10:26:32 +0000367/* ---------------------------------------------------------------------
368 These are here (I think) because they are deemed cancellation
369 points by POSIX. For the moment we'll simply pass the call along
370 to the corresponding thread-unaware (?) libc routine.
371 ------------------------------------------------------------------ */
372
sewardje663cb92002-04-12 10:26:32 +0000373#include <stdlib.h>
374#include <signal.h>
sewardje663cb92002-04-12 10:26:32 +0000375#include <sys/types.h>
376#include <sys/socket.h>
377
378extern
379int __libc_sigaction
380 (int signum,
381 const struct sigaction *act,
382 struct sigaction *oldact);
383int sigaction(int signum,
384 const struct sigaction *act,
385 struct sigaction *oldact)
386{
sewardj45b4b372002-04-16 22:50:32 +0000387 return __libc_sigaction(signum, act, oldact);
sewardje663cb92002-04-12 10:26:32 +0000388}
389
390
391extern
392int __libc_connect(int sockfd,
393 const struct sockaddr *serv_addr,
394 socklen_t addrlen);
395int connect(int sockfd,
396 const struct sockaddr *serv_addr,
397 socklen_t addrlen)
398{
sewardj45b4b372002-04-16 22:50:32 +0000399 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000400}
401
402
403extern
404int __libc_fcntl(int fd, int cmd, long arg);
405int fcntl(int fd, int cmd, long arg)
406{
sewardj45b4b372002-04-16 22:50:32 +0000407 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000408}
409
410
411extern
412ssize_t __libc_write(int fd, const void *buf, size_t count);
413ssize_t write(int fd, const void *buf, size_t count)
414{
sewardj45b4b372002-04-16 22:50:32 +0000415 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000416}
417
418
419extern
420ssize_t __libc_read(int fd, void *buf, size_t count);
421ssize_t read(int fd, void *buf, size_t count)
422{
sewardj45b4b372002-04-16 22:50:32 +0000423 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000424}
425
426
427extern
428int __libc_open(const char *pathname, int flags);
429int open(const char *pathname, int flags)
430{
sewardj45b4b372002-04-16 22:50:32 +0000431 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000432}
433
434
435extern
436int __libc_close(int fd);
437int close(int fd)
438{
sewardj45b4b372002-04-16 22:50:32 +0000439 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000440}
441
442
443extern
444int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
445int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
446{
sewardj45b4b372002-04-16 22:50:32 +0000447 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000448}
449
450
451extern
452pid_t __libc_fork(void);
453pid_t fork(void)
454{
sewardj45b4b372002-04-16 22:50:32 +0000455 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000456}
457
458
459extern
460pid_t __libc_waitpid(pid_t pid, int *status, int options);
461pid_t waitpid(pid_t pid, int *status, int options)
462{
sewardj45b4b372002-04-16 22:50:32 +0000463 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000464}
465
466
467extern
468int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
469int nanosleep(const struct timespec *req, struct timespec *rem)
470{
471 return __libc_nanosleep(req, rem);
472}
473
474extern
475int __libc_fsync(int fd);
476int fsync(int fd)
477{
sewardj45b4b372002-04-16 22:50:32 +0000478 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000479}
480
sewardj70c75362002-04-13 04:18:32 +0000481extern
482off_t __libc_lseek(int fildes, off_t offset, int whence);
483off_t lseek(int fildes, off_t offset, int whence)
484{
sewardj45b4b372002-04-16 22:50:32 +0000485 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000486}
487
sewardj6af4b5d2002-04-16 04:40:49 +0000488extern
489void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
490void longjmp(jmp_buf env, int val)
491{
492 __libc_longjmp(env, val);
493}
494
495extern
496int __libc_send(int s, const void *msg, size_t len, int flags);
497int send(int s, const void *msg, size_t len, int flags)
498{
499 return __libc_send(s, msg, len, flags);
500}
501
sewardj1e8cdc92002-04-18 11:37:52 +0000502extern
503int __libc_recv(int s, void *buf, size_t len, int flags);
504int recv(int s, void *buf, size_t len, int flags)
505{
506 return __libc_recv(s, buf, len, flags);
507}
508
sewardj45b4b372002-04-16 22:50:32 +0000509
sewardj70c75362002-04-13 04:18:32 +0000510/*--------------------------------------------------*/
511
sewardje663cb92002-04-12 10:26:32 +0000512/* I've no idea what these are, but they get called quite a lot.
513 Anybody know? */
514
515#undef _IO_flockfile
516void _IO_flockfile ( _IO_FILE * file )
517{
518 // char* str = "_IO_flockfile\n";
519 // write(2, str, strlen(str));
520 // barf("_IO_flockfile");
521}
522
523#undef _IO_funlockfile
524void _IO_funlockfile ( _IO_FILE * file )
525{
526 // char* str = "_IO_funlockfile\n";
527 // write(2, str, strlen(str));
528 //barf("_IO_funlockfile");
529}
530
sewardj08a4c3f2002-04-13 03:45:44 +0000531/*--------------------------------------------------*/
532
533#include "vg_kerneliface.h"
534
535static
536__inline__
537int is_kerror ( int res )
538{
539 if (res >= -4095 && res <= -1)
540 return 1;
541 else
542 return 0;
543}
544
545
546static
547int my_do_syscall1 ( int syscallno, int arg1 )
548{
549 int __res;
550 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
551 : "=a" (__res)
552 : "0" (syscallno),
553 "d" (arg1) );
554 return __res;
555}
556
557static
558int my_do_syscall2 ( int syscallno,
559 int arg1, int arg2 )
560{
561 int __res;
562 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
563 : "=a" (__res)
564 : "0" (syscallno),
565 "d" (arg1),
566 "c" (arg2) );
567 return __res;
568}
569
570static
571int do_syscall_select( int n,
572 vki_fd_set* readfds,
573 vki_fd_set* writefds,
574 vki_fd_set* exceptfds,
575 struct vki_timeval * timeout )
576{
577 int res;
578 int args[5];
579 args[0] = n;
580 args[1] = (int)readfds;
581 args[2] = (int)writefds;
582 args[3] = (int)exceptfds;
583 args[4] = (int)timeout;
584 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
585 if (is_kerror(res)) {
586 * (__errno_location()) = -res;
587 return -1;
588 } else {
589 return res;
590 }
591}
592
593
594/* This is a wrapper round select(), which makes it thread-safe,
595 meaning that only this thread will block, rather than the entire
596 process. This wrapper in turn depends on nanosleep() not to block
597 the entire process, but I think (hope? suspect?) that POSIX
598 pthreads guarantees that to be the case.
599
600 Basic idea is: modify the timeout parameter to select so that it
601 returns immediately. Poll like this until select returns non-zero,
602 indicating something interesting happened, or until our time is up.
603 Space out the polls with nanosleeps of say 20 milliseconds, which
604 is required to be nonblocking; this allows other threads to run.
605*/
606#include <assert.h>
607
608
609int select ( int n,
610 fd_set *rfds,
611 fd_set *wfds,
612 fd_set *xfds,
613 struct timeval *timeout )
614{
615 int res;
616 fd_set rfds_copy;
617 fd_set wfds_copy;
618 fd_set xfds_copy;
619 struct vki_timeval t_now;
620 struct vki_timeval t_end;
621 struct vki_timeval zero_timeout;
622 struct vki_timespec nanosleep_interval;
623
624 ensure_valgrind("select");
625
626 /* We assume that the kernel and libc data layouts are identical
627 for the following types. These asserts provide a crude
628 check. */
629 if (sizeof(fd_set) != sizeof(vki_fd_set)
630 || sizeof(struct timeval) != sizeof(struct vki_timeval))
631 barf("valgrind's hacky non-blocking select(): data sizes error");
632
633 /* If a zero timeout specified, this call is harmless. */
634 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
635 return do_syscall_select( n, (vki_fd_set*)rfds,
636 (vki_fd_set*)wfds,
637 (vki_fd_set*)xfds,
638 (struct vki_timeval*)timeout);
639
640 /* If a timeout was specified, set t_end to be the end wallclock
641 time. */
642 if (timeout) {
643 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
644 assert(res == 0);
645 t_end = t_now;
646 t_end.tv_usec += timeout->tv_usec;
647 t_end.tv_sec += timeout->tv_sec;
648 if (t_end.tv_usec >= 1000000) {
649 t_end.tv_usec -= 1000000;
650 t_end.tv_sec += 1;
651 }
652 /* Stay sane ... */
653 assert (t_end.tv_sec > t_now.tv_sec
654 || (t_end.tv_sec == t_now.tv_sec
655 && t_end.tv_usec >= t_now.tv_usec));
656 }
657
658 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
659
660 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
661 NULL, in which case t_end holds the end time. */
662 while (1) {
663 if (timeout) {
664 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
665 assert(res == 0);
666 if (t_now.tv_sec > t_end.tv_sec
667 || (t_now.tv_sec == t_end.tv_sec
668 && t_now.tv_usec > t_end.tv_usec)) {
669 /* timeout; nothing interesting happened. */
670 if (rfds) FD_ZERO(rfds);
671 if (wfds) FD_ZERO(wfds);
672 if (xfds) FD_ZERO(xfds);
673 return 0;
674 }
675 }
676
677 /* These could be trashed each time round the loop, so restore
678 them each time. */
679 if (rfds) rfds_copy = *rfds;
680 if (wfds) wfds_copy = *wfds;
681 if (xfds) xfds_copy = *xfds;
682
683 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
684
685 res = do_syscall_select( n,
686 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
687 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
688 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
689 & zero_timeout );
690 if (res < 0) {
691 /* some kind of error (including EINTR); errno is set, so just
692 return. The sets are unspecified in this case. */
693 return res;
694 }
695 if (res > 0) {
696 /* one or more fds is ready. Copy out resulting sets and
697 return. */
698 if (rfds) *rfds = rfds_copy;
699 if (wfds) *wfds = wfds_copy;
700 if (xfds) *xfds = xfds_copy;
701 return res;
702 }
703 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
704 /* nanosleep and go round again */
705 nanosleep_interval.tv_sec = 0;
sewardj45b4b372002-04-16 22:50:32 +0000706 nanosleep_interval.tv_nsec = 40 * 1000 * 1000; /* 40 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +0000707 /* It's critical here that valgrind's nanosleep implementation
708 is nonblocking. */
709 (void)my_do_syscall2(__NR_nanosleep,
710 (int)(&nanosleep_interval), (int)NULL);
711 }
712}