blob: e910ccf1bbca39640b55e169fb53efc44faf0351 [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. */
sewardj604ec3c2002-04-18 22:38:41 +000064static __inline__
sewardje663cb92002-04-12 10:26:32 +000065void 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{
sewardj604ec3c2002-04-18 22:38:41 +0000226 mutex->__m_count = 0;
227 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
228 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
229 if (mutexattr)
230 mutex->__m_kind = mutexattr->__mutexkind;
231 return 0;
sewardje663cb92002-04-12 10:26:32 +0000232}
233
sewardje663cb92002-04-12 10:26:32 +0000234int pthread_mutex_lock(pthread_mutex_t *mutex)
235{
236 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000237 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000238 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;
sewardj604ec3c2002-04-18 22:38:41 +0000253 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000254 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{
sewardj604ec3c2002-04-18 22:38:41 +0000268 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
269 need to involve it. */
270 if (mutex->__m_count > 0)
271 return EBUSY;
272 return 0;
sewardje663cb92002-04-12 10:26:32 +0000273}
274
275
sewardjf8f819e2002-04-17 23:21:37 +0000276/* ---------------------------------------------------
277 CANCELLATION
278 ------------------------------------------------ */
279
sewardje663cb92002-04-12 10:26:32 +0000280int pthread_setcanceltype(int type, int *oldtype)
281{
sewardj2a3d28c2002-04-14 13:27:00 +0000282 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000283 return 0;
284}
285
286
287int pthread_cancel(pthread_t thread)
288{
289 int res;
290 ensure_valgrind("pthread_cancel");
291 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
292 VG_USERREQ__PTHREAD_CANCEL,
293 thread, 0, 0, 0);
294 return res;
295}
296
297
sewardjf8f819e2002-04-17 23:21:37 +0000298/* ---------------------------------------------------
299 THREAD-SPECIFICs
300 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000301
302int pthread_key_create(pthread_key_t *key,
303 void (*destr_function) (void *))
304{
sewardj2a3d28c2002-04-14 13:27:00 +0000305 ignored("pthread_key_create");
sewardj5e5fa512002-04-14 13:13:05 +0000306 return 0;
307}
308
309int pthread_key_delete(pthread_key_t key)
310{
sewardj2a3d28c2002-04-14 13:27:00 +0000311 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000312 return 0;
313}
314
315int pthread_setspecific(pthread_key_t key, const void *pointer)
316{
sewardj2a3d28c2002-04-14 13:27:00 +0000317 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000318 return 0;
319}
320
321void * pthread_getspecific(pthread_key_t key)
322{
sewardj2a3d28c2002-04-14 13:27:00 +0000323 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000324 return NULL;
325}
326
sewardjf8f819e2002-04-17 23:21:37 +0000327
328/* ---------------------------------------------------
329 MISC
330 ------------------------------------------------ */
331
332/* What are these? Anybody know? I don't. */
333
334void _pthread_cleanup_push_defer ( void )
335{
336 // char* str = "_pthread_cleanup_push_defer\n";
337 // write(2, str, strlen(str));
338}
339
340void _pthread_cleanup_pop_restore ( void )
341{
342 // char* str = "_pthread_cleanup_pop_restore\n";
343 // write(2, str, strlen(str));
344}
345
346
347pthread_t pthread_self(void)
348{
349 int tid;
350 ensure_valgrind("pthread_self");
351 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
352 VG_USERREQ__PTHREAD_GET_THREADID,
353 0, 0, 0, 0);
354 if (tid < 0 || tid >= VG_N_THREADS)
355 barf("pthread_self: invalid ThreadId");
356 return tid;
357}
358
359
sewardje663cb92002-04-12 10:26:32 +0000360/* ---------------------------------------------------------------------
361 These are here (I think) because they are deemed cancellation
362 points by POSIX. For the moment we'll simply pass the call along
363 to the corresponding thread-unaware (?) libc routine.
364 ------------------------------------------------------------------ */
365
sewardje663cb92002-04-12 10:26:32 +0000366#include <stdlib.h>
367#include <signal.h>
sewardje663cb92002-04-12 10:26:32 +0000368#include <sys/types.h>
369#include <sys/socket.h>
370
371extern
372int __libc_sigaction
373 (int signum,
374 const struct sigaction *act,
375 struct sigaction *oldact);
376int sigaction(int signum,
377 const struct sigaction *act,
378 struct sigaction *oldact)
379{
sewardj45b4b372002-04-16 22:50:32 +0000380 return __libc_sigaction(signum, act, oldact);
sewardje663cb92002-04-12 10:26:32 +0000381}
382
383
384extern
385int __libc_connect(int sockfd,
386 const struct sockaddr *serv_addr,
387 socklen_t addrlen);
388int connect(int sockfd,
389 const struct sockaddr *serv_addr,
390 socklen_t addrlen)
391{
sewardj45b4b372002-04-16 22:50:32 +0000392 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000393}
394
395
396extern
397int __libc_fcntl(int fd, int cmd, long arg);
398int fcntl(int fd, int cmd, long arg)
399{
sewardj45b4b372002-04-16 22:50:32 +0000400 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000401}
402
403
404extern
405ssize_t __libc_write(int fd, const void *buf, size_t count);
406ssize_t write(int fd, const void *buf, size_t count)
407{
sewardj45b4b372002-04-16 22:50:32 +0000408 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000409}
410
411
412extern
413ssize_t __libc_read(int fd, void *buf, size_t count);
414ssize_t read(int fd, void *buf, size_t count)
415{
sewardj45b4b372002-04-16 22:50:32 +0000416 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000417}
418
419
420extern
421int __libc_open(const char *pathname, int flags);
422int open(const char *pathname, int flags)
423{
sewardj45b4b372002-04-16 22:50:32 +0000424 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000425}
426
427
428extern
429int __libc_close(int fd);
430int close(int fd)
431{
sewardj45b4b372002-04-16 22:50:32 +0000432 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000433}
434
435
436extern
437int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
438int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
439{
sewardj45b4b372002-04-16 22:50:32 +0000440 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000441}
442
443
444extern
445pid_t __libc_fork(void);
446pid_t fork(void)
447{
sewardj45b4b372002-04-16 22:50:32 +0000448 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000449}
450
451
452extern
453pid_t __libc_waitpid(pid_t pid, int *status, int options);
454pid_t waitpid(pid_t pid, int *status, int options)
455{
sewardj45b4b372002-04-16 22:50:32 +0000456 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000457}
458
459
460extern
461int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
462int nanosleep(const struct timespec *req, struct timespec *rem)
463{
464 return __libc_nanosleep(req, rem);
465}
466
467extern
468int __libc_fsync(int fd);
469int fsync(int fd)
470{
sewardj45b4b372002-04-16 22:50:32 +0000471 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000472}
473
sewardj70c75362002-04-13 04:18:32 +0000474extern
475off_t __libc_lseek(int fildes, off_t offset, int whence);
476off_t lseek(int fildes, off_t offset, int whence)
477{
sewardj45b4b372002-04-16 22:50:32 +0000478 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000479}
480
sewardj6af4b5d2002-04-16 04:40:49 +0000481extern
482void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
483void longjmp(jmp_buf env, int val)
484{
485 __libc_longjmp(env, val);
486}
487
488extern
489int __libc_send(int s, const void *msg, size_t len, int flags);
490int send(int s, const void *msg, size_t len, int flags)
491{
492 return __libc_send(s, msg, len, flags);
493}
494
sewardj1e8cdc92002-04-18 11:37:52 +0000495extern
496int __libc_recv(int s, void *buf, size_t len, int flags);
497int recv(int s, void *buf, size_t len, int flags)
498{
499 return __libc_recv(s, buf, 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;
sewardj604ec3c2002-04-18 22:38:41 +0000699 nanosleep_interval.tv_nsec = 20 * 1000 * 1000; /* 20 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}