blob: 76923a3c779a3d9745d1714b1324b6d83134d044 [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>
sewardj2a1dcce2002-04-22 12:45:25 +000028#ifdef GLIBC_2_1
29#include <sys/time.h>
30#endif
sewardje663cb92002-04-12 10:26:32 +000031
32/* ---------------------------------------------------------------------
33 Helpers. We have to be pretty self-sufficient.
34 ------------------------------------------------------------------ */
35
sewardj45b4b372002-04-16 22:50:32 +000036/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
37 Returns 0 (none) if not running on Valgrind. */
38static
39int get_pt_trace_level ( void )
40{
41 int res;
42 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
43 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
44 0, 0, 0, 0);
45 return res;
46}
47
48
49
sewardje663cb92002-04-12 10:26:32 +000050static
51void myexit ( int arg )
52{
sewardj45b4b372002-04-16 22:50:32 +000053 int __res;
sewardje663cb92002-04-12 10:26:32 +000054 __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
55 : "=a" (__res)
56 : "0" (__NR_exit),
57 "c" (arg) );
sewardj45b4b372002-04-16 22:50:32 +000058 /* We don't bother to mention the fact that this asm trashes %ebx,
59 since it won't return. If you ever do let it return ... fix
60 this! */
sewardje663cb92002-04-12 10:26:32 +000061}
62
63
64/* Give up without using printf etc, since they seem to give
65 segfaults. */
sewardj604ec3c2002-04-18 22:38:41 +000066static __inline__
sewardje663cb92002-04-12 10:26:32 +000067void ensure_valgrind ( char* caller )
68{
69 char* str;
70 int is_valgrind = RUNNING_ON_VALGRIND;
71 if (!is_valgrind) {
72 str = "\nvalgrind-ed process: vg_libpthread.so: "
73 "pthread call when\n";
74 write(2, str, strlen(str));
75 str = "not running on valgrind; aborting! "
76 "This is probably a bug in\n";
77 write(2, str, strlen(str));
78 str = "valgrind. Please report it to me at: "
79 "jseward@acm.org. Thanks.\n";
80 write(2, str, strlen(str));
81 str = "unexpectedly called function is: ";
82 write(2, str, strlen(str));
83 write(2, caller, strlen(caller));
84 str = "\n\n";
85 write(2, str, strlen(str));
86 myexit(1);
87 }
88}
89
90
91static
sewardj3b5d8862002-04-20 13:53:23 +000092__attribute__((noreturn))
sewardje663cb92002-04-12 10:26:32 +000093void barf ( char* str )
94{
95 char buf[100];
96 buf[0] = 0;
97 strcat(buf, "\nvg_libpthread.so: ");
98 strcat(buf, str);
99 strcat(buf, "\n\n");
100 write(2, buf, strlen(buf));
101 myexit(1);
sewardj3b5d8862002-04-20 13:53:23 +0000102 /* We have to persuade gcc into believing this doesn't return. */
103 while (1) { };
sewardje663cb92002-04-12 10:26:32 +0000104}
105
106
sewardj2a3d28c2002-04-14 13:27:00 +0000107static void ignored ( char* msg )
108{
sewardj45b4b372002-04-16 22:50:32 +0000109 if (get_pt_trace_level() >= 1) {
110 char* ig = "vg_libpthread.so: IGNORED call to: ";
111 write(2, ig, strlen(ig));
112 write(2, msg, strlen(msg));
113 ig = "\n";
114 write(2, ig, strlen(ig));
115 }
sewardj2a3d28c2002-04-14 13:27:00 +0000116}
117
sewardj30671ff2002-04-21 00:13:57 +0000118static void kludged ( char* msg )
119{
120 if (get_pt_trace_level() >= 1) {
121 char* ig = "vg_libpthread.so: KLUDGED call to: ";
122 write(2, ig, strlen(ig));
123 write(2, msg, strlen(msg));
124 ig = "\n";
125 write(2, ig, strlen(ig));
126 }
127}
128
sewardje663cb92002-04-12 10:26:32 +0000129
130/* ---------------------------------------------------------------------
131 Pass pthread_ calls to Valgrind's request mechanism.
132 ------------------------------------------------------------------ */
133
sewardjf8f819e2002-04-17 23:21:37 +0000134#include <pthread.h>
135#include <stdio.h>
136#include <errno.h>
sewardj5f07b662002-04-23 16:52:51 +0000137#include <assert.h>
138#include <sys/time.h> /* gettimeofday */
sewardjf8f819e2002-04-17 23:21:37 +0000139
140/* ---------------------------------------------------
141 THREAD ATTRIBUTES
142 ------------------------------------------------ */
143
sewardj6af4b5d2002-04-16 04:40:49 +0000144int pthread_attr_init(pthread_attr_t *attr)
145{
146 ignored("pthread_attr_init");
147 return 0;
148}
149
150int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
151{
152 ignored("pthread_attr_setdetachstate");
153 return 0;
154}
155
sewardj30671ff2002-04-21 00:13:57 +0000156int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
157{
158 ignored("pthread_attr_setinheritsched");
159 return 0;
160}
sewardj6af4b5d2002-04-16 04:40:49 +0000161
sewardj30671ff2002-04-21 00:13:57 +0000162/* This is completely bogus. */
163int pthread_attr_getschedparam(const pthread_attr_t *attr,
164 struct sched_param *param)
165{
166 kludged("pthread_attr_getschedparam");
167 if (param) param->__sched_priority = 0; /* who knows */
168 return 0;
169}
170
171int pthread_attr_setschedparam(pthread_attr_t *attr,
172 const struct sched_param *param)
173{
174 ignored("pthread_attr_setschedparam");
175 return 0;
176}
177
178int pthread_attr_destroy(pthread_attr_t *attr)
179{
180 ignored("pthread_attr_destroy");
181 return 0;
182}
sewardjf8f819e2002-04-17 23:21:37 +0000183
184/* ---------------------------------------------------
185 THREADs
186 ------------------------------------------------ */
187
sewardj6072c362002-04-19 14:40:57 +0000188int pthread_equal(pthread_t thread1, pthread_t thread2)
189{
190 return thread1 == thread2 ? 1 : 0;
191}
192
193
sewardje663cb92002-04-12 10:26:32 +0000194int
195pthread_create (pthread_t *__restrict __thread,
196 __const pthread_attr_t *__restrict __attr,
197 void *(*__start_routine) (void *),
198 void *__restrict __arg)
199{
200 int res;
201 ensure_valgrind("pthread_create");
202 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
203 VG_USERREQ__PTHREAD_CREATE,
204 __thread, __attr, __start_routine, __arg);
205 return res;
206}
207
208
209
210int
211pthread_join (pthread_t __th, void **__thread_return)
212{
213 int res;
214 ensure_valgrind("pthread_join");
215 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
216 VG_USERREQ__PTHREAD_JOIN,
217 __th, __thread_return, 0, 0);
218 return res;
219}
220
221
sewardj3b5d8862002-04-20 13:53:23 +0000222void pthread_exit(void *retval)
223{
224 int res;
225 ensure_valgrind("pthread_exit");
226 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
227 VG_USERREQ__PTHREAD_EXIT,
228 retval, 0, 0, 0);
229 /* Doesn't return! */
230 /* However, we have to fool gcc into knowing that. */
231 barf("pthread_exit: still alive after request?!");
232}
233
sewardje663cb92002-04-12 10:26:32 +0000234
235static int thread_specific_errno[VG_N_THREADS];
236
237int* __errno_location ( void )
238{
239 int tid;
sewardj35805422002-04-21 13:05:34 +0000240 /* ensure_valgrind("__errno_location"); */
sewardje663cb92002-04-12 10:26:32 +0000241 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
242 VG_USERREQ__PTHREAD_GET_THREADID,
243 0, 0, 0, 0);
244 /* 'cos I'm paranoid ... */
245 if (tid < 0 || tid >= VG_N_THREADS)
246 barf("__errno_location: invalid ThreadId");
247 return & thread_specific_errno[tid];
248}
249
250
sewardjf8f819e2002-04-17 23:21:37 +0000251/* ---------------------------------------------------
252 MUTEX ATTRIBUTES
253 ------------------------------------------------ */
254
sewardje663cb92002-04-12 10:26:32 +0000255int pthread_mutexattr_init(pthread_mutexattr_t *attr)
256{
sewardjf8f819e2002-04-17 23:21:37 +0000257 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000258 return 0;
sewardje663cb92002-04-12 10:26:32 +0000259}
260
sewardjf8f819e2002-04-17 23:21:37 +0000261int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
262{
263 switch (type) {
sewardj2a1dcce2002-04-22 12:45:25 +0000264#ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000265 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000266 case PTHREAD_MUTEX_ADAPTIVE_NP:
267#endif
sewardjf8f819e2002-04-17 23:21:37 +0000268 case PTHREAD_MUTEX_RECURSIVE_NP:
269 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000270 attr->__mutexkind = type;
271 return 0;
272 default:
273 return EINVAL;
274 }
275}
276
277int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
278{
279 return 0;
280}
281
282
283/* ---------------------------------------------------
284 MUTEXes
285 ------------------------------------------------ */
286
sewardje663cb92002-04-12 10:26:32 +0000287int pthread_mutex_init(pthread_mutex_t *mutex,
288 const pthread_mutexattr_t *mutexattr)
289{
sewardj604ec3c2002-04-18 22:38:41 +0000290 mutex->__m_count = 0;
291 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
292 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
293 if (mutexattr)
294 mutex->__m_kind = mutexattr->__mutexkind;
295 return 0;
sewardje663cb92002-04-12 10:26:32 +0000296}
297
sewardje663cb92002-04-12 10:26:32 +0000298int pthread_mutex_lock(pthread_mutex_t *mutex)
299{
300 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000301 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000302 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000303 char* str = "pthread_mutex_lock-NOT-INSIDE-VALGRIND\n";
304 write(2, str, strlen(str));
305 return 0;
306 } else {
307 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
308 VG_USERREQ__PTHREAD_MUTEX_LOCK,
309 mutex, 0, 0, 0);
310 return res;
311 }
312}
313
sewardj30671ff2002-04-21 00:13:57 +0000314int pthread_mutex_trylock(pthread_mutex_t *mutex)
315{
316 int res;
317 static int moans = 3;
318 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
319 char* str = "pthread_mutex_trylock-NOT-INSIDE-VALGRIND\n";
320 write(2, str, strlen(str));
321 return 0;
322 } else {
323 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
324 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
325 mutex, 0, 0, 0);
326 return res;
327 }
328}
329
sewardje663cb92002-04-12 10:26:32 +0000330int pthread_mutex_unlock(pthread_mutex_t *mutex)
331{
332 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000333 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000334 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000335 char* str = "pthread_mutex_unlock-NOT-INSIDE-VALGRIND\n";
336 write(2, str, strlen(str));
337 return 0;
338 } else {
339 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
340 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
341 mutex, 0, 0, 0);
342 return res;
343 }
344}
345
sewardje663cb92002-04-12 10:26:32 +0000346int pthread_mutex_destroy(pthread_mutex_t *mutex)
347{
sewardj604ec3c2002-04-18 22:38:41 +0000348 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
349 need to involve it. */
350 if (mutex->__m_count > 0)
351 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000352 mutex->__m_count = 0;
353 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
354 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000355 return 0;
sewardje663cb92002-04-12 10:26:32 +0000356}
357
358
sewardjf8f819e2002-04-17 23:21:37 +0000359/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000360 CONDITION VARIABLES
361 ------------------------------------------------ */
362
363/* LinuxThreads supports no attributes for conditions. Hence ... */
364
365int pthread_condattr_init(pthread_condattr_t *attr)
366{
367 return 0;
368}
369
sewardj0738a592002-04-20 13:59:33 +0000370int pthread_condattr_destroy(pthread_condattr_t *attr)
371{
372 return 0;
373}
sewardj6072c362002-04-19 14:40:57 +0000374
375int pthread_cond_init( pthread_cond_t *cond,
376 const pthread_condattr_t *cond_attr)
377{
378 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
379 return 0;
380}
381
sewardjf854f472002-04-21 12:19:41 +0000382int pthread_cond_destroy(pthread_cond_t *cond)
383{
384 /* should check that no threads are waiting on this CV */
385 kludged("pthread_cond_destroy");
386 return 0;
387}
sewardj6072c362002-04-19 14:40:57 +0000388
389/* ---------------------------------------------------
390 SCHEDULING
391 ------------------------------------------------ */
392
393/* This is completely bogus. */
394int pthread_getschedparam(pthread_t target_thread,
395 int *policy,
396 struct sched_param *param)
397{
sewardj30671ff2002-04-21 00:13:57 +0000398 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000399 if (policy) *policy = SCHED_OTHER;
sewardj2a1dcce2002-04-22 12:45:25 +0000400# ifdef GLIBC_2_1
401 if (param) param->sched_priority = 0; /* who knows */
402# else
sewardj6072c362002-04-19 14:40:57 +0000403 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000404# endif
sewardj6072c362002-04-19 14:40:57 +0000405 return 0;
406}
407
408int pthread_setschedparam(pthread_t target_thread,
409 int policy,
410 const struct sched_param *param)
411{
412 ignored("pthread_setschedparam");
413 return 0;
414}
415
sewardj3b5d8862002-04-20 13:53:23 +0000416int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
417{
418 int res;
419 ensure_valgrind("pthread_cond_wait");
420 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
421 VG_USERREQ__PTHREAD_COND_WAIT,
422 cond, mutex, 0, 0);
423 return res;
424}
425
sewardj5f07b662002-04-23 16:52:51 +0000426int pthread_cond_timedwait ( pthread_cond_t *cond,
427 pthread_mutex_t *mutex,
428 const struct timespec *abstime )
429{
430 int res;
431 unsigned int ms_now, ms_end;
432 struct timeval timeval_now;
433 unsigned long long int ull_ms_now_after_1970;
434 unsigned long long int ull_ms_end_after_1970;
435
436 ensure_valgrind("pthread_cond_timedwait");
437 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
438 VG_USERREQ__READ_MILLISECOND_TIMER,
439 0, 0, 0, 0);
440 assert(ms_now != 0xFFFFFFFF);
441 res = gettimeofday(&timeval_now, NULL);
442 assert(res == 0);
443
444 ull_ms_now_after_1970
445 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
446 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
447 ull_ms_end_after_1970
448 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
449 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
450 assert(ull_ms_end_after_1970 >= ull_ms_now_after_1970);
451 ms_end
452 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
453 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
454 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
455 cond, mutex, ms_end, 0);
456 return res;
457}
458
459
sewardj3b5d8862002-04-20 13:53:23 +0000460int pthread_cond_signal(pthread_cond_t *cond)
461{
462 int res;
463 ensure_valgrind("pthread_cond_signal");
464 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
465 VG_USERREQ__PTHREAD_COND_SIGNAL,
466 cond, 0, 0, 0);
467 return res;
468}
469
470int pthread_cond_broadcast(pthread_cond_t *cond)
471{
472 int res;
473 ensure_valgrind("pthread_cond_broadcast");
474 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
475 VG_USERREQ__PTHREAD_COND_BROADCAST,
476 cond, 0, 0, 0);
477 return res;
478}
479
sewardj6072c362002-04-19 14:40:57 +0000480
481/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000482 CANCELLATION
483 ------------------------------------------------ */
484
sewardje663cb92002-04-12 10:26:32 +0000485int pthread_setcanceltype(int type, int *oldtype)
486{
sewardj2a3d28c2002-04-14 13:27:00 +0000487 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000488 return 0;
489}
490
491
492int pthread_cancel(pthread_t thread)
493{
494 int res;
495 ensure_valgrind("pthread_cancel");
496 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
497 VG_USERREQ__PTHREAD_CANCEL,
498 thread, 0, 0, 0);
499 return res;
500}
501
502
sewardjf8f819e2002-04-17 23:21:37 +0000503/* ---------------------------------------------------
504 THREAD-SPECIFICs
505 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000506
507int pthread_key_create(pthread_key_t *key,
508 void (*destr_function) (void *))
509{
sewardj5f07b662002-04-23 16:52:51 +0000510 int res;
511 ensure_valgrind("pthread_key_create");
512 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
513 VG_USERREQ__PTHREAD_KEY_CREATE,
514 key, destr_function, 0, 0);
515 return res;
sewardj5e5fa512002-04-14 13:13:05 +0000516}
517
518int pthread_key_delete(pthread_key_t key)
519{
sewardj2a3d28c2002-04-14 13:27:00 +0000520 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000521 return 0;
522}
523
524int pthread_setspecific(pthread_key_t key, const void *pointer)
525{
sewardj5f07b662002-04-23 16:52:51 +0000526 int res;
527 ensure_valgrind("pthread_setspecific");
528 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
529 VG_USERREQ__PTHREAD_SETSPECIFIC,
530 key, pointer, 0, 0);
531 return res;
sewardj5e5fa512002-04-14 13:13:05 +0000532}
533
534void * pthread_getspecific(pthread_key_t key)
535{
sewardj5f07b662002-04-23 16:52:51 +0000536 int res;
537 ensure_valgrind("pthread_getspecific");
538 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
539 VG_USERREQ__PTHREAD_GETSPECIFIC,
540 key, 0 , 0, 0);
541 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +0000542}
543
sewardjf8f819e2002-04-17 23:21:37 +0000544
545/* ---------------------------------------------------
546 MISC
547 ------------------------------------------------ */
548
549/* What are these? Anybody know? I don't. */
550
551void _pthread_cleanup_push_defer ( void )
552{
553 // char* str = "_pthread_cleanup_push_defer\n";
554 // write(2, str, strlen(str));
555}
556
557void _pthread_cleanup_pop_restore ( void )
558{
559 // char* str = "_pthread_cleanup_pop_restore\n";
560 // write(2, str, strlen(str));
561}
562
563
564pthread_t pthread_self(void)
565{
566 int tid;
567 ensure_valgrind("pthread_self");
568 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
569 VG_USERREQ__PTHREAD_GET_THREADID,
570 0, 0, 0, 0);
571 if (tid < 0 || tid >= VG_N_THREADS)
572 barf("pthread_self: invalid ThreadId");
573 return tid;
574}
575
576
sewardje663cb92002-04-12 10:26:32 +0000577/* ---------------------------------------------------------------------
578 These are here (I think) because they are deemed cancellation
579 points by POSIX. For the moment we'll simply pass the call along
580 to the corresponding thread-unaware (?) libc routine.
581 ------------------------------------------------------------------ */
582
sewardje663cb92002-04-12 10:26:32 +0000583#include <stdlib.h>
584#include <signal.h>
sewardje663cb92002-04-12 10:26:32 +0000585#include <sys/types.h>
586#include <sys/socket.h>
587
588extern
589int __libc_sigaction
590 (int signum,
591 const struct sigaction *act,
592 struct sigaction *oldact);
593int sigaction(int signum,
594 const struct sigaction *act,
595 struct sigaction *oldact)
596{
sewardj2a1dcce2002-04-22 12:45:25 +0000597# ifdef GLIBC_2_1
598 return __sigaction(signum, act, oldact);
599# else
sewardj45b4b372002-04-16 22:50:32 +0000600 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +0000601# endif
sewardje663cb92002-04-12 10:26:32 +0000602}
603
604
605extern
606int __libc_connect(int sockfd,
607 const struct sockaddr *serv_addr,
608 socklen_t addrlen);
609int connect(int sockfd,
610 const struct sockaddr *serv_addr,
611 socklen_t addrlen)
612{
sewardj45b4b372002-04-16 22:50:32 +0000613 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000614}
615
616
617extern
618int __libc_fcntl(int fd, int cmd, long arg);
619int fcntl(int fd, int cmd, long arg)
620{
sewardj45b4b372002-04-16 22:50:32 +0000621 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000622}
623
624
625extern
626ssize_t __libc_write(int fd, const void *buf, size_t count);
627ssize_t write(int fd, const void *buf, size_t count)
628{
sewardj45b4b372002-04-16 22:50:32 +0000629 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000630}
631
632
633extern
634ssize_t __libc_read(int fd, void *buf, size_t count);
635ssize_t read(int fd, void *buf, size_t count)
636{
sewardj45b4b372002-04-16 22:50:32 +0000637 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000638}
639
640
641extern
642int __libc_open(const char *pathname, int flags);
643int open(const char *pathname, int flags)
644{
sewardj45b4b372002-04-16 22:50:32 +0000645 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000646}
647
648
649extern
650int __libc_close(int fd);
651int close(int fd)
652{
sewardj45b4b372002-04-16 22:50:32 +0000653 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000654}
655
656
657extern
658int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
659int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
660{
sewardj45b4b372002-04-16 22:50:32 +0000661 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000662}
663
664
665extern
666pid_t __libc_fork(void);
667pid_t fork(void)
668{
sewardj45b4b372002-04-16 22:50:32 +0000669 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000670}
671
672
673extern
674pid_t __libc_waitpid(pid_t pid, int *status, int options);
675pid_t waitpid(pid_t pid, int *status, int options)
676{
sewardj45b4b372002-04-16 22:50:32 +0000677 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000678}
679
680
681extern
682int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
683int nanosleep(const struct timespec *req, struct timespec *rem)
684{
685 return __libc_nanosleep(req, rem);
686}
687
688extern
689int __libc_fsync(int fd);
690int fsync(int fd)
691{
sewardj45b4b372002-04-16 22:50:32 +0000692 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000693}
694
sewardj70c75362002-04-13 04:18:32 +0000695extern
696off_t __libc_lseek(int fildes, off_t offset, int whence);
697off_t lseek(int fildes, off_t offset, int whence)
698{
sewardj45b4b372002-04-16 22:50:32 +0000699 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000700}
701
sewardj6af4b5d2002-04-16 04:40:49 +0000702extern
703void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
704void longjmp(jmp_buf env, int val)
705{
706 __libc_longjmp(env, val);
707}
708
709extern
710int __libc_send(int s, const void *msg, size_t len, int flags);
711int send(int s, const void *msg, size_t len, int flags)
712{
713 return __libc_send(s, msg, len, flags);
714}
715
sewardj1e8cdc92002-04-18 11:37:52 +0000716extern
717int __libc_recv(int s, void *buf, size_t len, int flags);
718int recv(int s, void *buf, size_t len, int flags)
719{
720 return __libc_recv(s, buf, len, flags);
721}
722
sewardj45b4b372002-04-16 22:50:32 +0000723
sewardj70c75362002-04-13 04:18:32 +0000724/*--------------------------------------------------*/
725
sewardje663cb92002-04-12 10:26:32 +0000726/* I've no idea what these are, but they get called quite a lot.
727 Anybody know? */
728
729#undef _IO_flockfile
730void _IO_flockfile ( _IO_FILE * file )
731{
732 // char* str = "_IO_flockfile\n";
733 // write(2, str, strlen(str));
734 // barf("_IO_flockfile");
735}
736
737#undef _IO_funlockfile
738void _IO_funlockfile ( _IO_FILE * file )
739{
740 // char* str = "_IO_funlockfile\n";
741 // write(2, str, strlen(str));
742 //barf("_IO_funlockfile");
743}
744
sewardj08a4c3f2002-04-13 03:45:44 +0000745/*--------------------------------------------------*/
746
747#include "vg_kerneliface.h"
748
749static
750__inline__
751int is_kerror ( int res )
752{
753 if (res >= -4095 && res <= -1)
754 return 1;
755 else
756 return 0;
757}
758
759
760static
761int my_do_syscall1 ( int syscallno, int arg1 )
762{
763 int __res;
764 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
765 : "=a" (__res)
766 : "0" (syscallno),
767 "d" (arg1) );
768 return __res;
769}
770
771static
772int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +0000773 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +0000774{
775 int __res;
776 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
777 : "=a" (__res)
778 : "0" (syscallno),
779 "d" (arg1),
780 "c" (arg2) );
781 return __res;
782}
783
784static
sewardjf854f472002-04-21 12:19:41 +0000785int my_do_syscall3 ( int syscallno,
786 int arg1, int arg2, int arg3 )
787{
788 int __res;
789 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
790 : "=a" (__res)
791 : "0" (syscallno),
792 "S" (arg1),
793 "c" (arg2),
794 "d" (arg3) );
795 return __res;
796}
797
798static
sewardj08a4c3f2002-04-13 03:45:44 +0000799int do_syscall_select( int n,
800 vki_fd_set* readfds,
801 vki_fd_set* writefds,
802 vki_fd_set* exceptfds,
803 struct vki_timeval * timeout )
804{
805 int res;
806 int args[5];
807 args[0] = n;
808 args[1] = (int)readfds;
809 args[2] = (int)writefds;
810 args[3] = (int)exceptfds;
811 args[4] = (int)timeout;
812 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +0000813 return res;
sewardj08a4c3f2002-04-13 03:45:44 +0000814}
815
816
817/* This is a wrapper round select(), which makes it thread-safe,
818 meaning that only this thread will block, rather than the entire
819 process. This wrapper in turn depends on nanosleep() not to block
820 the entire process, but I think (hope? suspect?) that POSIX
821 pthreads guarantees that to be the case.
822
823 Basic idea is: modify the timeout parameter to select so that it
824 returns immediately. Poll like this until select returns non-zero,
825 indicating something interesting happened, or until our time is up.
826 Space out the polls with nanosleeps of say 20 milliseconds, which
827 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +0000828
829 Assumes:
830 * (checked via assert) types fd_set and vki_fd_set are identical.
831 * (checked via assert) types timeval and vki_timeval are identical.
832 * (unchecked) libc error numbers (EINTR etc) are the negation of the
833 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +0000834*/
sewardj08a4c3f2002-04-13 03:45:44 +0000835
836
837int select ( int n,
838 fd_set *rfds,
839 fd_set *wfds,
840 fd_set *xfds,
841 struct timeval *timeout )
842{
sewardj5f07b662002-04-23 16:52:51 +0000843 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +0000844 int res;
845 fd_set rfds_copy;
846 fd_set wfds_copy;
847 fd_set xfds_copy;
848 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +0000849 struct vki_timeval zero_timeout;
850 struct vki_timespec nanosleep_interval;
851
sewardj5f07b662002-04-23 16:52:51 +0000852 /* gcc's complains about ms_end being used uninitialised -- classic
853 case it can't understand, where ms_end is both defined and used
854 only if timeout != NULL. Hence ... */
855 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +0000856
857 /* We assume that the kernel and libc data layouts are identical
858 for the following types. These asserts provide a crude
859 check. */
860 if (sizeof(fd_set) != sizeof(vki_fd_set)
861 || sizeof(struct timeval) != sizeof(struct vki_timeval))
862 barf("valgrind's hacky non-blocking select(): data sizes error");
863
sewardj5f07b662002-04-23 16:52:51 +0000864 /* Detect the current time and simultaneously find out if we are
865 running on Valgrind. */
866 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
867 VG_USERREQ__READ_MILLISECOND_TIMER,
868 0, 0, 0, 0);
869
870 /* If a zero timeout specified, this call is harmless. Also go
871 this route if we're not running on Valgrind, for whatever
872 reason. */
873 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
874 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +0000875 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +0000876 (vki_fd_set*)wfds,
877 (vki_fd_set*)xfds,
878 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +0000879 if (is_kerror(res)) {
880 * (__errno_location()) = -res;
881 return -1;
882 } else {
883 return res;
884 }
885 }
sewardj08a4c3f2002-04-13 03:45:44 +0000886
sewardj5f07b662002-04-23 16:52:51 +0000887 /* If a timeout was specified, set ms_end to be the end millisecond
888 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000889 if (timeout) {
890 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
891 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +0000892 ms_end = ms_now;
893 ms_end += (timeout->tv_usec / 1000);
894 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +0000895 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +0000896 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +0000897 }
898
899 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
900
901 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +0000902 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000903 while (1) {
904 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +0000905 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
906 VG_USERREQ__READ_MILLISECOND_TIMER,
907 0, 0, 0, 0);
908 assert(ms_now != 0xFFFFFFFF);
909 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +0000910 /* timeout; nothing interesting happened. */
911 if (rfds) FD_ZERO(rfds);
912 if (wfds) FD_ZERO(wfds);
913 if (xfds) FD_ZERO(xfds);
914 return 0;
915 }
916 }
917
918 /* These could be trashed each time round the loop, so restore
919 them each time. */
920 if (rfds) rfds_copy = *rfds;
921 if (wfds) wfds_copy = *wfds;
922 if (xfds) xfds_copy = *xfds;
923
924 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
925
926 res = do_syscall_select( n,
927 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
928 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
929 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
930 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +0000931 if (is_kerror(res)) {
932 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +0000933 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +0000934 * (__errno_location()) = -res;
935 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +0000936 }
937 if (res > 0) {
938 /* one or more fds is ready. Copy out resulting sets and
939 return. */
940 if (rfds) *rfds = rfds_copy;
941 if (wfds) *wfds = wfds_copy;
942 if (xfds) *xfds = xfds_copy;
943 return res;
944 }
945 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
946 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +0000947 nanosleep_interval.tv_sec = 0;
sewardj5f07b662002-04-23 16:52:51 +0000948 nanosleep_interval.tv_nsec = 100 * 1000 * 1000; /* 100 milliseconds */
sewardjf854f472002-04-21 12:19:41 +0000949 /* It's critical here that valgrind's nanosleep implementation
950 is nonblocking. */
951 (void)my_do_syscall2(__NR_nanosleep,
952 (int)(&nanosleep_interval), (int)NULL);
953 }
954}
955
956
957
958
959#include <sys/poll.h>
960
961int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
962{
sewardj5f07b662002-04-23 16:52:51 +0000963 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +0000964 int res, i;
sewardjf854f472002-04-21 12:19:41 +0000965 struct vki_timespec nanosleep_interval;
966
967 ensure_valgrind("poll");
968
sewardj5f07b662002-04-23 16:52:51 +0000969 /* Detect the current time and simultaneously find out if we are
970 running on Valgrind. */
971 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
972 VG_USERREQ__READ_MILLISECOND_TIMER,
973 0, 0, 0, 0);
974
sewardjf854f472002-04-21 12:19:41 +0000975 if (/* CHECK SIZES FOR struct pollfd */
976 sizeof(struct timeval) != sizeof(struct vki_timeval))
977 barf("valgrind's hacky non-blocking poll(): data sizes error");
978
sewardj5f07b662002-04-23 16:52:51 +0000979 /* dummy initialisation to keep gcc -Wall happy */
980 ms_end = 0;
981
982 /* If a zero timeout specified, this call is harmless. Also do
983 this if not running on Valgrind. */
984 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +0000985 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
986 if (is_kerror(res)) {
987 * (__errno_location()) = -res;
988 return -1;
989 } else {
990 return res;
991 }
992 }
993
sewardj5f07b662002-04-23 16:52:51 +0000994 /* If a timeout was specified, set ms_end to be the end wallclock
995 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +0000996 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +0000997 ms_end += (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +0000998 }
999
1000 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1001
1002 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1003 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001004 assert(__timeout != 0);
1005
sewardjf854f472002-04-21 12:19:41 +00001006 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001007 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001008 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1009 VG_USERREQ__READ_MILLISECOND_TIMER,
1010 0, 0, 0, 0);
1011 assert(ms_now != 0xFFFFFFFF);
1012 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001013 /* timeout; nothing interesting happened. */
1014 for (i = 0; i < __nfds; i++)
1015 __fds[i].revents = 0;
1016 return 0;
1017 }
1018 }
1019
sewardj5f07b662002-04-23 16:52:51 +00001020 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001021 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1022 if (is_kerror(res)) {
1023 /* Some kind of error. Set errno and return. */
1024 * (__errno_location()) = -res;
1025 return -1;
1026 }
1027 if (res > 0) {
1028 /* One or more fds is ready. Return now. */
1029 return res;
1030 }
1031 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1032 /* nanosleep and go round again */
1033 nanosleep_interval.tv_sec = 0;
sewardj5f07b662002-04-23 16:52:51 +00001034 nanosleep_interval.tv_nsec = 99 * 1000 * 1000; /* 99 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001035 /* It's critical here that valgrind's nanosleep implementation
1036 is nonblocking. */
1037 (void)my_do_syscall2(__NR_nanosleep,
1038 (int)(&nanosleep_interval), (int)NULL);
1039 }
1040}