blob: f32c5533eaa60d03c6d61654fa2fe50052d26cd5 [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
sewardj45b4b372002-04-16 22:50:32 +0000502
sewardj70c75362002-04-13 04:18:32 +0000503/*--------------------------------------------------*/
504
sewardje663cb92002-04-12 10:26:32 +0000505/* I've no idea what these are, but they get called quite a lot.
506 Anybody know? */
507
508#undef _IO_flockfile
509void _IO_flockfile ( _IO_FILE * file )
510{
511 // char* str = "_IO_flockfile\n";
512 // write(2, str, strlen(str));
513 // barf("_IO_flockfile");
514}
515
516#undef _IO_funlockfile
517void _IO_funlockfile ( _IO_FILE * file )
518{
519 // char* str = "_IO_funlockfile\n";
520 // write(2, str, strlen(str));
521 //barf("_IO_funlockfile");
522}
523
sewardj08a4c3f2002-04-13 03:45:44 +0000524/*--------------------------------------------------*/
525
526#include "vg_kerneliface.h"
527
528static
529__inline__
530int is_kerror ( int res )
531{
532 if (res >= -4095 && res <= -1)
533 return 1;
534 else
535 return 0;
536}
537
538
539static
540int my_do_syscall1 ( int syscallno, int arg1 )
541{
542 int __res;
543 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
544 : "=a" (__res)
545 : "0" (syscallno),
546 "d" (arg1) );
547 return __res;
548}
549
550static
551int my_do_syscall2 ( int syscallno,
552 int arg1, int arg2 )
553{
554 int __res;
555 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
556 : "=a" (__res)
557 : "0" (syscallno),
558 "d" (arg1),
559 "c" (arg2) );
560 return __res;
561}
562
563static
564int do_syscall_select( int n,
565 vki_fd_set* readfds,
566 vki_fd_set* writefds,
567 vki_fd_set* exceptfds,
568 struct vki_timeval * timeout )
569{
570 int res;
571 int args[5];
572 args[0] = n;
573 args[1] = (int)readfds;
574 args[2] = (int)writefds;
575 args[3] = (int)exceptfds;
576 args[4] = (int)timeout;
577 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
578 if (is_kerror(res)) {
579 * (__errno_location()) = -res;
580 return -1;
581 } else {
582 return res;
583 }
584}
585
586
587/* This is a wrapper round select(), which makes it thread-safe,
588 meaning that only this thread will block, rather than the entire
589 process. This wrapper in turn depends on nanosleep() not to block
590 the entire process, but I think (hope? suspect?) that POSIX
591 pthreads guarantees that to be the case.
592
593 Basic idea is: modify the timeout parameter to select so that it
594 returns immediately. Poll like this until select returns non-zero,
595 indicating something interesting happened, or until our time is up.
596 Space out the polls with nanosleeps of say 20 milliseconds, which
597 is required to be nonblocking; this allows other threads to run.
598*/
599#include <assert.h>
600
601
602int select ( int n,
603 fd_set *rfds,
604 fd_set *wfds,
605 fd_set *xfds,
606 struct timeval *timeout )
607{
608 int res;
609 fd_set rfds_copy;
610 fd_set wfds_copy;
611 fd_set xfds_copy;
612 struct vki_timeval t_now;
613 struct vki_timeval t_end;
614 struct vki_timeval zero_timeout;
615 struct vki_timespec nanosleep_interval;
616
617 ensure_valgrind("select");
618
619 /* We assume that the kernel and libc data layouts are identical
620 for the following types. These asserts provide a crude
621 check. */
622 if (sizeof(fd_set) != sizeof(vki_fd_set)
623 || sizeof(struct timeval) != sizeof(struct vki_timeval))
624 barf("valgrind's hacky non-blocking select(): data sizes error");
625
626 /* If a zero timeout specified, this call is harmless. */
627 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
628 return do_syscall_select( n, (vki_fd_set*)rfds,
629 (vki_fd_set*)wfds,
630 (vki_fd_set*)xfds,
631 (struct vki_timeval*)timeout);
632
633 /* If a timeout was specified, set t_end to be the end wallclock
634 time. */
635 if (timeout) {
636 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
637 assert(res == 0);
638 t_end = t_now;
639 t_end.tv_usec += timeout->tv_usec;
640 t_end.tv_sec += timeout->tv_sec;
641 if (t_end.tv_usec >= 1000000) {
642 t_end.tv_usec -= 1000000;
643 t_end.tv_sec += 1;
644 }
645 /* Stay sane ... */
646 assert (t_end.tv_sec > t_now.tv_sec
647 || (t_end.tv_sec == t_now.tv_sec
648 && t_end.tv_usec >= t_now.tv_usec));
649 }
650
651 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
652
653 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
654 NULL, in which case t_end holds the end time. */
655 while (1) {
656 if (timeout) {
657 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
658 assert(res == 0);
659 if (t_now.tv_sec > t_end.tv_sec
660 || (t_now.tv_sec == t_end.tv_sec
661 && t_now.tv_usec > t_end.tv_usec)) {
662 /* timeout; nothing interesting happened. */
663 if (rfds) FD_ZERO(rfds);
664 if (wfds) FD_ZERO(wfds);
665 if (xfds) FD_ZERO(xfds);
666 return 0;
667 }
668 }
669
670 /* These could be trashed each time round the loop, so restore
671 them each time. */
672 if (rfds) rfds_copy = *rfds;
673 if (wfds) wfds_copy = *wfds;
674 if (xfds) xfds_copy = *xfds;
675
676 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
677
678 res = do_syscall_select( n,
679 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
680 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
681 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
682 & zero_timeout );
683 if (res < 0) {
684 /* some kind of error (including EINTR); errno is set, so just
685 return. The sets are unspecified in this case. */
686 return res;
687 }
688 if (res > 0) {
689 /* one or more fds is ready. Copy out resulting sets and
690 return. */
691 if (rfds) *rfds = rfds_copy;
692 if (wfds) *wfds = wfds_copy;
693 if (xfds) *xfds = xfds_copy;
694 return res;
695 }
696 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
697 /* nanosleep and go round again */
698 nanosleep_interval.tv_sec = 0;
sewardj45b4b372002-04-16 22:50:32 +0000699 nanosleep_interval.tv_nsec = 40 * 1000 * 1000; /* 40 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +0000700 /* It's critical here that valgrind's nanosleep implementation
701 is nonblocking. */
702 (void)my_do_syscall2(__NR_nanosleep,
703 (int)(&nanosleep_interval), (int)NULL);
704 }
705}