blob: 3ecd6f1145b73a3549e19ef31be1aaf6427b41b0 [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
sewardj3b5d8862002-04-20 13:53:23 +000090__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +000091void barf ( char* str )
92{
93 char buf[100];
94 buf[0] = 0;
95 strcat(buf, "\nvg_libpthread.so: ");
96 strcat(buf, str);
97 strcat(buf, "\n\n");
98 write(2, buf, strlen(buf));
99 myexit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000100 /* We have to persuade gcc into believing this doesn't return. */
101 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000102}
103
104
sewardj2a3d28c2002-04-14 13:27:00 +0000105static void ignored ( char* msg )
106{
sewardj45b4b372002-04-16 22:50:32 +0000107 if (get_pt_trace_level() >= 1) {
108 char* ig = "vg_libpthread.so: IGNORED call to: ";
109 write(2, ig, strlen(ig));
110 write(2, msg, strlen(msg));
111 ig = "\n";
112 write(2, ig, strlen(ig));
113 }
sewardj2a3d28c2002-04-14 13:27:00 +0000114}
115
sewardje663cb92002-04-12 10:26:32 +0000116
117/* ---------------------------------------------------------------------
118 Pass pthread_ calls to Valgrind's request mechanism.
119 ------------------------------------------------------------------ */
120
sewardjf8f819e2002-04-17 23:21:37 +0000121#include <pthread.h>
122#include <stdio.h>
123#include <errno.h>
124
125/* ---------------------------------------------------
126 THREAD ATTRIBUTES
127 ------------------------------------------------ */
128
sewardj6af4b5d2002-04-16 04:40:49 +0000129int pthread_attr_init(pthread_attr_t *attr)
130{
131 ignored("pthread_attr_init");
132 return 0;
133}
134
135int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
136{
137 ignored("pthread_attr_setdetachstate");
138 return 0;
139}
140
141
sewardjf8f819e2002-04-17 23:21:37 +0000142
143/* ---------------------------------------------------
144 THREADs
145 ------------------------------------------------ */
146
sewardj6072c362002-04-19 14:40:57 +0000147int pthread_equal(pthread_t thread1, pthread_t thread2)
148{
149 return thread1 == thread2 ? 1 : 0;
150}
151
152
sewardje663cb92002-04-12 10:26:32 +0000153int
154pthread_create (pthread_t *__restrict __thread,
155 __const pthread_attr_t *__restrict __attr,
156 void *(*__start_routine) (void *),
157 void *__restrict __arg)
158{
159 int res;
160 ensure_valgrind("pthread_create");
161 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
162 VG_USERREQ__PTHREAD_CREATE,
163 __thread, __attr, __start_routine, __arg);
164 return res;
165}
166
167
168
169int
170pthread_join (pthread_t __th, void **__thread_return)
171{
172 int res;
173 ensure_valgrind("pthread_join");
174 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
175 VG_USERREQ__PTHREAD_JOIN,
176 __th, __thread_return, 0, 0);
177 return res;
178}
179
180
sewardj3b5d8862002-04-20 13:53:23 +0000181void pthread_exit(void *retval)
182{
183 int res;
184 ensure_valgrind("pthread_exit");
185 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
186 VG_USERREQ__PTHREAD_EXIT,
187 retval, 0, 0, 0);
188 /* Doesn't return! */
189 /* However, we have to fool gcc into knowing that. */
190 barf("pthread_exit: still alive after request?!");
191}
192
sewardje663cb92002-04-12 10:26:32 +0000193
194static int thread_specific_errno[VG_N_THREADS];
195
196int* __errno_location ( void )
197{
198 int tid;
199 ensure_valgrind("__errno_location");
200 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
201 VG_USERREQ__PTHREAD_GET_THREADID,
202 0, 0, 0, 0);
203 /* 'cos I'm paranoid ... */
204 if (tid < 0 || tid >= VG_N_THREADS)
205 barf("__errno_location: invalid ThreadId");
206 return & thread_specific_errno[tid];
207}
208
209
sewardjf8f819e2002-04-17 23:21:37 +0000210/* ---------------------------------------------------
211 MUTEX ATTRIBUTES
212 ------------------------------------------------ */
213
sewardje663cb92002-04-12 10:26:32 +0000214int pthread_mutexattr_init(pthread_mutexattr_t *attr)
215{
sewardjf8f819e2002-04-17 23:21:37 +0000216 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000217 return 0;
sewardje663cb92002-04-12 10:26:32 +0000218}
219
sewardjf8f819e2002-04-17 23:21:37 +0000220int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
221{
222 switch (type) {
223 case PTHREAD_MUTEX_TIMED_NP:
224 case PTHREAD_MUTEX_RECURSIVE_NP:
225 case PTHREAD_MUTEX_ERRORCHECK_NP:
226 case PTHREAD_MUTEX_ADAPTIVE_NP:
227 attr->__mutexkind = type;
228 return 0;
229 default:
230 return EINVAL;
231 }
232}
233
234int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
235{
236 return 0;
237}
238
239
240/* ---------------------------------------------------
241 MUTEXes
242 ------------------------------------------------ */
243
sewardje663cb92002-04-12 10:26:32 +0000244int pthread_mutex_init(pthread_mutex_t *mutex,
245 const pthread_mutexattr_t *mutexattr)
246{
sewardj604ec3c2002-04-18 22:38:41 +0000247 mutex->__m_count = 0;
248 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
249 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
250 if (mutexattr)
251 mutex->__m_kind = mutexattr->__mutexkind;
252 return 0;
sewardje663cb92002-04-12 10:26:32 +0000253}
254
sewardje663cb92002-04-12 10:26:32 +0000255int pthread_mutex_lock(pthread_mutex_t *mutex)
256{
257 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000258 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000259 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000260 char* str = "pthread_mutex_lock-NOT-INSIDE-VALGRIND\n";
261 write(2, str, strlen(str));
262 return 0;
263 } else {
264 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
265 VG_USERREQ__PTHREAD_MUTEX_LOCK,
266 mutex, 0, 0, 0);
267 return res;
268 }
269}
270
271int pthread_mutex_unlock(pthread_mutex_t *mutex)
272{
273 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000274 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000275 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000276 char* str = "pthread_mutex_unlock-NOT-INSIDE-VALGRIND\n";
277 write(2, str, strlen(str));
278 return 0;
279 } else {
280 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
281 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
282 mutex, 0, 0, 0);
283 return res;
284 }
285}
286
sewardje663cb92002-04-12 10:26:32 +0000287int pthread_mutex_destroy(pthread_mutex_t *mutex)
288{
sewardj604ec3c2002-04-18 22:38:41 +0000289 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
290 need to involve it. */
291 if (mutex->__m_count > 0)
292 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000293 mutex->__m_count = 0;
294 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
295 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000296 return 0;
sewardje663cb92002-04-12 10:26:32 +0000297}
298
299
sewardjf8f819e2002-04-17 23:21:37 +0000300/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000301 CONDITION VARIABLES
302 ------------------------------------------------ */
303
304/* LinuxThreads supports no attributes for conditions. Hence ... */
305
306int pthread_condattr_init(pthread_condattr_t *attr)
307{
308 return 0;
309}
310
311
312int pthread_cond_init( pthread_cond_t *cond,
313 const pthread_condattr_t *cond_attr)
314{
315 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
316 return 0;
317}
318
319
320/* ---------------------------------------------------
321 SCHEDULING
322 ------------------------------------------------ */
323
324/* This is completely bogus. */
325int pthread_getschedparam(pthread_t target_thread,
326 int *policy,
327 struct sched_param *param)
328{
329 if (policy) *policy = SCHED_OTHER;
330 if (param) param->__sched_priority = 0; /* who knows */
331 return 0;
332}
333
334int pthread_setschedparam(pthread_t target_thread,
335 int policy,
336 const struct sched_param *param)
337{
338 ignored("pthread_setschedparam");
339 return 0;
340}
341
sewardj3b5d8862002-04-20 13:53:23 +0000342int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
343{
344 int res;
345 ensure_valgrind("pthread_cond_wait");
346 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
347 VG_USERREQ__PTHREAD_COND_WAIT,
348 cond, mutex, 0, 0);
349 return res;
350}
351
352int pthread_cond_signal(pthread_cond_t *cond)
353{
354 int res;
355 ensure_valgrind("pthread_cond_signal");
356 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
357 VG_USERREQ__PTHREAD_COND_SIGNAL,
358 cond, 0, 0, 0);
359 return res;
360}
361
362int pthread_cond_broadcast(pthread_cond_t *cond)
363{
364 int res;
365 ensure_valgrind("pthread_cond_broadcast");
366 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
367 VG_USERREQ__PTHREAD_COND_BROADCAST,
368 cond, 0, 0, 0);
369 return res;
370}
371
sewardj6072c362002-04-19 14:40:57 +0000372
373/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000374 CANCELLATION
375 ------------------------------------------------ */
376
sewardje663cb92002-04-12 10:26:32 +0000377int pthread_setcanceltype(int type, int *oldtype)
378{
sewardj2a3d28c2002-04-14 13:27:00 +0000379 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000380 return 0;
381}
382
383
384int pthread_cancel(pthread_t thread)
385{
386 int res;
387 ensure_valgrind("pthread_cancel");
388 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
389 VG_USERREQ__PTHREAD_CANCEL,
390 thread, 0, 0, 0);
391 return res;
392}
393
394
sewardjf8f819e2002-04-17 23:21:37 +0000395/* ---------------------------------------------------
396 THREAD-SPECIFICs
397 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000398
399int pthread_key_create(pthread_key_t *key,
400 void (*destr_function) (void *))
401{
sewardj2a3d28c2002-04-14 13:27:00 +0000402 ignored("pthread_key_create");
sewardj5e5fa512002-04-14 13:13:05 +0000403 return 0;
404}
405
406int pthread_key_delete(pthread_key_t key)
407{
sewardj2a3d28c2002-04-14 13:27:00 +0000408 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000409 return 0;
410}
411
412int pthread_setspecific(pthread_key_t key, const void *pointer)
413{
sewardj2a3d28c2002-04-14 13:27:00 +0000414 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000415 return 0;
416}
417
418void * pthread_getspecific(pthread_key_t key)
419{
sewardj2a3d28c2002-04-14 13:27:00 +0000420 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000421 return NULL;
422}
423
sewardjf8f819e2002-04-17 23:21:37 +0000424
425/* ---------------------------------------------------
426 MISC
427 ------------------------------------------------ */
428
429/* What are these? Anybody know? I don't. */
430
431void _pthread_cleanup_push_defer ( void )
432{
433 // char* str = "_pthread_cleanup_push_defer\n";
434 // write(2, str, strlen(str));
435}
436
437void _pthread_cleanup_pop_restore ( void )
438{
439 // char* str = "_pthread_cleanup_pop_restore\n";
440 // write(2, str, strlen(str));
441}
442
443
444pthread_t pthread_self(void)
445{
446 int tid;
447 ensure_valgrind("pthread_self");
448 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
449 VG_USERREQ__PTHREAD_GET_THREADID,
450 0, 0, 0, 0);
451 if (tid < 0 || tid >= VG_N_THREADS)
452 barf("pthread_self: invalid ThreadId");
453 return tid;
454}
455
456
sewardje663cb92002-04-12 10:26:32 +0000457/* ---------------------------------------------------------------------
458 These are here (I think) because they are deemed cancellation
459 points by POSIX. For the moment we'll simply pass the call along
460 to the corresponding thread-unaware (?) libc routine.
461 ------------------------------------------------------------------ */
462
sewardje663cb92002-04-12 10:26:32 +0000463#include <stdlib.h>
464#include <signal.h>
sewardje663cb92002-04-12 10:26:32 +0000465#include <sys/types.h>
466#include <sys/socket.h>
467
468extern
469int __libc_sigaction
470 (int signum,
471 const struct sigaction *act,
472 struct sigaction *oldact);
473int sigaction(int signum,
474 const struct sigaction *act,
475 struct sigaction *oldact)
476{
sewardj45b4b372002-04-16 22:50:32 +0000477 return __libc_sigaction(signum, act, oldact);
sewardje663cb92002-04-12 10:26:32 +0000478}
479
480
481extern
482int __libc_connect(int sockfd,
483 const struct sockaddr *serv_addr,
484 socklen_t addrlen);
485int connect(int sockfd,
486 const struct sockaddr *serv_addr,
487 socklen_t addrlen)
488{
sewardj45b4b372002-04-16 22:50:32 +0000489 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000490}
491
492
493extern
494int __libc_fcntl(int fd, int cmd, long arg);
495int fcntl(int fd, int cmd, long arg)
496{
sewardj45b4b372002-04-16 22:50:32 +0000497 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000498}
499
500
501extern
502ssize_t __libc_write(int fd, const void *buf, size_t count);
503ssize_t write(int fd, const void *buf, size_t count)
504{
sewardj45b4b372002-04-16 22:50:32 +0000505 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000506}
507
508
509extern
510ssize_t __libc_read(int fd, void *buf, size_t count);
511ssize_t read(int fd, void *buf, size_t count)
512{
sewardj45b4b372002-04-16 22:50:32 +0000513 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000514}
515
516
517extern
518int __libc_open(const char *pathname, int flags);
519int open(const char *pathname, int flags)
520{
sewardj45b4b372002-04-16 22:50:32 +0000521 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000522}
523
524
525extern
526int __libc_close(int fd);
527int close(int fd)
528{
sewardj45b4b372002-04-16 22:50:32 +0000529 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000530}
531
532
533extern
534int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
535int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
536{
sewardj45b4b372002-04-16 22:50:32 +0000537 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000538}
539
540
541extern
542pid_t __libc_fork(void);
543pid_t fork(void)
544{
sewardj45b4b372002-04-16 22:50:32 +0000545 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000546}
547
548
549extern
550pid_t __libc_waitpid(pid_t pid, int *status, int options);
551pid_t waitpid(pid_t pid, int *status, int options)
552{
sewardj45b4b372002-04-16 22:50:32 +0000553 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000554}
555
556
557extern
558int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
559int nanosleep(const struct timespec *req, struct timespec *rem)
560{
561 return __libc_nanosleep(req, rem);
562}
563
564extern
565int __libc_fsync(int fd);
566int fsync(int fd)
567{
sewardj45b4b372002-04-16 22:50:32 +0000568 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000569}
570
sewardj70c75362002-04-13 04:18:32 +0000571extern
572off_t __libc_lseek(int fildes, off_t offset, int whence);
573off_t lseek(int fildes, off_t offset, int whence)
574{
sewardj45b4b372002-04-16 22:50:32 +0000575 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000576}
577
sewardj6af4b5d2002-04-16 04:40:49 +0000578extern
579void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
580void longjmp(jmp_buf env, int val)
581{
582 __libc_longjmp(env, val);
583}
584
585extern
586int __libc_send(int s, const void *msg, size_t len, int flags);
587int send(int s, const void *msg, size_t len, int flags)
588{
589 return __libc_send(s, msg, len, flags);
590}
591
sewardj1e8cdc92002-04-18 11:37:52 +0000592extern
593int __libc_recv(int s, void *buf, size_t len, int flags);
594int recv(int s, void *buf, size_t len, int flags)
595{
596 return __libc_recv(s, buf, len, flags);
597}
598
sewardj45b4b372002-04-16 22:50:32 +0000599
sewardj70c75362002-04-13 04:18:32 +0000600/*--------------------------------------------------*/
601
sewardje663cb92002-04-12 10:26:32 +0000602/* I've no idea what these are, but they get called quite a lot.
603 Anybody know? */
604
605#undef _IO_flockfile
606void _IO_flockfile ( _IO_FILE * file )
607{
608 // char* str = "_IO_flockfile\n";
609 // write(2, str, strlen(str));
610 // barf("_IO_flockfile");
611}
612
613#undef _IO_funlockfile
614void _IO_funlockfile ( _IO_FILE * file )
615{
616 // char* str = "_IO_funlockfile\n";
617 // write(2, str, strlen(str));
618 //barf("_IO_funlockfile");
619}
620
sewardj08a4c3f2002-04-13 03:45:44 +0000621/*--------------------------------------------------*/
622
623#include "vg_kerneliface.h"
624
625static
626__inline__
627int is_kerror ( int res )
628{
629 if (res >= -4095 && res <= -1)
630 return 1;
631 else
632 return 0;
633}
634
635
636static
637int my_do_syscall1 ( int syscallno, int arg1 )
638{
639 int __res;
640 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
641 : "=a" (__res)
642 : "0" (syscallno),
643 "d" (arg1) );
644 return __res;
645}
646
647static
648int my_do_syscall2 ( int syscallno,
649 int arg1, int arg2 )
650{
651 int __res;
652 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
653 : "=a" (__res)
654 : "0" (syscallno),
655 "d" (arg1),
656 "c" (arg2) );
657 return __res;
658}
659
660static
661int do_syscall_select( int n,
662 vki_fd_set* readfds,
663 vki_fd_set* writefds,
664 vki_fd_set* exceptfds,
665 struct vki_timeval * timeout )
666{
667 int res;
668 int args[5];
669 args[0] = n;
670 args[1] = (int)readfds;
671 args[2] = (int)writefds;
672 args[3] = (int)exceptfds;
673 args[4] = (int)timeout;
674 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
675 if (is_kerror(res)) {
676 * (__errno_location()) = -res;
677 return -1;
678 } else {
679 return res;
680 }
681}
682
683
684/* This is a wrapper round select(), which makes it thread-safe,
685 meaning that only this thread will block, rather than the entire
686 process. This wrapper in turn depends on nanosleep() not to block
687 the entire process, but I think (hope? suspect?) that POSIX
688 pthreads guarantees that to be the case.
689
690 Basic idea is: modify the timeout parameter to select so that it
691 returns immediately. Poll like this until select returns non-zero,
692 indicating something interesting happened, or until our time is up.
693 Space out the polls with nanosleeps of say 20 milliseconds, which
694 is required to be nonblocking; this allows other threads to run.
695*/
696#include <assert.h>
697
698
699int select ( int n,
700 fd_set *rfds,
701 fd_set *wfds,
702 fd_set *xfds,
703 struct timeval *timeout )
704{
705 int res;
706 fd_set rfds_copy;
707 fd_set wfds_copy;
708 fd_set xfds_copy;
709 struct vki_timeval t_now;
710 struct vki_timeval t_end;
711 struct vki_timeval zero_timeout;
712 struct vki_timespec nanosleep_interval;
713
714 ensure_valgrind("select");
715
716 /* We assume that the kernel and libc data layouts are identical
717 for the following types. These asserts provide a crude
718 check. */
719 if (sizeof(fd_set) != sizeof(vki_fd_set)
720 || sizeof(struct timeval) != sizeof(struct vki_timeval))
721 barf("valgrind's hacky non-blocking select(): data sizes error");
722
723 /* If a zero timeout specified, this call is harmless. */
724 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
725 return do_syscall_select( n, (vki_fd_set*)rfds,
726 (vki_fd_set*)wfds,
727 (vki_fd_set*)xfds,
728 (struct vki_timeval*)timeout);
729
730 /* If a timeout was specified, set t_end to be the end wallclock
731 time. */
732 if (timeout) {
733 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
734 assert(res == 0);
735 t_end = t_now;
736 t_end.tv_usec += timeout->tv_usec;
737 t_end.tv_sec += timeout->tv_sec;
738 if (t_end.tv_usec >= 1000000) {
739 t_end.tv_usec -= 1000000;
740 t_end.tv_sec += 1;
741 }
742 /* Stay sane ... */
743 assert (t_end.tv_sec > t_now.tv_sec
744 || (t_end.tv_sec == t_now.tv_sec
745 && t_end.tv_usec >= t_now.tv_usec));
746 }
747
748 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
749
750 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
751 NULL, in which case t_end holds the end time. */
752 while (1) {
753 if (timeout) {
754 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
755 assert(res == 0);
756 if (t_now.tv_sec > t_end.tv_sec
757 || (t_now.tv_sec == t_end.tv_sec
758 && t_now.tv_usec > t_end.tv_usec)) {
759 /* timeout; nothing interesting happened. */
760 if (rfds) FD_ZERO(rfds);
761 if (wfds) FD_ZERO(wfds);
762 if (xfds) FD_ZERO(xfds);
763 return 0;
764 }
765 }
766
767 /* These could be trashed each time round the loop, so restore
768 them each time. */
769 if (rfds) rfds_copy = *rfds;
770 if (wfds) wfds_copy = *wfds;
771 if (xfds) xfds_copy = *xfds;
772
773 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
774
775 res = do_syscall_select( n,
776 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
777 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
778 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
779 & zero_timeout );
780 if (res < 0) {
781 /* some kind of error (including EINTR); errno is set, so just
782 return. The sets are unspecified in this case. */
783 return res;
784 }
785 if (res > 0) {
786 /* one or more fds is ready. Copy out resulting sets and
787 return. */
788 if (rfds) *rfds = rfds_copy;
789 if (wfds) *wfds = wfds_copy;
790 if (xfds) *xfds = xfds_copy;
791 return res;
792 }
793 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
794 /* nanosleep and go round again */
795 nanosleep_interval.tv_sec = 0;
sewardj604ec3c2002-04-18 22:38:41 +0000796 nanosleep_interval.tv_nsec = 20 * 1000 * 1000; /* 20 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +0000797 /* It's critical here that valgrind's nanosleep implementation
798 is nonblocking. */
799 (void)my_do_syscall2(__NR_nanosleep,
800 (int)(&nanosleep_interval), (int)NULL);
801 }
802}