blob: b230c7e5a310851e6b2ab1460e4348f2b5fd39a8 [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");
sewardj72d58482002-04-24 02:20:20 +0000167# ifdef GLIBC_2_1
168 if (param) param->sched_priority = 0; /* who knows */
169# else
sewardj30671ff2002-04-21 00:13:57 +0000170 if (param) param->__sched_priority = 0; /* who knows */
sewardj72d58482002-04-24 02:20:20 +0000171# endif
sewardj30671ff2002-04-21 00:13:57 +0000172 return 0;
173}
174
175int pthread_attr_setschedparam(pthread_attr_t *attr,
176 const struct sched_param *param)
177{
178 ignored("pthread_attr_setschedparam");
179 return 0;
180}
181
182int pthread_attr_destroy(pthread_attr_t *attr)
183{
184 ignored("pthread_attr_destroy");
185 return 0;
186}
sewardjf8f819e2002-04-17 23:21:37 +0000187
188/* ---------------------------------------------------
189 THREADs
190 ------------------------------------------------ */
191
sewardj6072c362002-04-19 14:40:57 +0000192int pthread_equal(pthread_t thread1, pthread_t thread2)
193{
194 return thread1 == thread2 ? 1 : 0;
195}
196
197
sewardje663cb92002-04-12 10:26:32 +0000198int
199pthread_create (pthread_t *__restrict __thread,
200 __const pthread_attr_t *__restrict __attr,
201 void *(*__start_routine) (void *),
202 void *__restrict __arg)
203{
204 int res;
205 ensure_valgrind("pthread_create");
206 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
207 VG_USERREQ__PTHREAD_CREATE,
208 __thread, __attr, __start_routine, __arg);
209 return res;
210}
211
212
213
214int
215pthread_join (pthread_t __th, void **__thread_return)
216{
217 int res;
218 ensure_valgrind("pthread_join");
219 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
220 VG_USERREQ__PTHREAD_JOIN,
221 __th, __thread_return, 0, 0);
222 return res;
223}
224
225
sewardj3b5d8862002-04-20 13:53:23 +0000226void pthread_exit(void *retval)
227{
228 int res;
229 ensure_valgrind("pthread_exit");
230 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
231 VG_USERREQ__PTHREAD_EXIT,
232 retval, 0, 0, 0);
233 /* Doesn't return! */
234 /* However, we have to fool gcc into knowing that. */
235 barf("pthread_exit: still alive after request?!");
236}
237
sewardje663cb92002-04-12 10:26:32 +0000238
239static int thread_specific_errno[VG_N_THREADS];
240
241int* __errno_location ( void )
242{
243 int tid;
sewardj35805422002-04-21 13:05:34 +0000244 /* ensure_valgrind("__errno_location"); */
sewardje663cb92002-04-12 10:26:32 +0000245 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
246 VG_USERREQ__PTHREAD_GET_THREADID,
247 0, 0, 0, 0);
248 /* 'cos I'm paranoid ... */
249 if (tid < 0 || tid >= VG_N_THREADS)
250 barf("__errno_location: invalid ThreadId");
251 return & thread_specific_errno[tid];
252}
253
254
sewardjf8f819e2002-04-17 23:21:37 +0000255/* ---------------------------------------------------
256 MUTEX ATTRIBUTES
257 ------------------------------------------------ */
258
sewardje663cb92002-04-12 10:26:32 +0000259int pthread_mutexattr_init(pthread_mutexattr_t *attr)
260{
sewardjf8f819e2002-04-17 23:21:37 +0000261 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000262 return 0;
sewardje663cb92002-04-12 10:26:32 +0000263}
264
sewardjf8f819e2002-04-17 23:21:37 +0000265int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
266{
267 switch (type) {
sewardj2a1dcce2002-04-22 12:45:25 +0000268#ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000269 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000270 case PTHREAD_MUTEX_ADAPTIVE_NP:
271#endif
sewardjf8f819e2002-04-17 23:21:37 +0000272 case PTHREAD_MUTEX_RECURSIVE_NP:
273 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000274 attr->__mutexkind = type;
275 return 0;
276 default:
277 return EINVAL;
278 }
279}
280
281int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
282{
283 return 0;
284}
285
286
287/* ---------------------------------------------------
288 MUTEXes
289 ------------------------------------------------ */
290
sewardje663cb92002-04-12 10:26:32 +0000291int pthread_mutex_init(pthread_mutex_t *mutex,
292 const pthread_mutexattr_t *mutexattr)
293{
sewardj604ec3c2002-04-18 22:38:41 +0000294 mutex->__m_count = 0;
295 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
296 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
297 if (mutexattr)
298 mutex->__m_kind = mutexattr->__mutexkind;
299 return 0;
sewardje663cb92002-04-12 10:26:32 +0000300}
301
sewardje663cb92002-04-12 10:26:32 +0000302int pthread_mutex_lock(pthread_mutex_t *mutex)
303{
304 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000305 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000306 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000307 char* str = "pthread_mutex_lock-NOT-INSIDE-VALGRIND\n";
308 write(2, str, strlen(str));
309 return 0;
310 } else {
311 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
312 VG_USERREQ__PTHREAD_MUTEX_LOCK,
313 mutex, 0, 0, 0);
314 return res;
315 }
316}
317
sewardj30671ff2002-04-21 00:13:57 +0000318int pthread_mutex_trylock(pthread_mutex_t *mutex)
319{
320 int res;
321 static int moans = 3;
322 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
323 char* str = "pthread_mutex_trylock-NOT-INSIDE-VALGRIND\n";
324 write(2, str, strlen(str));
325 return 0;
326 } else {
327 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
328 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
329 mutex, 0, 0, 0);
330 return res;
331 }
332}
333
sewardje663cb92002-04-12 10:26:32 +0000334int pthread_mutex_unlock(pthread_mutex_t *mutex)
335{
336 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000337 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000338 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000339 char* str = "pthread_mutex_unlock-NOT-INSIDE-VALGRIND\n";
340 write(2, str, strlen(str));
341 return 0;
342 } else {
343 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
344 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
345 mutex, 0, 0, 0);
346 return res;
347 }
348}
349
sewardje663cb92002-04-12 10:26:32 +0000350int pthread_mutex_destroy(pthread_mutex_t *mutex)
351{
sewardj604ec3c2002-04-18 22:38:41 +0000352 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
353 need to involve it. */
354 if (mutex->__m_count > 0)
355 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000356 mutex->__m_count = 0;
357 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
358 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000359 return 0;
sewardje663cb92002-04-12 10:26:32 +0000360}
361
362
sewardjf8f819e2002-04-17 23:21:37 +0000363/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000364 CONDITION VARIABLES
365 ------------------------------------------------ */
366
367/* LinuxThreads supports no attributes for conditions. Hence ... */
368
369int pthread_condattr_init(pthread_condattr_t *attr)
370{
371 return 0;
372}
373
sewardj0738a592002-04-20 13:59:33 +0000374int pthread_condattr_destroy(pthread_condattr_t *attr)
375{
376 return 0;
377}
sewardj6072c362002-04-19 14:40:57 +0000378
379int pthread_cond_init( pthread_cond_t *cond,
380 const pthread_condattr_t *cond_attr)
381{
382 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
383 return 0;
384}
385
sewardjf854f472002-04-21 12:19:41 +0000386int pthread_cond_destroy(pthread_cond_t *cond)
387{
388 /* should check that no threads are waiting on this CV */
389 kludged("pthread_cond_destroy");
390 return 0;
391}
sewardj6072c362002-04-19 14:40:57 +0000392
393/* ---------------------------------------------------
394 SCHEDULING
395 ------------------------------------------------ */
396
397/* This is completely bogus. */
398int pthread_getschedparam(pthread_t target_thread,
399 int *policy,
400 struct sched_param *param)
401{
sewardj30671ff2002-04-21 00:13:57 +0000402 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000403 if (policy) *policy = SCHED_OTHER;
sewardj2a1dcce2002-04-22 12:45:25 +0000404# ifdef GLIBC_2_1
405 if (param) param->sched_priority = 0; /* who knows */
406# else
sewardj6072c362002-04-19 14:40:57 +0000407 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000408# endif
sewardj6072c362002-04-19 14:40:57 +0000409 return 0;
410}
411
412int pthread_setschedparam(pthread_t target_thread,
413 int policy,
414 const struct sched_param *param)
415{
416 ignored("pthread_setschedparam");
417 return 0;
418}
419
sewardj3b5d8862002-04-20 13:53:23 +0000420int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
421{
422 int res;
423 ensure_valgrind("pthread_cond_wait");
424 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
425 VG_USERREQ__PTHREAD_COND_WAIT,
426 cond, mutex, 0, 0);
427 return res;
428}
429
sewardj5f07b662002-04-23 16:52:51 +0000430int pthread_cond_timedwait ( pthread_cond_t *cond,
431 pthread_mutex_t *mutex,
432 const struct timespec *abstime )
433{
434 int res;
435 unsigned int ms_now, ms_end;
436 struct timeval timeval_now;
437 unsigned long long int ull_ms_now_after_1970;
438 unsigned long long int ull_ms_end_after_1970;
439
440 ensure_valgrind("pthread_cond_timedwait");
441 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
442 VG_USERREQ__READ_MILLISECOND_TIMER,
443 0, 0, 0, 0);
444 assert(ms_now != 0xFFFFFFFF);
445 res = gettimeofday(&timeval_now, NULL);
446 assert(res == 0);
447
448 ull_ms_now_after_1970
449 = 1000ULL * ((unsigned long long int)(timeval_now.tv_sec))
450 + ((unsigned long long int)(timeval_now.tv_usec / 1000000));
451 ull_ms_end_after_1970
452 = 1000ULL * ((unsigned long long int)(abstime->tv_sec))
453 + ((unsigned long long int)(abstime->tv_nsec / 1000000));
454 assert(ull_ms_end_after_1970 >= ull_ms_now_after_1970);
455 ms_end
456 = ms_now + (unsigned int)(ull_ms_end_after_1970 - ull_ms_now_after_1970);
457 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
458 VG_USERREQ__PTHREAD_COND_TIMEDWAIT,
459 cond, mutex, ms_end, 0);
460 return res;
461}
462
463
sewardj3b5d8862002-04-20 13:53:23 +0000464int pthread_cond_signal(pthread_cond_t *cond)
465{
466 int res;
467 ensure_valgrind("pthread_cond_signal");
468 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
469 VG_USERREQ__PTHREAD_COND_SIGNAL,
470 cond, 0, 0, 0);
471 return res;
472}
473
474int pthread_cond_broadcast(pthread_cond_t *cond)
475{
476 int res;
477 ensure_valgrind("pthread_cond_broadcast");
478 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
479 VG_USERREQ__PTHREAD_COND_BROADCAST,
480 cond, 0, 0, 0);
481 return res;
482}
483
sewardj6072c362002-04-19 14:40:57 +0000484
485/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000486 CANCELLATION
487 ------------------------------------------------ */
488
sewardje663cb92002-04-12 10:26:32 +0000489int pthread_setcanceltype(int type, int *oldtype)
490{
sewardj2a3d28c2002-04-14 13:27:00 +0000491 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000492 return 0;
493}
494
495
496int pthread_cancel(pthread_t thread)
497{
498 int res;
499 ensure_valgrind("pthread_cancel");
500 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
501 VG_USERREQ__PTHREAD_CANCEL,
502 thread, 0, 0, 0);
503 return res;
504}
505
506
sewardjf8f819e2002-04-17 23:21:37 +0000507/* ---------------------------------------------------
508 THREAD-SPECIFICs
509 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000510
511int pthread_key_create(pthread_key_t *key,
512 void (*destr_function) (void *))
513{
sewardj5f07b662002-04-23 16:52:51 +0000514 int res;
515 ensure_valgrind("pthread_key_create");
516 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
517 VG_USERREQ__PTHREAD_KEY_CREATE,
518 key, destr_function, 0, 0);
519 return res;
sewardj5e5fa512002-04-14 13:13:05 +0000520}
521
522int pthread_key_delete(pthread_key_t key)
523{
sewardj2a3d28c2002-04-14 13:27:00 +0000524 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000525 return 0;
526}
527
528int pthread_setspecific(pthread_key_t key, const void *pointer)
529{
sewardj5f07b662002-04-23 16:52:51 +0000530 int res;
531 ensure_valgrind("pthread_setspecific");
532 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
533 VG_USERREQ__PTHREAD_SETSPECIFIC,
534 key, pointer, 0, 0);
535 return res;
sewardj5e5fa512002-04-14 13:13:05 +0000536}
537
538void * pthread_getspecific(pthread_key_t key)
539{
sewardj5f07b662002-04-23 16:52:51 +0000540 int res;
541 ensure_valgrind("pthread_getspecific");
542 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
543 VG_USERREQ__PTHREAD_GETSPECIFIC,
544 key, 0 , 0, 0);
545 return (void*)res;
sewardj5e5fa512002-04-14 13:13:05 +0000546}
547
sewardjf8f819e2002-04-17 23:21:37 +0000548
549/* ---------------------------------------------------
550 MISC
551 ------------------------------------------------ */
552
553/* What are these? Anybody know? I don't. */
554
555void _pthread_cleanup_push_defer ( void )
556{
557 // char* str = "_pthread_cleanup_push_defer\n";
558 // write(2, str, strlen(str));
559}
560
561void _pthread_cleanup_pop_restore ( void )
562{
563 // char* str = "_pthread_cleanup_pop_restore\n";
564 // write(2, str, strlen(str));
565}
566
567
568pthread_t pthread_self(void)
569{
570 int tid;
571 ensure_valgrind("pthread_self");
572 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
573 VG_USERREQ__PTHREAD_GET_THREADID,
574 0, 0, 0, 0);
575 if (tid < 0 || tid >= VG_N_THREADS)
576 barf("pthread_self: invalid ThreadId");
577 return tid;
578}
579
580
sewardje663cb92002-04-12 10:26:32 +0000581/* ---------------------------------------------------------------------
582 These are here (I think) because they are deemed cancellation
583 points by POSIX. For the moment we'll simply pass the call along
584 to the corresponding thread-unaware (?) libc routine.
585 ------------------------------------------------------------------ */
586
sewardje663cb92002-04-12 10:26:32 +0000587#include <stdlib.h>
588#include <signal.h>
sewardje663cb92002-04-12 10:26:32 +0000589#include <sys/types.h>
590#include <sys/socket.h>
591
592extern
593int __libc_sigaction
594 (int signum,
595 const struct sigaction *act,
596 struct sigaction *oldact);
597int sigaction(int signum,
598 const struct sigaction *act,
599 struct sigaction *oldact)
600{
sewardj2a1dcce2002-04-22 12:45:25 +0000601# ifdef GLIBC_2_1
602 return __sigaction(signum, act, oldact);
603# else
sewardj45b4b372002-04-16 22:50:32 +0000604 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +0000605# endif
sewardje663cb92002-04-12 10:26:32 +0000606}
607
608
609extern
610int __libc_connect(int sockfd,
611 const struct sockaddr *serv_addr,
612 socklen_t addrlen);
613int connect(int sockfd,
614 const struct sockaddr *serv_addr,
615 socklen_t addrlen)
616{
sewardj45b4b372002-04-16 22:50:32 +0000617 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000618}
619
620
621extern
622int __libc_fcntl(int fd, int cmd, long arg);
623int fcntl(int fd, int cmd, long arg)
624{
sewardj45b4b372002-04-16 22:50:32 +0000625 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000626}
627
628
629extern
630ssize_t __libc_write(int fd, const void *buf, size_t count);
631ssize_t write(int fd, const void *buf, size_t count)
632{
sewardj45b4b372002-04-16 22:50:32 +0000633 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000634}
635
636
637extern
638ssize_t __libc_read(int fd, void *buf, size_t count);
639ssize_t read(int fd, void *buf, size_t count)
640{
sewardj45b4b372002-04-16 22:50:32 +0000641 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000642}
643
644
645extern
646int __libc_open(const char *pathname, int flags);
647int open(const char *pathname, int flags)
648{
sewardj45b4b372002-04-16 22:50:32 +0000649 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000650}
651
652
653extern
654int __libc_close(int fd);
655int close(int fd)
656{
sewardj45b4b372002-04-16 22:50:32 +0000657 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000658}
659
660
661extern
662int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
663int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
664{
sewardj45b4b372002-04-16 22:50:32 +0000665 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000666}
667
668
669extern
670pid_t __libc_fork(void);
671pid_t fork(void)
672{
sewardj45b4b372002-04-16 22:50:32 +0000673 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000674}
675
676
677extern
678pid_t __libc_waitpid(pid_t pid, int *status, int options);
679pid_t waitpid(pid_t pid, int *status, int options)
680{
sewardj45b4b372002-04-16 22:50:32 +0000681 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000682}
683
684
685extern
686int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
687int nanosleep(const struct timespec *req, struct timespec *rem)
688{
689 return __libc_nanosleep(req, rem);
690}
691
692extern
693int __libc_fsync(int fd);
694int fsync(int fd)
695{
sewardj45b4b372002-04-16 22:50:32 +0000696 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000697}
698
sewardj70c75362002-04-13 04:18:32 +0000699extern
700off_t __libc_lseek(int fildes, off_t offset, int whence);
701off_t lseek(int fildes, off_t offset, int whence)
702{
sewardj45b4b372002-04-16 22:50:32 +0000703 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000704}
705
sewardj6af4b5d2002-04-16 04:40:49 +0000706extern
707void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
708void longjmp(jmp_buf env, int val)
709{
710 __libc_longjmp(env, val);
711}
712
713extern
714int __libc_send(int s, const void *msg, size_t len, int flags);
715int send(int s, const void *msg, size_t len, int flags)
716{
717 return __libc_send(s, msg, len, flags);
718}
719
sewardj1e8cdc92002-04-18 11:37:52 +0000720extern
721int __libc_recv(int s, void *buf, size_t len, int flags);
722int recv(int s, void *buf, size_t len, int flags)
723{
724 return __libc_recv(s, buf, len, flags);
725}
726
sewardj45b4b372002-04-16 22:50:32 +0000727
sewardj70c75362002-04-13 04:18:32 +0000728/*--------------------------------------------------*/
729
sewardje663cb92002-04-12 10:26:32 +0000730/* I've no idea what these are, but they get called quite a lot.
731 Anybody know? */
732
733#undef _IO_flockfile
734void _IO_flockfile ( _IO_FILE * file )
735{
736 // char* str = "_IO_flockfile\n";
737 // write(2, str, strlen(str));
738 // barf("_IO_flockfile");
739}
740
741#undef _IO_funlockfile
742void _IO_funlockfile ( _IO_FILE * file )
743{
744 // char* str = "_IO_funlockfile\n";
745 // write(2, str, strlen(str));
746 //barf("_IO_funlockfile");
747}
748
sewardj08a4c3f2002-04-13 03:45:44 +0000749/*--------------------------------------------------*/
750
751#include "vg_kerneliface.h"
752
753static
754__inline__
755int is_kerror ( int res )
756{
757 if (res >= -4095 && res <= -1)
758 return 1;
759 else
760 return 0;
761}
762
763
764static
765int my_do_syscall1 ( int syscallno, int arg1 )
766{
767 int __res;
768 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
769 : "=a" (__res)
770 : "0" (syscallno),
771 "d" (arg1) );
772 return __res;
773}
774
775static
776int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +0000777 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +0000778{
779 int __res;
780 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
781 : "=a" (__res)
782 : "0" (syscallno),
783 "d" (arg1),
784 "c" (arg2) );
785 return __res;
786}
787
788static
sewardjf854f472002-04-21 12:19:41 +0000789int my_do_syscall3 ( int syscallno,
790 int arg1, int arg2, int arg3 )
791{
792 int __res;
793 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
794 : "=a" (__res)
795 : "0" (syscallno),
796 "S" (arg1),
797 "c" (arg2),
798 "d" (arg3) );
799 return __res;
800}
801
802static
sewardj08a4c3f2002-04-13 03:45:44 +0000803int do_syscall_select( int n,
804 vki_fd_set* readfds,
805 vki_fd_set* writefds,
806 vki_fd_set* exceptfds,
807 struct vki_timeval * timeout )
808{
809 int res;
810 int args[5];
811 args[0] = n;
812 args[1] = (int)readfds;
813 args[2] = (int)writefds;
814 args[3] = (int)exceptfds;
815 args[4] = (int)timeout;
816 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +0000817 return res;
sewardj08a4c3f2002-04-13 03:45:44 +0000818}
819
820
821/* This is a wrapper round select(), which makes it thread-safe,
822 meaning that only this thread will block, rather than the entire
823 process. This wrapper in turn depends on nanosleep() not to block
824 the entire process, but I think (hope? suspect?) that POSIX
825 pthreads guarantees that to be the case.
826
827 Basic idea is: modify the timeout parameter to select so that it
828 returns immediately. Poll like this until select returns non-zero,
829 indicating something interesting happened, or until our time is up.
830 Space out the polls with nanosleeps of say 20 milliseconds, which
831 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +0000832
833 Assumes:
834 * (checked via assert) types fd_set and vki_fd_set are identical.
835 * (checked via assert) types timeval and vki_timeval are identical.
836 * (unchecked) libc error numbers (EINTR etc) are the negation of the
837 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +0000838*/
sewardj08a4c3f2002-04-13 03:45:44 +0000839
840
841int select ( int n,
842 fd_set *rfds,
843 fd_set *wfds,
844 fd_set *xfds,
845 struct timeval *timeout )
846{
sewardj5f07b662002-04-23 16:52:51 +0000847 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +0000848 int res;
849 fd_set rfds_copy;
850 fd_set wfds_copy;
851 fd_set xfds_copy;
852 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +0000853 struct vki_timeval zero_timeout;
854 struct vki_timespec nanosleep_interval;
855
sewardj5f07b662002-04-23 16:52:51 +0000856 /* gcc's complains about ms_end being used uninitialised -- classic
857 case it can't understand, where ms_end is both defined and used
858 only if timeout != NULL. Hence ... */
859 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +0000860
861 /* We assume that the kernel and libc data layouts are identical
862 for the following types. These asserts provide a crude
863 check. */
864 if (sizeof(fd_set) != sizeof(vki_fd_set)
865 || sizeof(struct timeval) != sizeof(struct vki_timeval))
866 barf("valgrind's hacky non-blocking select(): data sizes error");
867
sewardj5f07b662002-04-23 16:52:51 +0000868 /* Detect the current time and simultaneously find out if we are
869 running on Valgrind. */
870 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
871 VG_USERREQ__READ_MILLISECOND_TIMER,
872 0, 0, 0, 0);
873
874 /* If a zero timeout specified, this call is harmless. Also go
875 this route if we're not running on Valgrind, for whatever
876 reason. */
877 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
878 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +0000879 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +0000880 (vki_fd_set*)wfds,
881 (vki_fd_set*)xfds,
882 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +0000883 if (is_kerror(res)) {
884 * (__errno_location()) = -res;
885 return -1;
886 } else {
887 return res;
888 }
889 }
sewardj08a4c3f2002-04-13 03:45:44 +0000890
sewardj5f07b662002-04-23 16:52:51 +0000891 /* If a timeout was specified, set ms_end to be the end millisecond
892 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000893 if (timeout) {
894 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
895 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +0000896 ms_end = ms_now;
897 ms_end += (timeout->tv_usec / 1000);
898 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +0000899 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +0000900 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +0000901 }
902
903 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
904
905 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +0000906 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000907 while (1) {
908 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +0000909 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
910 VG_USERREQ__READ_MILLISECOND_TIMER,
911 0, 0, 0, 0);
912 assert(ms_now != 0xFFFFFFFF);
913 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +0000914 /* timeout; nothing interesting happened. */
915 if (rfds) FD_ZERO(rfds);
916 if (wfds) FD_ZERO(wfds);
917 if (xfds) FD_ZERO(xfds);
918 return 0;
919 }
920 }
921
922 /* These could be trashed each time round the loop, so restore
923 them each time. */
924 if (rfds) rfds_copy = *rfds;
925 if (wfds) wfds_copy = *wfds;
926 if (xfds) xfds_copy = *xfds;
927
928 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
929
930 res = do_syscall_select( n,
931 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
932 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
933 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
934 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +0000935 if (is_kerror(res)) {
936 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +0000937 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +0000938 * (__errno_location()) = -res;
939 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +0000940 }
941 if (res > 0) {
942 /* one or more fds is ready. Copy out resulting sets and
943 return. */
944 if (rfds) *rfds = rfds_copy;
945 if (wfds) *wfds = wfds_copy;
946 if (xfds) *xfds = xfds_copy;
947 return res;
948 }
949 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
950 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +0000951 nanosleep_interval.tv_sec = 0;
sewardj5f07b662002-04-23 16:52:51 +0000952 nanosleep_interval.tv_nsec = 100 * 1000 * 1000; /* 100 milliseconds */
sewardjf854f472002-04-21 12:19:41 +0000953 /* It's critical here that valgrind's nanosleep implementation
954 is nonblocking. */
955 (void)my_do_syscall2(__NR_nanosleep,
956 (int)(&nanosleep_interval), (int)NULL);
957 }
958}
959
960
961
962
963#include <sys/poll.h>
964
sewardj72d58482002-04-24 02:20:20 +0000965#ifdef GLIBC_2_1
966typedef unsigned long int nfds_t;
967#endif
968
sewardjf854f472002-04-21 12:19:41 +0000969int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
970{
sewardj5f07b662002-04-23 16:52:51 +0000971 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +0000972 int res, i;
sewardjf854f472002-04-21 12:19:41 +0000973 struct vki_timespec nanosleep_interval;
974
975 ensure_valgrind("poll");
976
sewardj5f07b662002-04-23 16:52:51 +0000977 /* Detect the current time and simultaneously find out if we are
978 running on Valgrind. */
979 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
980 VG_USERREQ__READ_MILLISECOND_TIMER,
981 0, 0, 0, 0);
982
sewardjf854f472002-04-21 12:19:41 +0000983 if (/* CHECK SIZES FOR struct pollfd */
984 sizeof(struct timeval) != sizeof(struct vki_timeval))
985 barf("valgrind's hacky non-blocking poll(): data sizes error");
986
sewardj5f07b662002-04-23 16:52:51 +0000987 /* dummy initialisation to keep gcc -Wall happy */
988 ms_end = 0;
989
990 /* If a zero timeout specified, this call is harmless. Also do
991 this if not running on Valgrind. */
992 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +0000993 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
994 if (is_kerror(res)) {
995 * (__errno_location()) = -res;
996 return -1;
997 } else {
998 return res;
999 }
1000 }
1001
sewardj5f07b662002-04-23 16:52:51 +00001002 /* If a timeout was specified, set ms_end to be the end wallclock
1003 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001004 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001005 ms_end += (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001006 }
1007
1008 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1009
1010 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1011 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001012 assert(__timeout != 0);
1013
sewardjf854f472002-04-21 12:19:41 +00001014 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001015 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001016 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1017 VG_USERREQ__READ_MILLISECOND_TIMER,
1018 0, 0, 0, 0);
1019 assert(ms_now != 0xFFFFFFFF);
1020 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001021 /* timeout; nothing interesting happened. */
1022 for (i = 0; i < __nfds; i++)
1023 __fds[i].revents = 0;
1024 return 0;
1025 }
1026 }
1027
sewardj5f07b662002-04-23 16:52:51 +00001028 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001029 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1030 if (is_kerror(res)) {
1031 /* Some kind of error. Set errno and return. */
1032 * (__errno_location()) = -res;
1033 return -1;
1034 }
1035 if (res > 0) {
1036 /* One or more fds is ready. Return now. */
1037 return res;
1038 }
1039 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1040 /* nanosleep and go round again */
1041 nanosleep_interval.tv_sec = 0;
sewardj5f07b662002-04-23 16:52:51 +00001042 nanosleep_interval.tv_nsec = 99 * 1000 * 1000; /* 99 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001043 /* It's critical here that valgrind's nanosleep implementation
1044 is nonblocking. */
1045 (void)my_do_syscall2(__NR_nanosleep,
1046 (int)(&nanosleep_interval), (int)NULL);
1047 }
1048}