blob: 435b7e292a505153a5f72819b08c3ef6872ef141 [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
sewardj6072c362002-04-19 14:40:57 +0000144int pthread_equal(pthread_t thread1, pthread_t thread2)
145{
146 return thread1 == thread2 ? 1 : 0;
147}
148
149
sewardje663cb92002-04-12 10:26:32 +0000150int
151pthread_create (pthread_t *__restrict __thread,
152 __const pthread_attr_t *__restrict __attr,
153 void *(*__start_routine) (void *),
154 void *__restrict __arg)
155{
156 int res;
157 ensure_valgrind("pthread_create");
158 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
159 VG_USERREQ__PTHREAD_CREATE,
160 __thread, __attr, __start_routine, __arg);
161 return res;
162}
163
164
165
166int
167pthread_join (pthread_t __th, void **__thread_return)
168{
169 int res;
170 ensure_valgrind("pthread_join");
171 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
172 VG_USERREQ__PTHREAD_JOIN,
173 __th, __thread_return, 0, 0);
174 return res;
175}
176
177
sewardje663cb92002-04-12 10:26:32 +0000178
179static int thread_specific_errno[VG_N_THREADS];
180
181int* __errno_location ( void )
182{
183 int tid;
184 ensure_valgrind("__errno_location");
185 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
186 VG_USERREQ__PTHREAD_GET_THREADID,
187 0, 0, 0, 0);
188 /* 'cos I'm paranoid ... */
189 if (tid < 0 || tid >= VG_N_THREADS)
190 barf("__errno_location: invalid ThreadId");
191 return & thread_specific_errno[tid];
192}
193
194
sewardjf8f819e2002-04-17 23:21:37 +0000195/* ---------------------------------------------------
196 MUTEX ATTRIBUTES
197 ------------------------------------------------ */
198
sewardje663cb92002-04-12 10:26:32 +0000199int pthread_mutexattr_init(pthread_mutexattr_t *attr)
200{
sewardjf8f819e2002-04-17 23:21:37 +0000201 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000202 return 0;
sewardje663cb92002-04-12 10:26:32 +0000203}
204
sewardjf8f819e2002-04-17 23:21:37 +0000205int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
206{
207 switch (type) {
208 case PTHREAD_MUTEX_TIMED_NP:
209 case PTHREAD_MUTEX_RECURSIVE_NP:
210 case PTHREAD_MUTEX_ERRORCHECK_NP:
211 case PTHREAD_MUTEX_ADAPTIVE_NP:
212 attr->__mutexkind = type;
213 return 0;
214 default:
215 return EINVAL;
216 }
217}
218
219int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
220{
221 return 0;
222}
223
224
225/* ---------------------------------------------------
226 MUTEXes
227 ------------------------------------------------ */
228
sewardje663cb92002-04-12 10:26:32 +0000229int pthread_mutex_init(pthread_mutex_t *mutex,
230 const pthread_mutexattr_t *mutexattr)
231{
sewardj604ec3c2002-04-18 22:38:41 +0000232 mutex->__m_count = 0;
233 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
234 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
235 if (mutexattr)
236 mutex->__m_kind = mutexattr->__mutexkind;
237 return 0;
sewardje663cb92002-04-12 10:26:32 +0000238}
239
sewardje663cb92002-04-12 10:26:32 +0000240int pthread_mutex_lock(pthread_mutex_t *mutex)
241{
242 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000243 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000244 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000245 char* str = "pthread_mutex_lock-NOT-INSIDE-VALGRIND\n";
246 write(2, str, strlen(str));
247 return 0;
248 } else {
249 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
250 VG_USERREQ__PTHREAD_MUTEX_LOCK,
251 mutex, 0, 0, 0);
252 return res;
253 }
254}
255
256int pthread_mutex_unlock(pthread_mutex_t *mutex)
257{
258 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000259 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000260 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000261 char* str = "pthread_mutex_unlock-NOT-INSIDE-VALGRIND\n";
262 write(2, str, strlen(str));
263 return 0;
264 } else {
265 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
266 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
267 mutex, 0, 0, 0);
268 return res;
269 }
270}
271
sewardje663cb92002-04-12 10:26:32 +0000272int pthread_mutex_destroy(pthread_mutex_t *mutex)
273{
sewardj604ec3c2002-04-18 22:38:41 +0000274 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
275 need to involve it. */
276 if (mutex->__m_count > 0)
277 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000278 mutex->__m_count = 0;
279 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
280 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000281 return 0;
sewardje663cb92002-04-12 10:26:32 +0000282}
283
284
sewardjf8f819e2002-04-17 23:21:37 +0000285/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000286 CONDITION VARIABLES
287 ------------------------------------------------ */
288
289/* LinuxThreads supports no attributes for conditions. Hence ... */
290
291int pthread_condattr_init(pthread_condattr_t *attr)
292{
293 return 0;
294}
295
296
297int pthread_cond_init( pthread_cond_t *cond,
298 const pthread_condattr_t *cond_attr)
299{
300 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
301 return 0;
302}
303
304
305/* ---------------------------------------------------
306 SCHEDULING
307 ------------------------------------------------ */
308
309/* This is completely bogus. */
310int pthread_getschedparam(pthread_t target_thread,
311 int *policy,
312 struct sched_param *param)
313{
314 if (policy) *policy = SCHED_OTHER;
315 if (param) param->__sched_priority = 0; /* who knows */
316 return 0;
317}
318
319int pthread_setschedparam(pthread_t target_thread,
320 int policy,
321 const struct sched_param *param)
322{
323 ignored("pthread_setschedparam");
324 return 0;
325}
326
327
328/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000329 CANCELLATION
330 ------------------------------------------------ */
331
sewardje663cb92002-04-12 10:26:32 +0000332int pthread_setcanceltype(int type, int *oldtype)
333{
sewardj2a3d28c2002-04-14 13:27:00 +0000334 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000335 return 0;
336}
337
338
339int pthread_cancel(pthread_t thread)
340{
341 int res;
342 ensure_valgrind("pthread_cancel");
343 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
344 VG_USERREQ__PTHREAD_CANCEL,
345 thread, 0, 0, 0);
346 return res;
347}
348
349
sewardjf8f819e2002-04-17 23:21:37 +0000350/* ---------------------------------------------------
351 THREAD-SPECIFICs
352 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000353
354int pthread_key_create(pthread_key_t *key,
355 void (*destr_function) (void *))
356{
sewardj2a3d28c2002-04-14 13:27:00 +0000357 ignored("pthread_key_create");
sewardj5e5fa512002-04-14 13:13:05 +0000358 return 0;
359}
360
361int pthread_key_delete(pthread_key_t key)
362{
sewardj2a3d28c2002-04-14 13:27:00 +0000363 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000364 return 0;
365}
366
367int pthread_setspecific(pthread_key_t key, const void *pointer)
368{
sewardj2a3d28c2002-04-14 13:27:00 +0000369 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000370 return 0;
371}
372
373void * pthread_getspecific(pthread_key_t key)
374{
sewardj2a3d28c2002-04-14 13:27:00 +0000375 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000376 return NULL;
377}
378
sewardjf8f819e2002-04-17 23:21:37 +0000379
380/* ---------------------------------------------------
381 MISC
382 ------------------------------------------------ */
383
384/* What are these? Anybody know? I don't. */
385
386void _pthread_cleanup_push_defer ( void )
387{
388 // char* str = "_pthread_cleanup_push_defer\n";
389 // write(2, str, strlen(str));
390}
391
392void _pthread_cleanup_pop_restore ( void )
393{
394 // char* str = "_pthread_cleanup_pop_restore\n";
395 // write(2, str, strlen(str));
396}
397
398
399pthread_t pthread_self(void)
400{
401 int tid;
402 ensure_valgrind("pthread_self");
403 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
404 VG_USERREQ__PTHREAD_GET_THREADID,
405 0, 0, 0, 0);
406 if (tid < 0 || tid >= VG_N_THREADS)
407 barf("pthread_self: invalid ThreadId");
408 return tid;
409}
410
411
sewardje663cb92002-04-12 10:26:32 +0000412/* ---------------------------------------------------------------------
413 These are here (I think) because they are deemed cancellation
414 points by POSIX. For the moment we'll simply pass the call along
415 to the corresponding thread-unaware (?) libc routine.
416 ------------------------------------------------------------------ */
417
sewardje663cb92002-04-12 10:26:32 +0000418#include <stdlib.h>
419#include <signal.h>
sewardje663cb92002-04-12 10:26:32 +0000420#include <sys/types.h>
421#include <sys/socket.h>
422
423extern
424int __libc_sigaction
425 (int signum,
426 const struct sigaction *act,
427 struct sigaction *oldact);
428int sigaction(int signum,
429 const struct sigaction *act,
430 struct sigaction *oldact)
431{
sewardj45b4b372002-04-16 22:50:32 +0000432 return __libc_sigaction(signum, act, oldact);
sewardje663cb92002-04-12 10:26:32 +0000433}
434
435
436extern
437int __libc_connect(int sockfd,
438 const struct sockaddr *serv_addr,
439 socklen_t addrlen);
440int connect(int sockfd,
441 const struct sockaddr *serv_addr,
442 socklen_t addrlen)
443{
sewardj45b4b372002-04-16 22:50:32 +0000444 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000445}
446
447
448extern
449int __libc_fcntl(int fd, int cmd, long arg);
450int fcntl(int fd, int cmd, long arg)
451{
sewardj45b4b372002-04-16 22:50:32 +0000452 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000453}
454
455
456extern
457ssize_t __libc_write(int fd, const void *buf, size_t count);
458ssize_t write(int fd, const void *buf, size_t count)
459{
sewardj45b4b372002-04-16 22:50:32 +0000460 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000461}
462
463
464extern
465ssize_t __libc_read(int fd, void *buf, size_t count);
466ssize_t read(int fd, void *buf, size_t count)
467{
sewardj45b4b372002-04-16 22:50:32 +0000468 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000469}
470
471
472extern
473int __libc_open(const char *pathname, int flags);
474int open(const char *pathname, int flags)
475{
sewardj45b4b372002-04-16 22:50:32 +0000476 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000477}
478
479
480extern
481int __libc_close(int fd);
482int close(int fd)
483{
sewardj45b4b372002-04-16 22:50:32 +0000484 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000485}
486
487
488extern
489int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
490int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
491{
sewardj45b4b372002-04-16 22:50:32 +0000492 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000493}
494
495
496extern
497pid_t __libc_fork(void);
498pid_t fork(void)
499{
sewardj45b4b372002-04-16 22:50:32 +0000500 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000501}
502
503
504extern
505pid_t __libc_waitpid(pid_t pid, int *status, int options);
506pid_t waitpid(pid_t pid, int *status, int options)
507{
sewardj45b4b372002-04-16 22:50:32 +0000508 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000509}
510
511
512extern
513int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
514int nanosleep(const struct timespec *req, struct timespec *rem)
515{
516 return __libc_nanosleep(req, rem);
517}
518
519extern
520int __libc_fsync(int fd);
521int fsync(int fd)
522{
sewardj45b4b372002-04-16 22:50:32 +0000523 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000524}
525
sewardj70c75362002-04-13 04:18:32 +0000526extern
527off_t __libc_lseek(int fildes, off_t offset, int whence);
528off_t lseek(int fildes, off_t offset, int whence)
529{
sewardj45b4b372002-04-16 22:50:32 +0000530 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000531}
532
sewardj6af4b5d2002-04-16 04:40:49 +0000533extern
534void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
535void longjmp(jmp_buf env, int val)
536{
537 __libc_longjmp(env, val);
538}
539
540extern
541int __libc_send(int s, const void *msg, size_t len, int flags);
542int send(int s, const void *msg, size_t len, int flags)
543{
544 return __libc_send(s, msg, len, flags);
545}
546
sewardj1e8cdc92002-04-18 11:37:52 +0000547extern
548int __libc_recv(int s, void *buf, size_t len, int flags);
549int recv(int s, void *buf, size_t len, int flags)
550{
551 return __libc_recv(s, buf, len, flags);
552}
553
sewardj45b4b372002-04-16 22:50:32 +0000554
sewardj70c75362002-04-13 04:18:32 +0000555/*--------------------------------------------------*/
556
sewardje663cb92002-04-12 10:26:32 +0000557/* I've no idea what these are, but they get called quite a lot.
558 Anybody know? */
559
560#undef _IO_flockfile
561void _IO_flockfile ( _IO_FILE * file )
562{
563 // char* str = "_IO_flockfile\n";
564 // write(2, str, strlen(str));
565 // barf("_IO_flockfile");
566}
567
568#undef _IO_funlockfile
569void _IO_funlockfile ( _IO_FILE * file )
570{
571 // char* str = "_IO_funlockfile\n";
572 // write(2, str, strlen(str));
573 //barf("_IO_funlockfile");
574}
575
sewardj08a4c3f2002-04-13 03:45:44 +0000576/*--------------------------------------------------*/
577
578#include "vg_kerneliface.h"
579
580static
581__inline__
582int is_kerror ( int res )
583{
584 if (res >= -4095 && res <= -1)
585 return 1;
586 else
587 return 0;
588}
589
590
591static
592int my_do_syscall1 ( int syscallno, int arg1 )
593{
594 int __res;
595 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
596 : "=a" (__res)
597 : "0" (syscallno),
598 "d" (arg1) );
599 return __res;
600}
601
602static
603int my_do_syscall2 ( int syscallno,
604 int arg1, int arg2 )
605{
606 int __res;
607 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
608 : "=a" (__res)
609 : "0" (syscallno),
610 "d" (arg1),
611 "c" (arg2) );
612 return __res;
613}
614
615static
616int do_syscall_select( int n,
617 vki_fd_set* readfds,
618 vki_fd_set* writefds,
619 vki_fd_set* exceptfds,
620 struct vki_timeval * timeout )
621{
622 int res;
623 int args[5];
624 args[0] = n;
625 args[1] = (int)readfds;
626 args[2] = (int)writefds;
627 args[3] = (int)exceptfds;
628 args[4] = (int)timeout;
629 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
630 if (is_kerror(res)) {
631 * (__errno_location()) = -res;
632 return -1;
633 } else {
634 return res;
635 }
636}
637
638
639/* This is a wrapper round select(), which makes it thread-safe,
640 meaning that only this thread will block, rather than the entire
641 process. This wrapper in turn depends on nanosleep() not to block
642 the entire process, but I think (hope? suspect?) that POSIX
643 pthreads guarantees that to be the case.
644
645 Basic idea is: modify the timeout parameter to select so that it
646 returns immediately. Poll like this until select returns non-zero,
647 indicating something interesting happened, or until our time is up.
648 Space out the polls with nanosleeps of say 20 milliseconds, which
649 is required to be nonblocking; this allows other threads to run.
650*/
651#include <assert.h>
652
653
654int select ( int n,
655 fd_set *rfds,
656 fd_set *wfds,
657 fd_set *xfds,
658 struct timeval *timeout )
659{
660 int res;
661 fd_set rfds_copy;
662 fd_set wfds_copy;
663 fd_set xfds_copy;
664 struct vki_timeval t_now;
665 struct vki_timeval t_end;
666 struct vki_timeval zero_timeout;
667 struct vki_timespec nanosleep_interval;
668
669 ensure_valgrind("select");
670
671 /* We assume that the kernel and libc data layouts are identical
672 for the following types. These asserts provide a crude
673 check. */
674 if (sizeof(fd_set) != sizeof(vki_fd_set)
675 || sizeof(struct timeval) != sizeof(struct vki_timeval))
676 barf("valgrind's hacky non-blocking select(): data sizes error");
677
678 /* If a zero timeout specified, this call is harmless. */
679 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
680 return do_syscall_select( n, (vki_fd_set*)rfds,
681 (vki_fd_set*)wfds,
682 (vki_fd_set*)xfds,
683 (struct vki_timeval*)timeout);
684
685 /* If a timeout was specified, set t_end to be the end wallclock
686 time. */
687 if (timeout) {
688 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
689 assert(res == 0);
690 t_end = t_now;
691 t_end.tv_usec += timeout->tv_usec;
692 t_end.tv_sec += timeout->tv_sec;
693 if (t_end.tv_usec >= 1000000) {
694 t_end.tv_usec -= 1000000;
695 t_end.tv_sec += 1;
696 }
697 /* Stay sane ... */
698 assert (t_end.tv_sec > t_now.tv_sec
699 || (t_end.tv_sec == t_now.tv_sec
700 && t_end.tv_usec >= t_now.tv_usec));
701 }
702
703 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
704
705 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
706 NULL, in which case t_end holds the end time. */
707 while (1) {
708 if (timeout) {
709 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
710 assert(res == 0);
711 if (t_now.tv_sec > t_end.tv_sec
712 || (t_now.tv_sec == t_end.tv_sec
713 && t_now.tv_usec > t_end.tv_usec)) {
714 /* timeout; nothing interesting happened. */
715 if (rfds) FD_ZERO(rfds);
716 if (wfds) FD_ZERO(wfds);
717 if (xfds) FD_ZERO(xfds);
718 return 0;
719 }
720 }
721
722 /* These could be trashed each time round the loop, so restore
723 them each time. */
724 if (rfds) rfds_copy = *rfds;
725 if (wfds) wfds_copy = *wfds;
726 if (xfds) xfds_copy = *xfds;
727
728 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
729
730 res = do_syscall_select( n,
731 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
732 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
733 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
734 & zero_timeout );
735 if (res < 0) {
736 /* some kind of error (including EINTR); errno is set, so just
737 return. The sets are unspecified in this case. */
738 return res;
739 }
740 if (res > 0) {
741 /* one or more fds is ready. Copy out resulting sets and
742 return. */
743 if (rfds) *rfds = rfds_copy;
744 if (wfds) *wfds = wfds_copy;
745 if (xfds) *xfds = xfds_copy;
746 return res;
747 }
748 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
749 /* nanosleep and go round again */
750 nanosleep_interval.tv_sec = 0;
sewardj604ec3c2002-04-18 22:38:41 +0000751 nanosleep_interval.tv_nsec = 20 * 1000 * 1000; /* 20 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +0000752 /* It's critical here that valgrind's nanosleep implementation
753 is nonblocking. */
754 (void)my_do_syscall2(__NR_nanosleep,
755 (int)(&nanosleep_interval), (int)NULL);
756 }
757}