blob: f5c53616089f1b19c4514dd08c43a265fe184c10 [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
sewardjf854f472002-04-21 12:19:41 +0000376int pthread_cond_destroy(pthread_cond_t *cond)
377{
378 /* should check that no threads are waiting on this CV */
379 kludged("pthread_cond_destroy");
380 return 0;
381}
sewardj6072c362002-04-19 14:40:57 +0000382
383/* ---------------------------------------------------
384 SCHEDULING
385 ------------------------------------------------ */
386
387/* This is completely bogus. */
388int pthread_getschedparam(pthread_t target_thread,
389 int *policy,
390 struct sched_param *param)
391{
sewardj30671ff2002-04-21 00:13:57 +0000392 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000393 if (policy) *policy = SCHED_OTHER;
394 if (param) param->__sched_priority = 0; /* who knows */
395 return 0;
396}
397
398int pthread_setschedparam(pthread_t target_thread,
399 int policy,
400 const struct sched_param *param)
401{
402 ignored("pthread_setschedparam");
403 return 0;
404}
405
sewardj3b5d8862002-04-20 13:53:23 +0000406int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
407{
408 int res;
409 ensure_valgrind("pthread_cond_wait");
410 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
411 VG_USERREQ__PTHREAD_COND_WAIT,
412 cond, mutex, 0, 0);
413 return res;
414}
415
416int pthread_cond_signal(pthread_cond_t *cond)
417{
418 int res;
419 ensure_valgrind("pthread_cond_signal");
420 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
421 VG_USERREQ__PTHREAD_COND_SIGNAL,
422 cond, 0, 0, 0);
423 return res;
424}
425
426int pthread_cond_broadcast(pthread_cond_t *cond)
427{
428 int res;
429 ensure_valgrind("pthread_cond_broadcast");
430 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
431 VG_USERREQ__PTHREAD_COND_BROADCAST,
432 cond, 0, 0, 0);
433 return res;
434}
435
sewardj6072c362002-04-19 14:40:57 +0000436
437/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000438 CANCELLATION
439 ------------------------------------------------ */
440
sewardje663cb92002-04-12 10:26:32 +0000441int pthread_setcanceltype(int type, int *oldtype)
442{
sewardj2a3d28c2002-04-14 13:27:00 +0000443 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000444 return 0;
445}
446
447
448int pthread_cancel(pthread_t thread)
449{
450 int res;
451 ensure_valgrind("pthread_cancel");
452 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
453 VG_USERREQ__PTHREAD_CANCEL,
454 thread, 0, 0, 0);
455 return res;
456}
457
458
sewardjf8f819e2002-04-17 23:21:37 +0000459/* ---------------------------------------------------
460 THREAD-SPECIFICs
461 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000462
463int pthread_key_create(pthread_key_t *key,
464 void (*destr_function) (void *))
465{
sewardj2a3d28c2002-04-14 13:27:00 +0000466 ignored("pthread_key_create");
sewardj5e5fa512002-04-14 13:13:05 +0000467 return 0;
468}
469
470int pthread_key_delete(pthread_key_t key)
471{
sewardj2a3d28c2002-04-14 13:27:00 +0000472 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000473 return 0;
474}
475
476int pthread_setspecific(pthread_key_t key, const void *pointer)
477{
sewardj2a3d28c2002-04-14 13:27:00 +0000478 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000479 return 0;
480}
481
482void * pthread_getspecific(pthread_key_t key)
483{
sewardj2a3d28c2002-04-14 13:27:00 +0000484 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000485 return NULL;
486}
487
sewardjf8f819e2002-04-17 23:21:37 +0000488
489/* ---------------------------------------------------
490 MISC
491 ------------------------------------------------ */
492
493/* What are these? Anybody know? I don't. */
494
495void _pthread_cleanup_push_defer ( void )
496{
497 // char* str = "_pthread_cleanup_push_defer\n";
498 // write(2, str, strlen(str));
499}
500
501void _pthread_cleanup_pop_restore ( void )
502{
503 // char* str = "_pthread_cleanup_pop_restore\n";
504 // write(2, str, strlen(str));
505}
506
507
508pthread_t pthread_self(void)
509{
510 int tid;
511 ensure_valgrind("pthread_self");
512 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
513 VG_USERREQ__PTHREAD_GET_THREADID,
514 0, 0, 0, 0);
515 if (tid < 0 || tid >= VG_N_THREADS)
516 barf("pthread_self: invalid ThreadId");
517 return tid;
518}
519
520
sewardje663cb92002-04-12 10:26:32 +0000521/* ---------------------------------------------------------------------
522 These are here (I think) because they are deemed cancellation
523 points by POSIX. For the moment we'll simply pass the call along
524 to the corresponding thread-unaware (?) libc routine.
525 ------------------------------------------------------------------ */
526
sewardje663cb92002-04-12 10:26:32 +0000527#include <stdlib.h>
528#include <signal.h>
sewardje663cb92002-04-12 10:26:32 +0000529#include <sys/types.h>
530#include <sys/socket.h>
531
532extern
533int __libc_sigaction
534 (int signum,
535 const struct sigaction *act,
536 struct sigaction *oldact);
537int sigaction(int signum,
538 const struct sigaction *act,
539 struct sigaction *oldact)
540{
sewardj45b4b372002-04-16 22:50:32 +0000541 return __libc_sigaction(signum, act, oldact);
sewardje663cb92002-04-12 10:26:32 +0000542}
543
544
545extern
546int __libc_connect(int sockfd,
547 const struct sockaddr *serv_addr,
548 socklen_t addrlen);
549int connect(int sockfd,
550 const struct sockaddr *serv_addr,
551 socklen_t addrlen)
552{
sewardj45b4b372002-04-16 22:50:32 +0000553 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000554}
555
556
557extern
558int __libc_fcntl(int fd, int cmd, long arg);
559int fcntl(int fd, int cmd, long arg)
560{
sewardj45b4b372002-04-16 22:50:32 +0000561 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000562}
563
564
565extern
566ssize_t __libc_write(int fd, const void *buf, size_t count);
567ssize_t write(int fd, const void *buf, size_t count)
568{
sewardj45b4b372002-04-16 22:50:32 +0000569 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000570}
571
572
573extern
574ssize_t __libc_read(int fd, void *buf, size_t count);
575ssize_t read(int fd, void *buf, size_t count)
576{
sewardj45b4b372002-04-16 22:50:32 +0000577 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000578}
579
580
581extern
582int __libc_open(const char *pathname, int flags);
583int open(const char *pathname, int flags)
584{
sewardj45b4b372002-04-16 22:50:32 +0000585 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000586}
587
588
589extern
590int __libc_close(int fd);
591int close(int fd)
592{
sewardj45b4b372002-04-16 22:50:32 +0000593 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000594}
595
596
597extern
598int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
599int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
600{
sewardj45b4b372002-04-16 22:50:32 +0000601 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000602}
603
604
605extern
606pid_t __libc_fork(void);
607pid_t fork(void)
608{
sewardj45b4b372002-04-16 22:50:32 +0000609 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000610}
611
612
613extern
614pid_t __libc_waitpid(pid_t pid, int *status, int options);
615pid_t waitpid(pid_t pid, int *status, int options)
616{
sewardj45b4b372002-04-16 22:50:32 +0000617 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000618}
619
620
621extern
622int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
623int nanosleep(const struct timespec *req, struct timespec *rem)
624{
625 return __libc_nanosleep(req, rem);
626}
627
628extern
629int __libc_fsync(int fd);
630int fsync(int fd)
631{
sewardj45b4b372002-04-16 22:50:32 +0000632 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000633}
634
sewardj70c75362002-04-13 04:18:32 +0000635extern
636off_t __libc_lseek(int fildes, off_t offset, int whence);
637off_t lseek(int fildes, off_t offset, int whence)
638{
sewardj45b4b372002-04-16 22:50:32 +0000639 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000640}
641
sewardj6af4b5d2002-04-16 04:40:49 +0000642extern
643void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
644void longjmp(jmp_buf env, int val)
645{
646 __libc_longjmp(env, val);
647}
648
649extern
650int __libc_send(int s, const void *msg, size_t len, int flags);
651int send(int s, const void *msg, size_t len, int flags)
652{
653 return __libc_send(s, msg, len, flags);
654}
655
sewardj1e8cdc92002-04-18 11:37:52 +0000656extern
657int __libc_recv(int s, void *buf, size_t len, int flags);
658int recv(int s, void *buf, size_t len, int flags)
659{
660 return __libc_recv(s, buf, len, flags);
661}
662
sewardj45b4b372002-04-16 22:50:32 +0000663
sewardj70c75362002-04-13 04:18:32 +0000664/*--------------------------------------------------*/
665
sewardje663cb92002-04-12 10:26:32 +0000666/* I've no idea what these are, but they get called quite a lot.
667 Anybody know? */
668
669#undef _IO_flockfile
670void _IO_flockfile ( _IO_FILE * file )
671{
672 // char* str = "_IO_flockfile\n";
673 // write(2, str, strlen(str));
674 // barf("_IO_flockfile");
675}
676
677#undef _IO_funlockfile
678void _IO_funlockfile ( _IO_FILE * file )
679{
680 // char* str = "_IO_funlockfile\n";
681 // write(2, str, strlen(str));
682 //barf("_IO_funlockfile");
683}
684
sewardj08a4c3f2002-04-13 03:45:44 +0000685/*--------------------------------------------------*/
686
687#include "vg_kerneliface.h"
688
689static
690__inline__
691int is_kerror ( int res )
692{
693 if (res >= -4095 && res <= -1)
694 return 1;
695 else
696 return 0;
697}
698
699
700static
701int my_do_syscall1 ( int syscallno, int arg1 )
702{
703 int __res;
704 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
705 : "=a" (__res)
706 : "0" (syscallno),
707 "d" (arg1) );
708 return __res;
709}
710
711static
712int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +0000713 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +0000714{
715 int __res;
716 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
717 : "=a" (__res)
718 : "0" (syscallno),
719 "d" (arg1),
720 "c" (arg2) );
721 return __res;
722}
723
724static
sewardjf854f472002-04-21 12:19:41 +0000725int my_do_syscall3 ( int syscallno,
726 int arg1, int arg2, int arg3 )
727{
728 int __res;
729 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
730 : "=a" (__res)
731 : "0" (syscallno),
732 "S" (arg1),
733 "c" (arg2),
734 "d" (arg3) );
735 return __res;
736}
737
738static
sewardj08a4c3f2002-04-13 03:45:44 +0000739int do_syscall_select( int n,
740 vki_fd_set* readfds,
741 vki_fd_set* writefds,
742 vki_fd_set* exceptfds,
743 struct vki_timeval * timeout )
744{
745 int res;
746 int args[5];
747 args[0] = n;
748 args[1] = (int)readfds;
749 args[2] = (int)writefds;
750 args[3] = (int)exceptfds;
751 args[4] = (int)timeout;
752 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +0000753 return res;
sewardj08a4c3f2002-04-13 03:45:44 +0000754}
755
756
757/* This is a wrapper round select(), which makes it thread-safe,
758 meaning that only this thread will block, rather than the entire
759 process. This wrapper in turn depends on nanosleep() not to block
760 the entire process, but I think (hope? suspect?) that POSIX
761 pthreads guarantees that to be the case.
762
763 Basic idea is: modify the timeout parameter to select so that it
764 returns immediately. Poll like this until select returns non-zero,
765 indicating something interesting happened, or until our time is up.
766 Space out the polls with nanosleeps of say 20 milliseconds, which
767 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +0000768
769 Assumes:
770 * (checked via assert) types fd_set and vki_fd_set are identical.
771 * (checked via assert) types timeval and vki_timeval are identical.
772 * (unchecked) libc error numbers (EINTR etc) are the negation of the
773 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +0000774*/
775#include <assert.h>
776
777
778int select ( int n,
779 fd_set *rfds,
780 fd_set *wfds,
781 fd_set *xfds,
782 struct timeval *timeout )
783{
784 int res;
785 fd_set rfds_copy;
786 fd_set wfds_copy;
787 fd_set xfds_copy;
788 struct vki_timeval t_now;
789 struct vki_timeval t_end;
790 struct vki_timeval zero_timeout;
791 struct vki_timespec nanosleep_interval;
792
793 ensure_valgrind("select");
794
795 /* We assume that the kernel and libc data layouts are identical
796 for the following types. These asserts provide a crude
797 check. */
798 if (sizeof(fd_set) != sizeof(vki_fd_set)
799 || sizeof(struct timeval) != sizeof(struct vki_timeval))
800 barf("valgrind's hacky non-blocking select(): data sizes error");
801
802 /* If a zero timeout specified, this call is harmless. */
sewardj02535bc2002-04-21 01:08:26 +0000803 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
804 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +0000805 (vki_fd_set*)wfds,
806 (vki_fd_set*)xfds,
807 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +0000808 if (is_kerror(res)) {
809 * (__errno_location()) = -res;
810 return -1;
811 } else {
812 return res;
813 }
814 }
sewardj08a4c3f2002-04-13 03:45:44 +0000815
816 /* If a timeout was specified, set t_end to be the end wallclock
817 time. */
818 if (timeout) {
819 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
820 assert(res == 0);
821 t_end = t_now;
822 t_end.tv_usec += timeout->tv_usec;
823 t_end.tv_sec += timeout->tv_sec;
824 if (t_end.tv_usec >= 1000000) {
825 t_end.tv_usec -= 1000000;
826 t_end.tv_sec += 1;
827 }
828 /* Stay sane ... */
829 assert (t_end.tv_sec > t_now.tv_sec
830 || (t_end.tv_sec == t_now.tv_sec
831 && t_end.tv_usec >= t_now.tv_usec));
832 }
833
834 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
835
836 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
837 NULL, in which case t_end holds the end time. */
838 while (1) {
839 if (timeout) {
840 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
841 assert(res == 0);
842 if (t_now.tv_sec > t_end.tv_sec
843 || (t_now.tv_sec == t_end.tv_sec
844 && t_now.tv_usec > t_end.tv_usec)) {
845 /* timeout; nothing interesting happened. */
846 if (rfds) FD_ZERO(rfds);
847 if (wfds) FD_ZERO(wfds);
848 if (xfds) FD_ZERO(xfds);
849 return 0;
850 }
851 }
852
853 /* These could be trashed each time round the loop, so restore
854 them each time. */
855 if (rfds) rfds_copy = *rfds;
856 if (wfds) wfds_copy = *wfds;
857 if (xfds) xfds_copy = *xfds;
858
859 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
860
861 res = do_syscall_select( n,
862 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
863 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
864 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
865 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +0000866 if (is_kerror(res)) {
867 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +0000868 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +0000869 * (__errno_location()) = -res;
870 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +0000871 }
872 if (res > 0) {
873 /* one or more fds is ready. Copy out resulting sets and
874 return. */
875 if (rfds) *rfds = rfds_copy;
876 if (wfds) *wfds = wfds_copy;
877 if (xfds) *xfds = xfds_copy;
878 return res;
879 }
880 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
881 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +0000882 nanosleep_interval.tv_sec = 0;
sewardjf854f472002-04-21 12:19:41 +0000883 nanosleep_interval.tv_nsec = 75 * 1000 * 1000; /* 75 milliseconds */
884 /* It's critical here that valgrind's nanosleep implementation
885 is nonblocking. */
886 (void)my_do_syscall2(__NR_nanosleep,
887 (int)(&nanosleep_interval), (int)NULL);
888 }
889}
890
891
892
893
894#include <sys/poll.h>
895
896int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
897{
898 int res, i;
899 struct vki_timeval t_now;
900 struct vki_timeval t_end;
901 struct vki_timespec nanosleep_interval;
902
903 ensure_valgrind("poll");
904
905 if (/* CHECK SIZES FOR struct pollfd */
906 sizeof(struct timeval) != sizeof(struct vki_timeval))
907 barf("valgrind's hacky non-blocking poll(): data sizes error");
908
909 /* If a zero timeout specified, this call is harmless. */
910 if (__timeout == 0) {
911 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
912 if (is_kerror(res)) {
913 * (__errno_location()) = -res;
914 return -1;
915 } else {
916 return res;
917 }
918 }
919
920 /* If a timeout was specified, set t_end to be the end wallclock
921 time. */
922 if (__timeout > 0) {
923 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
924 assert(res == 0);
925 t_end = t_now;
926 t_end.tv_usec += 1000 * (__timeout % 1000);
927 t_end.tv_sec += (__timeout / 1000);
928 if (t_end.tv_usec >= 1000000) {
929 t_end.tv_usec -= 1000000;
930 t_end.tv_sec += 1;
931 }
932 /* Stay sane ... */
933 assert (t_end.tv_sec > t_now.tv_sec
934 || (t_end.tv_sec == t_now.tv_sec
935 && t_end.tv_usec >= t_now.tv_usec));
936 }
937
938 /* fprintf(stderr, "MY_POLL: before loop\n"); */
939
940 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
941 in which case t_end holds the end time. */
942 while (1) {
943 assert(__timeout != 0);
944 if (__timeout > 0) {
945 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
946 assert(res == 0);
947 if (t_now.tv_sec > t_end.tv_sec
948 || (t_now.tv_sec == t_end.tv_sec
949 && t_now.tv_usec > t_end.tv_usec)) {
950 /* timeout; nothing interesting happened. */
951 for (i = 0; i < __nfds; i++)
952 __fds[i].revents = 0;
953 return 0;
954 }
955 }
956
957 /* These could be trashed each time round the loop, so restore
958 them each time. */
959 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
960 if (is_kerror(res)) {
961 /* Some kind of error. Set errno and return. */
962 * (__errno_location()) = -res;
963 return -1;
964 }
965 if (res > 0) {
966 /* One or more fds is ready. Return now. */
967 return res;
968 }
969 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
970 /* nanosleep and go round again */
971 nanosleep_interval.tv_sec = 0;
972 nanosleep_interval.tv_nsec = 100 * 1000 * 1000; /* 100 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +0000973 /* It's critical here that valgrind's nanosleep implementation
974 is nonblocking. */
975 (void)my_do_syscall2(__NR_nanosleep,
976 (int)(&nanosleep_interval), (int)NULL);
977 }
978}