blob: 6bdf09affc6c2239c3bc7c469b8e2cd505be1f48 [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
sewardj30671ff2002-04-21 00:13:57 +0000116static void kludged ( char* msg )
117{
118 if (get_pt_trace_level() >= 1) {
119 char* ig = "vg_libpthread.so: KLUDGED call to: ";
120 write(2, ig, strlen(ig));
121 write(2, msg, strlen(msg));
122 ig = "\n";
123 write(2, ig, strlen(ig));
124 }
125}
126
sewardje663cb92002-04-12 10:26:32 +0000127
128/* ---------------------------------------------------------------------
129 Pass pthread_ calls to Valgrind's request mechanism.
130 ------------------------------------------------------------------ */
131
sewardjf8f819e2002-04-17 23:21:37 +0000132#include <pthread.h>
133#include <stdio.h>
134#include <errno.h>
135
136/* ---------------------------------------------------
137 THREAD ATTRIBUTES
138 ------------------------------------------------ */
139
sewardj6af4b5d2002-04-16 04:40:49 +0000140int pthread_attr_init(pthread_attr_t *attr)
141{
142 ignored("pthread_attr_init");
143 return 0;
144}
145
146int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
147{
148 ignored("pthread_attr_setdetachstate");
149 return 0;
150}
151
sewardj30671ff2002-04-21 00:13:57 +0000152int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
153{
154 ignored("pthread_attr_setinheritsched");
155 return 0;
156}
sewardj6af4b5d2002-04-16 04:40:49 +0000157
sewardj30671ff2002-04-21 00:13:57 +0000158/* This is completely bogus. */
159int pthread_attr_getschedparam(const pthread_attr_t *attr,
160 struct sched_param *param)
161{
162 kludged("pthread_attr_getschedparam");
163 if (param) param->__sched_priority = 0; /* who knows */
164 return 0;
165}
166
167int pthread_attr_setschedparam(pthread_attr_t *attr,
168 const struct sched_param *param)
169{
170 ignored("pthread_attr_setschedparam");
171 return 0;
172}
173
174int pthread_attr_destroy(pthread_attr_t *attr)
175{
176 ignored("pthread_attr_destroy");
177 return 0;
178}
sewardjf8f819e2002-04-17 23:21:37 +0000179
180/* ---------------------------------------------------
181 THREADs
182 ------------------------------------------------ */
183
sewardj6072c362002-04-19 14:40:57 +0000184int pthread_equal(pthread_t thread1, pthread_t thread2)
185{
186 return thread1 == thread2 ? 1 : 0;
187}
188
189
sewardje663cb92002-04-12 10:26:32 +0000190int
191pthread_create (pthread_t *__restrict __thread,
192 __const pthread_attr_t *__restrict __attr,
193 void *(*__start_routine) (void *),
194 void *__restrict __arg)
195{
196 int res;
197 ensure_valgrind("pthread_create");
198 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
199 VG_USERREQ__PTHREAD_CREATE,
200 __thread, __attr, __start_routine, __arg);
201 return res;
202}
203
204
205
206int
207pthread_join (pthread_t __th, void **__thread_return)
208{
209 int res;
210 ensure_valgrind("pthread_join");
211 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
212 VG_USERREQ__PTHREAD_JOIN,
213 __th, __thread_return, 0, 0);
214 return res;
215}
216
217
sewardj3b5d8862002-04-20 13:53:23 +0000218void pthread_exit(void *retval)
219{
220 int res;
221 ensure_valgrind("pthread_exit");
222 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
223 VG_USERREQ__PTHREAD_EXIT,
224 retval, 0, 0, 0);
225 /* Doesn't return! */
226 /* However, we have to fool gcc into knowing that. */
227 barf("pthread_exit: still alive after request?!");
228}
229
sewardje663cb92002-04-12 10:26:32 +0000230
231static int thread_specific_errno[VG_N_THREADS];
232
233int* __errno_location ( void )
234{
235 int tid;
236 ensure_valgrind("__errno_location");
237 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
238 VG_USERREQ__PTHREAD_GET_THREADID,
239 0, 0, 0, 0);
240 /* 'cos I'm paranoid ... */
241 if (tid < 0 || tid >= VG_N_THREADS)
242 barf("__errno_location: invalid ThreadId");
243 return & thread_specific_errno[tid];
244}
245
246
sewardjf8f819e2002-04-17 23:21:37 +0000247/* ---------------------------------------------------
248 MUTEX ATTRIBUTES
249 ------------------------------------------------ */
250
sewardje663cb92002-04-12 10:26:32 +0000251int pthread_mutexattr_init(pthread_mutexattr_t *attr)
252{
sewardjf8f819e2002-04-17 23:21:37 +0000253 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000254 return 0;
sewardje663cb92002-04-12 10:26:32 +0000255}
256
sewardjf8f819e2002-04-17 23:21:37 +0000257int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
258{
259 switch (type) {
260 case PTHREAD_MUTEX_TIMED_NP:
261 case PTHREAD_MUTEX_RECURSIVE_NP:
262 case PTHREAD_MUTEX_ERRORCHECK_NP:
263 case PTHREAD_MUTEX_ADAPTIVE_NP:
264 attr->__mutexkind = type;
265 return 0;
266 default:
267 return EINVAL;
268 }
269}
270
271int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
272{
273 return 0;
274}
275
276
277/* ---------------------------------------------------
278 MUTEXes
279 ------------------------------------------------ */
280
sewardje663cb92002-04-12 10:26:32 +0000281int pthread_mutex_init(pthread_mutex_t *mutex,
282 const pthread_mutexattr_t *mutexattr)
283{
sewardj604ec3c2002-04-18 22:38:41 +0000284 mutex->__m_count = 0;
285 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
286 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
287 if (mutexattr)
288 mutex->__m_kind = mutexattr->__mutexkind;
289 return 0;
sewardje663cb92002-04-12 10:26:32 +0000290}
291
sewardje663cb92002-04-12 10:26:32 +0000292int pthread_mutex_lock(pthread_mutex_t *mutex)
293{
294 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000295 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000296 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000297 char* str = "pthread_mutex_lock-NOT-INSIDE-VALGRIND\n";
298 write(2, str, strlen(str));
299 return 0;
300 } else {
301 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
302 VG_USERREQ__PTHREAD_MUTEX_LOCK,
303 mutex, 0, 0, 0);
304 return res;
305 }
306}
307
sewardj30671ff2002-04-21 00:13:57 +0000308int pthread_mutex_trylock(pthread_mutex_t *mutex)
309{
310 int res;
311 static int moans = 3;
312 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
313 char* str = "pthread_mutex_trylock-NOT-INSIDE-VALGRIND\n";
314 write(2, str, strlen(str));
315 return 0;
316 } else {
317 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
318 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
319 mutex, 0, 0, 0);
320 return res;
321 }
322}
323
sewardje663cb92002-04-12 10:26:32 +0000324int pthread_mutex_unlock(pthread_mutex_t *mutex)
325{
326 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000327 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000328 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000329 char* str = "pthread_mutex_unlock-NOT-INSIDE-VALGRIND\n";
330 write(2, str, strlen(str));
331 return 0;
332 } else {
333 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
334 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
335 mutex, 0, 0, 0);
336 return res;
337 }
338}
339
sewardje663cb92002-04-12 10:26:32 +0000340int pthread_mutex_destroy(pthread_mutex_t *mutex)
341{
sewardj604ec3c2002-04-18 22:38:41 +0000342 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
343 need to involve it. */
344 if (mutex->__m_count > 0)
345 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000346 mutex->__m_count = 0;
347 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
348 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000349 return 0;
sewardje663cb92002-04-12 10:26:32 +0000350}
351
352
sewardjf8f819e2002-04-17 23:21:37 +0000353/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000354 CONDITION VARIABLES
355 ------------------------------------------------ */
356
357/* LinuxThreads supports no attributes for conditions. Hence ... */
358
359int pthread_condattr_init(pthread_condattr_t *attr)
360{
361 return 0;
362}
363
sewardj0738a592002-04-20 13:59:33 +0000364int pthread_condattr_destroy(pthread_condattr_t *attr)
365{
366 return 0;
367}
sewardj6072c362002-04-19 14:40:57 +0000368
369int pthread_cond_init( pthread_cond_t *cond,
370 const pthread_condattr_t *cond_attr)
371{
372 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
373 return 0;
374}
375
376
377/* ---------------------------------------------------
378 SCHEDULING
379 ------------------------------------------------ */
380
381/* This is completely bogus. */
382int pthread_getschedparam(pthread_t target_thread,
383 int *policy,
384 struct sched_param *param)
385{
sewardj30671ff2002-04-21 00:13:57 +0000386 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000387 if (policy) *policy = SCHED_OTHER;
388 if (param) param->__sched_priority = 0; /* who knows */
389 return 0;
390}
391
392int pthread_setschedparam(pthread_t target_thread,
393 int policy,
394 const struct sched_param *param)
395{
396 ignored("pthread_setschedparam");
397 return 0;
398}
399
sewardj3b5d8862002-04-20 13:53:23 +0000400int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
401{
402 int res;
403 ensure_valgrind("pthread_cond_wait");
404 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
405 VG_USERREQ__PTHREAD_COND_WAIT,
406 cond, mutex, 0, 0);
407 return res;
408}
409
410int pthread_cond_signal(pthread_cond_t *cond)
411{
412 int res;
413 ensure_valgrind("pthread_cond_signal");
414 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
415 VG_USERREQ__PTHREAD_COND_SIGNAL,
416 cond, 0, 0, 0);
417 return res;
418}
419
420int pthread_cond_broadcast(pthread_cond_t *cond)
421{
422 int res;
423 ensure_valgrind("pthread_cond_broadcast");
424 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
425 VG_USERREQ__PTHREAD_COND_BROADCAST,
426 cond, 0, 0, 0);
427 return res;
428}
429
sewardj6072c362002-04-19 14:40:57 +0000430
431/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000432 CANCELLATION
433 ------------------------------------------------ */
434
sewardje663cb92002-04-12 10:26:32 +0000435int pthread_setcanceltype(int type, int *oldtype)
436{
sewardj2a3d28c2002-04-14 13:27:00 +0000437 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000438 return 0;
439}
440
441
442int pthread_cancel(pthread_t thread)
443{
444 int res;
445 ensure_valgrind("pthread_cancel");
446 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
447 VG_USERREQ__PTHREAD_CANCEL,
448 thread, 0, 0, 0);
449 return res;
450}
451
452
sewardjf8f819e2002-04-17 23:21:37 +0000453/* ---------------------------------------------------
454 THREAD-SPECIFICs
455 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000456
457int pthread_key_create(pthread_key_t *key,
458 void (*destr_function) (void *))
459{
sewardj2a3d28c2002-04-14 13:27:00 +0000460 ignored("pthread_key_create");
sewardj5e5fa512002-04-14 13:13:05 +0000461 return 0;
462}
463
464int pthread_key_delete(pthread_key_t key)
465{
sewardj2a3d28c2002-04-14 13:27:00 +0000466 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000467 return 0;
468}
469
470int pthread_setspecific(pthread_key_t key, const void *pointer)
471{
sewardj2a3d28c2002-04-14 13:27:00 +0000472 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000473 return 0;
474}
475
476void * pthread_getspecific(pthread_key_t key)
477{
sewardj2a3d28c2002-04-14 13:27:00 +0000478 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000479 return NULL;
480}
481
sewardjf8f819e2002-04-17 23:21:37 +0000482
483/* ---------------------------------------------------
484 MISC
485 ------------------------------------------------ */
486
487/* What are these? Anybody know? I don't. */
488
489void _pthread_cleanup_push_defer ( void )
490{
491 // char* str = "_pthread_cleanup_push_defer\n";
492 // write(2, str, strlen(str));
493}
494
495void _pthread_cleanup_pop_restore ( void )
496{
497 // char* str = "_pthread_cleanup_pop_restore\n";
498 // write(2, str, strlen(str));
499}
500
501
502pthread_t pthread_self(void)
503{
504 int tid;
505 ensure_valgrind("pthread_self");
506 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
507 VG_USERREQ__PTHREAD_GET_THREADID,
508 0, 0, 0, 0);
509 if (tid < 0 || tid >= VG_N_THREADS)
510 barf("pthread_self: invalid ThreadId");
511 return tid;
512}
513
514
sewardje663cb92002-04-12 10:26:32 +0000515/* ---------------------------------------------------------------------
516 These are here (I think) because they are deemed cancellation
517 points by POSIX. For the moment we'll simply pass the call along
518 to the corresponding thread-unaware (?) libc routine.
519 ------------------------------------------------------------------ */
520
sewardje663cb92002-04-12 10:26:32 +0000521#include <stdlib.h>
522#include <signal.h>
sewardje663cb92002-04-12 10:26:32 +0000523#include <sys/types.h>
524#include <sys/socket.h>
525
526extern
527int __libc_sigaction
528 (int signum,
529 const struct sigaction *act,
530 struct sigaction *oldact);
531int sigaction(int signum,
532 const struct sigaction *act,
533 struct sigaction *oldact)
534{
sewardj45b4b372002-04-16 22:50:32 +0000535 return __libc_sigaction(signum, act, oldact);
sewardje663cb92002-04-12 10:26:32 +0000536}
537
538
539extern
540int __libc_connect(int sockfd,
541 const struct sockaddr *serv_addr,
542 socklen_t addrlen);
543int connect(int sockfd,
544 const struct sockaddr *serv_addr,
545 socklen_t addrlen)
546{
sewardj45b4b372002-04-16 22:50:32 +0000547 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000548}
549
550
551extern
552int __libc_fcntl(int fd, int cmd, long arg);
553int fcntl(int fd, int cmd, long arg)
554{
sewardj45b4b372002-04-16 22:50:32 +0000555 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000556}
557
558
559extern
560ssize_t __libc_write(int fd, const void *buf, size_t count);
561ssize_t write(int fd, const void *buf, size_t count)
562{
sewardj45b4b372002-04-16 22:50:32 +0000563 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000564}
565
566
567extern
568ssize_t __libc_read(int fd, void *buf, size_t count);
569ssize_t read(int fd, void *buf, size_t count)
570{
sewardj45b4b372002-04-16 22:50:32 +0000571 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000572}
573
574
575extern
576int __libc_open(const char *pathname, int flags);
577int open(const char *pathname, int flags)
578{
sewardj45b4b372002-04-16 22:50:32 +0000579 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000580}
581
582
583extern
584int __libc_close(int fd);
585int close(int fd)
586{
sewardj45b4b372002-04-16 22:50:32 +0000587 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000588}
589
590
591extern
592int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
593int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
594{
sewardj45b4b372002-04-16 22:50:32 +0000595 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000596}
597
598
599extern
600pid_t __libc_fork(void);
601pid_t fork(void)
602{
sewardj45b4b372002-04-16 22:50:32 +0000603 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000604}
605
606
607extern
608pid_t __libc_waitpid(pid_t pid, int *status, int options);
609pid_t waitpid(pid_t pid, int *status, int options)
610{
sewardj45b4b372002-04-16 22:50:32 +0000611 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000612}
613
614
615extern
616int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
617int nanosleep(const struct timespec *req, struct timespec *rem)
618{
619 return __libc_nanosleep(req, rem);
620}
621
622extern
623int __libc_fsync(int fd);
624int fsync(int fd)
625{
sewardj45b4b372002-04-16 22:50:32 +0000626 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000627}
628
sewardj70c75362002-04-13 04:18:32 +0000629extern
630off_t __libc_lseek(int fildes, off_t offset, int whence);
631off_t lseek(int fildes, off_t offset, int whence)
632{
sewardj45b4b372002-04-16 22:50:32 +0000633 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000634}
635
sewardj6af4b5d2002-04-16 04:40:49 +0000636extern
637void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
638void longjmp(jmp_buf env, int val)
639{
640 __libc_longjmp(env, val);
641}
642
643extern
644int __libc_send(int s, const void *msg, size_t len, int flags);
645int send(int s, const void *msg, size_t len, int flags)
646{
647 return __libc_send(s, msg, len, flags);
648}
649
sewardj1e8cdc92002-04-18 11:37:52 +0000650extern
651int __libc_recv(int s, void *buf, size_t len, int flags);
652int recv(int s, void *buf, size_t len, int flags)
653{
654 return __libc_recv(s, buf, len, flags);
655}
656
sewardj45b4b372002-04-16 22:50:32 +0000657
sewardj70c75362002-04-13 04:18:32 +0000658/*--------------------------------------------------*/
659
sewardje663cb92002-04-12 10:26:32 +0000660/* I've no idea what these are, but they get called quite a lot.
661 Anybody know? */
662
663#undef _IO_flockfile
664void _IO_flockfile ( _IO_FILE * file )
665{
666 // char* str = "_IO_flockfile\n";
667 // write(2, str, strlen(str));
668 // barf("_IO_flockfile");
669}
670
671#undef _IO_funlockfile
672void _IO_funlockfile ( _IO_FILE * file )
673{
674 // char* str = "_IO_funlockfile\n";
675 // write(2, str, strlen(str));
676 //barf("_IO_funlockfile");
677}
678
sewardj08a4c3f2002-04-13 03:45:44 +0000679/*--------------------------------------------------*/
680
681#include "vg_kerneliface.h"
682
683static
684__inline__
685int is_kerror ( int res )
686{
687 if (res >= -4095 && res <= -1)
688 return 1;
689 else
690 return 0;
691}
692
693
694static
695int my_do_syscall1 ( int syscallno, int arg1 )
696{
697 int __res;
698 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
699 : "=a" (__res)
700 : "0" (syscallno),
701 "d" (arg1) );
702 return __res;
703}
704
705static
706int my_do_syscall2 ( int syscallno,
707 int arg1, int arg2 )
708{
709 int __res;
710 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
711 : "=a" (__res)
712 : "0" (syscallno),
713 "d" (arg1),
714 "c" (arg2) );
715 return __res;
716}
717
718static
719int do_syscall_select( int n,
720 vki_fd_set* readfds,
721 vki_fd_set* writefds,
722 vki_fd_set* exceptfds,
723 struct vki_timeval * timeout )
724{
725 int res;
726 int args[5];
727 args[0] = n;
728 args[1] = (int)readfds;
729 args[2] = (int)writefds;
730 args[3] = (int)exceptfds;
731 args[4] = (int)timeout;
732 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
733 if (is_kerror(res)) {
734 * (__errno_location()) = -res;
735 return -1;
736 } else {
737 return res;
738 }
739}
740
741
742/* This is a wrapper round select(), which makes it thread-safe,
743 meaning that only this thread will block, rather than the entire
744 process. This wrapper in turn depends on nanosleep() not to block
745 the entire process, but I think (hope? suspect?) that POSIX
746 pthreads guarantees that to be the case.
747
748 Basic idea is: modify the timeout parameter to select so that it
749 returns immediately. Poll like this until select returns non-zero,
750 indicating something interesting happened, or until our time is up.
751 Space out the polls with nanosleeps of say 20 milliseconds, which
752 is required to be nonblocking; this allows other threads to run.
753*/
754#include <assert.h>
755
756
757int select ( int n,
758 fd_set *rfds,
759 fd_set *wfds,
760 fd_set *xfds,
761 struct timeval *timeout )
762{
763 int res;
764 fd_set rfds_copy;
765 fd_set wfds_copy;
766 fd_set xfds_copy;
767 struct vki_timeval t_now;
768 struct vki_timeval t_end;
769 struct vki_timeval zero_timeout;
770 struct vki_timespec nanosleep_interval;
771
772 ensure_valgrind("select");
773
774 /* We assume that the kernel and libc data layouts are identical
775 for the following types. These asserts provide a crude
776 check. */
777 if (sizeof(fd_set) != sizeof(vki_fd_set)
778 || sizeof(struct timeval) != sizeof(struct vki_timeval))
779 barf("valgrind's hacky non-blocking select(): data sizes error");
780
781 /* If a zero timeout specified, this call is harmless. */
782 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
783 return do_syscall_select( n, (vki_fd_set*)rfds,
784 (vki_fd_set*)wfds,
785 (vki_fd_set*)xfds,
786 (struct vki_timeval*)timeout);
787
788 /* If a timeout was specified, set t_end to be the end wallclock
789 time. */
790 if (timeout) {
791 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
792 assert(res == 0);
793 t_end = t_now;
794 t_end.tv_usec += timeout->tv_usec;
795 t_end.tv_sec += timeout->tv_sec;
796 if (t_end.tv_usec >= 1000000) {
797 t_end.tv_usec -= 1000000;
798 t_end.tv_sec += 1;
799 }
800 /* Stay sane ... */
801 assert (t_end.tv_sec > t_now.tv_sec
802 || (t_end.tv_sec == t_now.tv_sec
803 && t_end.tv_usec >= t_now.tv_usec));
804 }
805
806 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
807
808 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
809 NULL, in which case t_end holds the end time. */
810 while (1) {
811 if (timeout) {
812 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
813 assert(res == 0);
814 if (t_now.tv_sec > t_end.tv_sec
815 || (t_now.tv_sec == t_end.tv_sec
816 && t_now.tv_usec > t_end.tv_usec)) {
817 /* timeout; nothing interesting happened. */
818 if (rfds) FD_ZERO(rfds);
819 if (wfds) FD_ZERO(wfds);
820 if (xfds) FD_ZERO(xfds);
821 return 0;
822 }
823 }
824
825 /* These could be trashed each time round the loop, so restore
826 them each time. */
827 if (rfds) rfds_copy = *rfds;
828 if (wfds) wfds_copy = *wfds;
829 if (xfds) xfds_copy = *xfds;
830
831 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
832
833 res = do_syscall_select( n,
834 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
835 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
836 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
837 & zero_timeout );
838 if (res < 0) {
839 /* some kind of error (including EINTR); errno is set, so just
840 return. The sets are unspecified in this case. */
841 return res;
842 }
843 if (res > 0) {
844 /* one or more fds is ready. Copy out resulting sets and
845 return. */
846 if (rfds) *rfds = rfds_copy;
847 if (wfds) *wfds = wfds_copy;
848 if (xfds) *xfds = xfds_copy;
849 return res;
850 }
851 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
852 /* nanosleep and go round again */
853 nanosleep_interval.tv_sec = 0;
sewardj604ec3c2002-04-18 22:38:41 +0000854 nanosleep_interval.tv_nsec = 20 * 1000 * 1000; /* 20 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +0000855 /* It's critical here that valgrind's nanosleep implementation
856 is nonblocking. */
857 (void)my_do_syscall2(__NR_nanosleep,
858 (int)(&nanosleep_interval), (int)NULL);
859 }
860}