blob: 33e72ab2033edcf12208abd0ebf571e15e50e21f [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
sewardj0738a592002-04-20 13:59:33 +0000311int pthread_condattr_destroy(pthread_condattr_t *attr)
312{
313 return 0;
314}
sewardj6072c362002-04-19 14:40:57 +0000315
316int pthread_cond_init( pthread_cond_t *cond,
317 const pthread_condattr_t *cond_attr)
318{
319 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
320 return 0;
321}
322
323
324/* ---------------------------------------------------
325 SCHEDULING
326 ------------------------------------------------ */
327
328/* This is completely bogus. */
329int pthread_getschedparam(pthread_t target_thread,
330 int *policy,
331 struct sched_param *param)
332{
333 if (policy) *policy = SCHED_OTHER;
334 if (param) param->__sched_priority = 0; /* who knows */
335 return 0;
336}
337
338int pthread_setschedparam(pthread_t target_thread,
339 int policy,
340 const struct sched_param *param)
341{
342 ignored("pthread_setschedparam");
343 return 0;
344}
345
sewardj3b5d8862002-04-20 13:53:23 +0000346int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
347{
348 int res;
349 ensure_valgrind("pthread_cond_wait");
350 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
351 VG_USERREQ__PTHREAD_COND_WAIT,
352 cond, mutex, 0, 0);
353 return res;
354}
355
356int pthread_cond_signal(pthread_cond_t *cond)
357{
358 int res;
359 ensure_valgrind("pthread_cond_signal");
360 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
361 VG_USERREQ__PTHREAD_COND_SIGNAL,
362 cond, 0, 0, 0);
363 return res;
364}
365
366int pthread_cond_broadcast(pthread_cond_t *cond)
367{
368 int res;
369 ensure_valgrind("pthread_cond_broadcast");
370 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
371 VG_USERREQ__PTHREAD_COND_BROADCAST,
372 cond, 0, 0, 0);
373 return res;
374}
375
sewardj6072c362002-04-19 14:40:57 +0000376
377/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000378 CANCELLATION
379 ------------------------------------------------ */
380
sewardje663cb92002-04-12 10:26:32 +0000381int pthread_setcanceltype(int type, int *oldtype)
382{
sewardj2a3d28c2002-04-14 13:27:00 +0000383 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000384 return 0;
385}
386
387
388int pthread_cancel(pthread_t thread)
389{
390 int res;
391 ensure_valgrind("pthread_cancel");
392 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
393 VG_USERREQ__PTHREAD_CANCEL,
394 thread, 0, 0, 0);
395 return res;
396}
397
398
sewardjf8f819e2002-04-17 23:21:37 +0000399/* ---------------------------------------------------
400 THREAD-SPECIFICs
401 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000402
403int pthread_key_create(pthread_key_t *key,
404 void (*destr_function) (void *))
405{
sewardj2a3d28c2002-04-14 13:27:00 +0000406 ignored("pthread_key_create");
sewardj5e5fa512002-04-14 13:13:05 +0000407 return 0;
408}
409
410int pthread_key_delete(pthread_key_t key)
411{
sewardj2a3d28c2002-04-14 13:27:00 +0000412 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000413 return 0;
414}
415
416int pthread_setspecific(pthread_key_t key, const void *pointer)
417{
sewardj2a3d28c2002-04-14 13:27:00 +0000418 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000419 return 0;
420}
421
422void * pthread_getspecific(pthread_key_t key)
423{
sewardj2a3d28c2002-04-14 13:27:00 +0000424 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000425 return NULL;
426}
427
sewardjf8f819e2002-04-17 23:21:37 +0000428
429/* ---------------------------------------------------
430 MISC
431 ------------------------------------------------ */
432
433/* What are these? Anybody know? I don't. */
434
435void _pthread_cleanup_push_defer ( void )
436{
437 // char* str = "_pthread_cleanup_push_defer\n";
438 // write(2, str, strlen(str));
439}
440
441void _pthread_cleanup_pop_restore ( void )
442{
443 // char* str = "_pthread_cleanup_pop_restore\n";
444 // write(2, str, strlen(str));
445}
446
447
448pthread_t pthread_self(void)
449{
450 int tid;
451 ensure_valgrind("pthread_self");
452 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
453 VG_USERREQ__PTHREAD_GET_THREADID,
454 0, 0, 0, 0);
455 if (tid < 0 || tid >= VG_N_THREADS)
456 barf("pthread_self: invalid ThreadId");
457 return tid;
458}
459
460
sewardje663cb92002-04-12 10:26:32 +0000461/* ---------------------------------------------------------------------
462 These are here (I think) because they are deemed cancellation
463 points by POSIX. For the moment we'll simply pass the call along
464 to the corresponding thread-unaware (?) libc routine.
465 ------------------------------------------------------------------ */
466
sewardje663cb92002-04-12 10:26:32 +0000467#include <stdlib.h>
468#include <signal.h>
sewardje663cb92002-04-12 10:26:32 +0000469#include <sys/types.h>
470#include <sys/socket.h>
471
472extern
473int __libc_sigaction
474 (int signum,
475 const struct sigaction *act,
476 struct sigaction *oldact);
477int sigaction(int signum,
478 const struct sigaction *act,
479 struct sigaction *oldact)
480{
sewardj45b4b372002-04-16 22:50:32 +0000481 return __libc_sigaction(signum, act, oldact);
sewardje663cb92002-04-12 10:26:32 +0000482}
483
484
485extern
486int __libc_connect(int sockfd,
487 const struct sockaddr *serv_addr,
488 socklen_t addrlen);
489int connect(int sockfd,
490 const struct sockaddr *serv_addr,
491 socklen_t addrlen)
492{
sewardj45b4b372002-04-16 22:50:32 +0000493 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000494}
495
496
497extern
498int __libc_fcntl(int fd, int cmd, long arg);
499int fcntl(int fd, int cmd, long arg)
500{
sewardj45b4b372002-04-16 22:50:32 +0000501 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000502}
503
504
505extern
506ssize_t __libc_write(int fd, const void *buf, size_t count);
507ssize_t write(int fd, const void *buf, size_t count)
508{
sewardj45b4b372002-04-16 22:50:32 +0000509 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000510}
511
512
513extern
514ssize_t __libc_read(int fd, void *buf, size_t count);
515ssize_t read(int fd, void *buf, size_t count)
516{
sewardj45b4b372002-04-16 22:50:32 +0000517 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000518}
519
520
521extern
522int __libc_open(const char *pathname, int flags);
523int open(const char *pathname, int flags)
524{
sewardj45b4b372002-04-16 22:50:32 +0000525 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000526}
527
528
529extern
530int __libc_close(int fd);
531int close(int fd)
532{
sewardj45b4b372002-04-16 22:50:32 +0000533 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000534}
535
536
537extern
538int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
539int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
540{
sewardj45b4b372002-04-16 22:50:32 +0000541 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000542}
543
544
545extern
546pid_t __libc_fork(void);
547pid_t fork(void)
548{
sewardj45b4b372002-04-16 22:50:32 +0000549 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000550}
551
552
553extern
554pid_t __libc_waitpid(pid_t pid, int *status, int options);
555pid_t waitpid(pid_t pid, int *status, int options)
556{
sewardj45b4b372002-04-16 22:50:32 +0000557 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000558}
559
560
561extern
562int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
563int nanosleep(const struct timespec *req, struct timespec *rem)
564{
565 return __libc_nanosleep(req, rem);
566}
567
568extern
569int __libc_fsync(int fd);
570int fsync(int fd)
571{
sewardj45b4b372002-04-16 22:50:32 +0000572 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000573}
574
sewardj70c75362002-04-13 04:18:32 +0000575extern
576off_t __libc_lseek(int fildes, off_t offset, int whence);
577off_t lseek(int fildes, off_t offset, int whence)
578{
sewardj45b4b372002-04-16 22:50:32 +0000579 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000580}
581
sewardj6af4b5d2002-04-16 04:40:49 +0000582extern
583void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
584void longjmp(jmp_buf env, int val)
585{
586 __libc_longjmp(env, val);
587}
588
589extern
590int __libc_send(int s, const void *msg, size_t len, int flags);
591int send(int s, const void *msg, size_t len, int flags)
592{
593 return __libc_send(s, msg, len, flags);
594}
595
sewardj1e8cdc92002-04-18 11:37:52 +0000596extern
597int __libc_recv(int s, void *buf, size_t len, int flags);
598int recv(int s, void *buf, size_t len, int flags)
599{
600 return __libc_recv(s, buf, len, flags);
601}
602
sewardj45b4b372002-04-16 22:50:32 +0000603
sewardj70c75362002-04-13 04:18:32 +0000604/*--------------------------------------------------*/
605
sewardje663cb92002-04-12 10:26:32 +0000606/* I've no idea what these are, but they get called quite a lot.
607 Anybody know? */
608
609#undef _IO_flockfile
610void _IO_flockfile ( _IO_FILE * file )
611{
612 // char* str = "_IO_flockfile\n";
613 // write(2, str, strlen(str));
614 // barf("_IO_flockfile");
615}
616
617#undef _IO_funlockfile
618void _IO_funlockfile ( _IO_FILE * file )
619{
620 // char* str = "_IO_funlockfile\n";
621 // write(2, str, strlen(str));
622 //barf("_IO_funlockfile");
623}
624
sewardj08a4c3f2002-04-13 03:45:44 +0000625/*--------------------------------------------------*/
626
627#include "vg_kerneliface.h"
628
629static
630__inline__
631int is_kerror ( int res )
632{
633 if (res >= -4095 && res <= -1)
634 return 1;
635 else
636 return 0;
637}
638
639
640static
641int my_do_syscall1 ( int syscallno, int arg1 )
642{
643 int __res;
644 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
645 : "=a" (__res)
646 : "0" (syscallno),
647 "d" (arg1) );
648 return __res;
649}
650
651static
652int my_do_syscall2 ( int syscallno,
653 int arg1, int arg2 )
654{
655 int __res;
656 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
657 : "=a" (__res)
658 : "0" (syscallno),
659 "d" (arg1),
660 "c" (arg2) );
661 return __res;
662}
663
664static
665int do_syscall_select( int n,
666 vki_fd_set* readfds,
667 vki_fd_set* writefds,
668 vki_fd_set* exceptfds,
669 struct vki_timeval * timeout )
670{
671 int res;
672 int args[5];
673 args[0] = n;
674 args[1] = (int)readfds;
675 args[2] = (int)writefds;
676 args[3] = (int)exceptfds;
677 args[4] = (int)timeout;
678 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
679 if (is_kerror(res)) {
680 * (__errno_location()) = -res;
681 return -1;
682 } else {
683 return res;
684 }
685}
686
687
688/* This is a wrapper round select(), which makes it thread-safe,
689 meaning that only this thread will block, rather than the entire
690 process. This wrapper in turn depends on nanosleep() not to block
691 the entire process, but I think (hope? suspect?) that POSIX
692 pthreads guarantees that to be the case.
693
694 Basic idea is: modify the timeout parameter to select so that it
695 returns immediately. Poll like this until select returns non-zero,
696 indicating something interesting happened, or until our time is up.
697 Space out the polls with nanosleeps of say 20 milliseconds, which
698 is required to be nonblocking; this allows other threads to run.
699*/
700#include <assert.h>
701
702
703int select ( int n,
704 fd_set *rfds,
705 fd_set *wfds,
706 fd_set *xfds,
707 struct timeval *timeout )
708{
709 int res;
710 fd_set rfds_copy;
711 fd_set wfds_copy;
712 fd_set xfds_copy;
713 struct vki_timeval t_now;
714 struct vki_timeval t_end;
715 struct vki_timeval zero_timeout;
716 struct vki_timespec nanosleep_interval;
717
718 ensure_valgrind("select");
719
720 /* We assume that the kernel and libc data layouts are identical
721 for the following types. These asserts provide a crude
722 check. */
723 if (sizeof(fd_set) != sizeof(vki_fd_set)
724 || sizeof(struct timeval) != sizeof(struct vki_timeval))
725 barf("valgrind's hacky non-blocking select(): data sizes error");
726
727 /* If a zero timeout specified, this call is harmless. */
728 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
729 return do_syscall_select( n, (vki_fd_set*)rfds,
730 (vki_fd_set*)wfds,
731 (vki_fd_set*)xfds,
732 (struct vki_timeval*)timeout);
733
734 /* If a timeout was specified, set t_end to be the end wallclock
735 time. */
736 if (timeout) {
737 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
738 assert(res == 0);
739 t_end = t_now;
740 t_end.tv_usec += timeout->tv_usec;
741 t_end.tv_sec += timeout->tv_sec;
742 if (t_end.tv_usec >= 1000000) {
743 t_end.tv_usec -= 1000000;
744 t_end.tv_sec += 1;
745 }
746 /* Stay sane ... */
747 assert (t_end.tv_sec > t_now.tv_sec
748 || (t_end.tv_sec == t_now.tv_sec
749 && t_end.tv_usec >= t_now.tv_usec));
750 }
751
752 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
753
754 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
755 NULL, in which case t_end holds the end time. */
756 while (1) {
757 if (timeout) {
758 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
759 assert(res == 0);
760 if (t_now.tv_sec > t_end.tv_sec
761 || (t_now.tv_sec == t_end.tv_sec
762 && t_now.tv_usec > t_end.tv_usec)) {
763 /* timeout; nothing interesting happened. */
764 if (rfds) FD_ZERO(rfds);
765 if (wfds) FD_ZERO(wfds);
766 if (xfds) FD_ZERO(xfds);
767 return 0;
768 }
769 }
770
771 /* These could be trashed each time round the loop, so restore
772 them each time. */
773 if (rfds) rfds_copy = *rfds;
774 if (wfds) wfds_copy = *wfds;
775 if (xfds) xfds_copy = *xfds;
776
777 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
778
779 res = do_syscall_select( n,
780 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
781 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
782 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
783 & zero_timeout );
784 if (res < 0) {
785 /* some kind of error (including EINTR); errno is set, so just
786 return. The sets are unspecified in this case. */
787 return res;
788 }
789 if (res > 0) {
790 /* one or more fds is ready. Copy out resulting sets and
791 return. */
792 if (rfds) *rfds = rfds_copy;
793 if (wfds) *wfds = wfds_copy;
794 if (xfds) *xfds = xfds_copy;
795 return res;
796 }
797 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
798 /* nanosleep and go round again */
799 nanosleep_interval.tv_sec = 0;
sewardj604ec3c2002-04-18 22:38:41 +0000800 nanosleep_interval.tv_nsec = 20 * 1000 * 1000; /* 20 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +0000801 /* It's critical here that valgrind's nanosleep implementation
802 is nonblocking. */
803 (void)my_do_syscall2(__NR_nanosleep,
804 (int)(&nanosleep_interval), (int)NULL);
805 }
806}