blob: 8d88efc6054da74f9323ce3bbcf528e1f9b4dd7d [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
sewardj796d6a22002-04-24 02:28:34 +0000727extern
728int __libc_sendto(int s, const void *msg, size_t len, int flags,
729 const struct sockaddr *to, socklen_t tolen);
730int sendto(int s, const void *msg, size_t len, int flags,
731 const struct sockaddr *to, socklen_t tolen)
732{
733 return __libc_sendto(s, msg, len, flags, to, tolen);
734}
735
sewardj45b4b372002-04-16 22:50:32 +0000736
sewardj70c75362002-04-13 04:18:32 +0000737/*--------------------------------------------------*/
738
sewardje663cb92002-04-12 10:26:32 +0000739/* I've no idea what these are, but they get called quite a lot.
740 Anybody know? */
741
742#undef _IO_flockfile
743void _IO_flockfile ( _IO_FILE * file )
744{
745 // char* str = "_IO_flockfile\n";
746 // write(2, str, strlen(str));
747 // barf("_IO_flockfile");
748}
749
750#undef _IO_funlockfile
751void _IO_funlockfile ( _IO_FILE * file )
752{
753 // char* str = "_IO_funlockfile\n";
754 // write(2, str, strlen(str));
755 //barf("_IO_funlockfile");
756}
757
sewardj08a4c3f2002-04-13 03:45:44 +0000758/*--------------------------------------------------*/
759
760#include "vg_kerneliface.h"
761
762static
763__inline__
764int is_kerror ( int res )
765{
766 if (res >= -4095 && res <= -1)
767 return 1;
768 else
769 return 0;
770}
771
772
773static
774int my_do_syscall1 ( int syscallno, int arg1 )
775{
776 int __res;
777 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
778 : "=a" (__res)
779 : "0" (syscallno),
780 "d" (arg1) );
781 return __res;
782}
783
784static
785int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +0000786 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +0000787{
788 int __res;
789 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
790 : "=a" (__res)
791 : "0" (syscallno),
792 "d" (arg1),
793 "c" (arg2) );
794 return __res;
795}
796
797static
sewardjf854f472002-04-21 12:19:41 +0000798int my_do_syscall3 ( int syscallno,
799 int arg1, int arg2, int arg3 )
800{
801 int __res;
802 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
803 : "=a" (__res)
804 : "0" (syscallno),
805 "S" (arg1),
806 "c" (arg2),
807 "d" (arg3) );
808 return __res;
809}
810
811static
sewardj08a4c3f2002-04-13 03:45:44 +0000812int do_syscall_select( int n,
813 vki_fd_set* readfds,
814 vki_fd_set* writefds,
815 vki_fd_set* exceptfds,
816 struct vki_timeval * timeout )
817{
818 int res;
819 int args[5];
820 args[0] = n;
821 args[1] = (int)readfds;
822 args[2] = (int)writefds;
823 args[3] = (int)exceptfds;
824 args[4] = (int)timeout;
825 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +0000826 return res;
sewardj08a4c3f2002-04-13 03:45:44 +0000827}
828
829
830/* This is a wrapper round select(), which makes it thread-safe,
831 meaning that only this thread will block, rather than the entire
832 process. This wrapper in turn depends on nanosleep() not to block
833 the entire process, but I think (hope? suspect?) that POSIX
834 pthreads guarantees that to be the case.
835
836 Basic idea is: modify the timeout parameter to select so that it
837 returns immediately. Poll like this until select returns non-zero,
838 indicating something interesting happened, or until our time is up.
839 Space out the polls with nanosleeps of say 20 milliseconds, which
840 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +0000841
842 Assumes:
843 * (checked via assert) types fd_set and vki_fd_set are identical.
844 * (checked via assert) types timeval and vki_timeval are identical.
845 * (unchecked) libc error numbers (EINTR etc) are the negation of the
846 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +0000847*/
sewardj08a4c3f2002-04-13 03:45:44 +0000848
849
850int select ( int n,
851 fd_set *rfds,
852 fd_set *wfds,
853 fd_set *xfds,
854 struct timeval *timeout )
855{
sewardj5f07b662002-04-23 16:52:51 +0000856 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +0000857 int res;
858 fd_set rfds_copy;
859 fd_set wfds_copy;
860 fd_set xfds_copy;
861 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +0000862 struct vki_timeval zero_timeout;
863 struct vki_timespec nanosleep_interval;
864
sewardj5f07b662002-04-23 16:52:51 +0000865 /* gcc's complains about ms_end being used uninitialised -- classic
866 case it can't understand, where ms_end is both defined and used
867 only if timeout != NULL. Hence ... */
868 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +0000869
870 /* We assume that the kernel and libc data layouts are identical
871 for the following types. These asserts provide a crude
872 check. */
873 if (sizeof(fd_set) != sizeof(vki_fd_set)
874 || sizeof(struct timeval) != sizeof(struct vki_timeval))
875 barf("valgrind's hacky non-blocking select(): data sizes error");
876
sewardj5f07b662002-04-23 16:52:51 +0000877 /* Detect the current time and simultaneously find out if we are
878 running on Valgrind. */
879 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
880 VG_USERREQ__READ_MILLISECOND_TIMER,
881 0, 0, 0, 0);
882
883 /* If a zero timeout specified, this call is harmless. Also go
884 this route if we're not running on Valgrind, for whatever
885 reason. */
886 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
887 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +0000888 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +0000889 (vki_fd_set*)wfds,
890 (vki_fd_set*)xfds,
891 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +0000892 if (is_kerror(res)) {
893 * (__errno_location()) = -res;
894 return -1;
895 } else {
896 return res;
897 }
898 }
sewardj08a4c3f2002-04-13 03:45:44 +0000899
sewardj5f07b662002-04-23 16:52:51 +0000900 /* If a timeout was specified, set ms_end to be the end millisecond
901 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000902 if (timeout) {
903 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
904 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +0000905 ms_end = ms_now;
906 ms_end += (timeout->tv_usec / 1000);
907 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +0000908 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +0000909 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +0000910 }
911
912 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
913
914 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +0000915 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000916 while (1) {
917 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +0000918 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
919 VG_USERREQ__READ_MILLISECOND_TIMER,
920 0, 0, 0, 0);
921 assert(ms_now != 0xFFFFFFFF);
922 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +0000923 /* timeout; nothing interesting happened. */
924 if (rfds) FD_ZERO(rfds);
925 if (wfds) FD_ZERO(wfds);
926 if (xfds) FD_ZERO(xfds);
927 return 0;
928 }
929 }
930
931 /* These could be trashed each time round the loop, so restore
932 them each time. */
933 if (rfds) rfds_copy = *rfds;
934 if (wfds) wfds_copy = *wfds;
935 if (xfds) xfds_copy = *xfds;
936
937 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
938
939 res = do_syscall_select( n,
940 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
941 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
942 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
943 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +0000944 if (is_kerror(res)) {
945 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +0000946 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +0000947 * (__errno_location()) = -res;
948 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +0000949 }
950 if (res > 0) {
951 /* one or more fds is ready. Copy out resulting sets and
952 return. */
953 if (rfds) *rfds = rfds_copy;
954 if (wfds) *wfds = wfds_copy;
955 if (xfds) *xfds = xfds_copy;
956 return res;
957 }
958 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
959 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +0000960 nanosleep_interval.tv_sec = 0;
sewardj5f07b662002-04-23 16:52:51 +0000961 nanosleep_interval.tv_nsec = 100 * 1000 * 1000; /* 100 milliseconds */
sewardjf854f472002-04-21 12:19:41 +0000962 /* It's critical here that valgrind's nanosleep implementation
963 is nonblocking. */
964 (void)my_do_syscall2(__NR_nanosleep,
965 (int)(&nanosleep_interval), (int)NULL);
966 }
967}
968
969
970
971
972#include <sys/poll.h>
973
sewardj72d58482002-04-24 02:20:20 +0000974#ifdef GLIBC_2_1
975typedef unsigned long int nfds_t;
976#endif
977
sewardjf854f472002-04-21 12:19:41 +0000978int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
979{
sewardj5f07b662002-04-23 16:52:51 +0000980 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +0000981 int res, i;
sewardjf854f472002-04-21 12:19:41 +0000982 struct vki_timespec nanosleep_interval;
983
984 ensure_valgrind("poll");
985
sewardj5f07b662002-04-23 16:52:51 +0000986 /* Detect the current time and simultaneously find out if we are
987 running on Valgrind. */
988 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
989 VG_USERREQ__READ_MILLISECOND_TIMER,
990 0, 0, 0, 0);
991
sewardjf854f472002-04-21 12:19:41 +0000992 if (/* CHECK SIZES FOR struct pollfd */
993 sizeof(struct timeval) != sizeof(struct vki_timeval))
994 barf("valgrind's hacky non-blocking poll(): data sizes error");
995
sewardj5f07b662002-04-23 16:52:51 +0000996 /* dummy initialisation to keep gcc -Wall happy */
997 ms_end = 0;
998
999 /* If a zero timeout specified, this call is harmless. Also do
1000 this if not running on Valgrind. */
1001 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001002 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1003 if (is_kerror(res)) {
1004 * (__errno_location()) = -res;
1005 return -1;
1006 } else {
1007 return res;
1008 }
1009 }
1010
sewardj5f07b662002-04-23 16:52:51 +00001011 /* If a timeout was specified, set ms_end to be the end wallclock
1012 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001013 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001014 ms_end += (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001015 }
1016
1017 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1018
1019 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1020 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001021 assert(__timeout != 0);
1022
sewardjf854f472002-04-21 12:19:41 +00001023 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001024 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001025 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1026 VG_USERREQ__READ_MILLISECOND_TIMER,
1027 0, 0, 0, 0);
1028 assert(ms_now != 0xFFFFFFFF);
1029 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001030 /* timeout; nothing interesting happened. */
1031 for (i = 0; i < __nfds; i++)
1032 __fds[i].revents = 0;
1033 return 0;
1034 }
1035 }
1036
sewardj5f07b662002-04-23 16:52:51 +00001037 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001038 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1039 if (is_kerror(res)) {
1040 /* Some kind of error. Set errno and return. */
1041 * (__errno_location()) = -res;
1042 return -1;
1043 }
1044 if (res > 0) {
1045 /* One or more fds is ready. Return now. */
1046 return res;
1047 }
1048 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1049 /* nanosleep and go round again */
1050 nanosleep_interval.tv_sec = 0;
sewardj5f07b662002-04-23 16:52:51 +00001051 nanosleep_interval.tv_nsec = 99 * 1000 * 1000; /* 99 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001052 /* It's critical here that valgrind's nanosleep implementation
1053 is nonblocking. */
1054 (void)my_do_syscall2(__NR_nanosleep,
1055 (int)(&nanosleep_interval), (int)NULL);
1056 }
1057}