blob: 08ce8141bfa213970fa82ff3a78d4dccc5f9b275 [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/* ---------------------------------------------------
sewardj89d3d852002-04-24 19:21:39 +0000550 ONCEry
551 ------------------------------------------------ */
552
553static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
554
555
556int pthread_once ( pthread_once_t *once_control,
557 void (*init_routine) (void) )
558{
559 int res;
560 ensure_valgrind("pthread_once");
561
562 res = pthread_mutex_lock(&once_masterlock);
563
564 if (res != 0)
565 barf("pthread_once: Looks like your program's "
566 "init routine calls back to pthread_once() ?!");
567
568 if (*once_control == 0) {
569 *once_control = 1;
570 init_routine();
571 }
572
573 pthread_mutex_unlock(&once_masterlock);
574
575 return 0;
576}
577
578
579/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000580 MISC
581 ------------------------------------------------ */
582
583/* What are these? Anybody know? I don't. */
584
585void _pthread_cleanup_push_defer ( void )
586{
587 // char* str = "_pthread_cleanup_push_defer\n";
588 // write(2, str, strlen(str));
589}
590
591void _pthread_cleanup_pop_restore ( void )
592{
593 // char* str = "_pthread_cleanup_pop_restore\n";
594 // write(2, str, strlen(str));
595}
596
597
598pthread_t pthread_self(void)
599{
600 int tid;
601 ensure_valgrind("pthread_self");
602 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
603 VG_USERREQ__PTHREAD_GET_THREADID,
604 0, 0, 0, 0);
605 if (tid < 0 || tid >= VG_N_THREADS)
606 barf("pthread_self: invalid ThreadId");
607 return tid;
608}
609
610
sewardje663cb92002-04-12 10:26:32 +0000611/* ---------------------------------------------------------------------
612 These are here (I think) because they are deemed cancellation
613 points by POSIX. For the moment we'll simply pass the call along
614 to the corresponding thread-unaware (?) libc routine.
615 ------------------------------------------------------------------ */
616
sewardje663cb92002-04-12 10:26:32 +0000617#include <stdlib.h>
618#include <signal.h>
sewardje663cb92002-04-12 10:26:32 +0000619#include <sys/types.h>
620#include <sys/socket.h>
621
622extern
623int __libc_sigaction
624 (int signum,
625 const struct sigaction *act,
626 struct sigaction *oldact);
627int sigaction(int signum,
628 const struct sigaction *act,
629 struct sigaction *oldact)
630{
sewardj2a1dcce2002-04-22 12:45:25 +0000631# ifdef GLIBC_2_1
632 return __sigaction(signum, act, oldact);
633# else
sewardj45b4b372002-04-16 22:50:32 +0000634 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +0000635# endif
sewardje663cb92002-04-12 10:26:32 +0000636}
637
638
639extern
640int __libc_connect(int sockfd,
641 const struct sockaddr *serv_addr,
642 socklen_t addrlen);
643int connect(int sockfd,
644 const struct sockaddr *serv_addr,
645 socklen_t addrlen)
646{
sewardj45b4b372002-04-16 22:50:32 +0000647 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000648}
649
650
651extern
652int __libc_fcntl(int fd, int cmd, long arg);
653int fcntl(int fd, int cmd, long arg)
654{
sewardj45b4b372002-04-16 22:50:32 +0000655 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000656}
657
658
659extern
660ssize_t __libc_write(int fd, const void *buf, size_t count);
661ssize_t write(int fd, const void *buf, size_t count)
662{
sewardj45b4b372002-04-16 22:50:32 +0000663 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000664}
665
666
667extern
668ssize_t __libc_read(int fd, void *buf, size_t count);
669ssize_t read(int fd, void *buf, size_t count)
670{
sewardj45b4b372002-04-16 22:50:32 +0000671 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000672}
673
674
675extern
676int __libc_open(const char *pathname, int flags);
677int open(const char *pathname, int flags)
678{
sewardj45b4b372002-04-16 22:50:32 +0000679 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000680}
681
682
683extern
684int __libc_close(int fd);
685int close(int fd)
686{
sewardj45b4b372002-04-16 22:50:32 +0000687 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000688}
689
690
691extern
692int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
693int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
694{
sewardj45b4b372002-04-16 22:50:32 +0000695 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000696}
697
698
699extern
700pid_t __libc_fork(void);
701pid_t fork(void)
702{
sewardj45b4b372002-04-16 22:50:32 +0000703 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000704}
705
706
707extern
708pid_t __libc_waitpid(pid_t pid, int *status, int options);
709pid_t waitpid(pid_t pid, int *status, int options)
710{
sewardj45b4b372002-04-16 22:50:32 +0000711 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000712}
713
714
715extern
716int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
717int nanosleep(const struct timespec *req, struct timespec *rem)
718{
719 return __libc_nanosleep(req, rem);
720}
721
722extern
723int __libc_fsync(int fd);
724int fsync(int fd)
725{
sewardj45b4b372002-04-16 22:50:32 +0000726 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000727}
728
sewardj70c75362002-04-13 04:18:32 +0000729extern
730off_t __libc_lseek(int fildes, off_t offset, int whence);
731off_t lseek(int fildes, off_t offset, int whence)
732{
sewardj45b4b372002-04-16 22:50:32 +0000733 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000734}
735
sewardj6af4b5d2002-04-16 04:40:49 +0000736extern
737void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
738void longjmp(jmp_buf env, int val)
739{
740 __libc_longjmp(env, val);
741}
742
743extern
744int __libc_send(int s, const void *msg, size_t len, int flags);
745int send(int s, const void *msg, size_t len, int flags)
746{
747 return __libc_send(s, msg, len, flags);
748}
749
sewardj1e8cdc92002-04-18 11:37:52 +0000750extern
751int __libc_recv(int s, void *buf, size_t len, int flags);
752int recv(int s, void *buf, size_t len, int flags)
753{
754 return __libc_recv(s, buf, len, flags);
755}
756
sewardj796d6a22002-04-24 02:28:34 +0000757extern
758int __libc_sendto(int s, const void *msg, size_t len, int flags,
759 const struct sockaddr *to, socklen_t tolen);
760int sendto(int s, const void *msg, size_t len, int flags,
761 const struct sockaddr *to, socklen_t tolen)
762{
763 return __libc_sendto(s, msg, len, flags, to, tolen);
764}
765
sewardj369b1702002-04-24 13:28:15 +0000766extern
767int __libc_system(const char* str);
768int system(const char* str)
769{
770 return __libc_system(str);
771}
772
sewardjab0b1c32002-04-24 19:26:47 +0000773extern
774pid_t __libc_wait(int *status);
775pid_t wait(int *status)
776{
777 return __libc_wait(status);
778}
779
sewardj45b4b372002-04-16 22:50:32 +0000780
sewardj70c75362002-04-13 04:18:32 +0000781/*--------------------------------------------------*/
782
sewardje663cb92002-04-12 10:26:32 +0000783/* I've no idea what these are, but they get called quite a lot.
784 Anybody know? */
785
786#undef _IO_flockfile
787void _IO_flockfile ( _IO_FILE * file )
788{
789 // char* str = "_IO_flockfile\n";
790 // write(2, str, strlen(str));
791 // barf("_IO_flockfile");
792}
793
794#undef _IO_funlockfile
795void _IO_funlockfile ( _IO_FILE * file )
796{
797 // char* str = "_IO_funlockfile\n";
798 // write(2, str, strlen(str));
799 //barf("_IO_funlockfile");
800}
801
sewardj08a4c3f2002-04-13 03:45:44 +0000802/*--------------------------------------------------*/
803
804#include "vg_kerneliface.h"
805
806static
807__inline__
808int is_kerror ( int res )
809{
810 if (res >= -4095 && res <= -1)
811 return 1;
812 else
813 return 0;
814}
815
816
817static
818int my_do_syscall1 ( int syscallno, int arg1 )
819{
820 int __res;
821 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
822 : "=a" (__res)
823 : "0" (syscallno),
824 "d" (arg1) );
825 return __res;
826}
827
828static
829int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +0000830 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +0000831{
832 int __res;
833 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
834 : "=a" (__res)
835 : "0" (syscallno),
836 "d" (arg1),
837 "c" (arg2) );
838 return __res;
839}
840
841static
sewardjf854f472002-04-21 12:19:41 +0000842int my_do_syscall3 ( int syscallno,
843 int arg1, int arg2, int arg3 )
844{
845 int __res;
846 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
847 : "=a" (__res)
848 : "0" (syscallno),
849 "S" (arg1),
850 "c" (arg2),
851 "d" (arg3) );
852 return __res;
853}
854
855static
sewardj08a4c3f2002-04-13 03:45:44 +0000856int do_syscall_select( int n,
857 vki_fd_set* readfds,
858 vki_fd_set* writefds,
859 vki_fd_set* exceptfds,
860 struct vki_timeval * timeout )
861{
862 int res;
863 int args[5];
864 args[0] = n;
865 args[1] = (int)readfds;
866 args[2] = (int)writefds;
867 args[3] = (int)exceptfds;
868 args[4] = (int)timeout;
869 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +0000870 return res;
sewardj08a4c3f2002-04-13 03:45:44 +0000871}
872
873
874/* This is a wrapper round select(), which makes it thread-safe,
875 meaning that only this thread will block, rather than the entire
876 process. This wrapper in turn depends on nanosleep() not to block
877 the entire process, but I think (hope? suspect?) that POSIX
878 pthreads guarantees that to be the case.
879
880 Basic idea is: modify the timeout parameter to select so that it
881 returns immediately. Poll like this until select returns non-zero,
882 indicating something interesting happened, or until our time is up.
883 Space out the polls with nanosleeps of say 20 milliseconds, which
884 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +0000885
886 Assumes:
887 * (checked via assert) types fd_set and vki_fd_set are identical.
888 * (checked via assert) types timeval and vki_timeval are identical.
889 * (unchecked) libc error numbers (EINTR etc) are the negation of the
890 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +0000891*/
sewardj08a4c3f2002-04-13 03:45:44 +0000892
893
894int select ( int n,
895 fd_set *rfds,
896 fd_set *wfds,
897 fd_set *xfds,
898 struct timeval *timeout )
899{
sewardj5f07b662002-04-23 16:52:51 +0000900 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +0000901 int res;
902 fd_set rfds_copy;
903 fd_set wfds_copy;
904 fd_set xfds_copy;
905 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +0000906 struct vki_timeval zero_timeout;
907 struct vki_timespec nanosleep_interval;
908
sewardj5f07b662002-04-23 16:52:51 +0000909 /* gcc's complains about ms_end being used uninitialised -- classic
910 case it can't understand, where ms_end is both defined and used
911 only if timeout != NULL. Hence ... */
912 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +0000913
914 /* We assume that the kernel and libc data layouts are identical
915 for the following types. These asserts provide a crude
916 check. */
917 if (sizeof(fd_set) != sizeof(vki_fd_set)
918 || sizeof(struct timeval) != sizeof(struct vki_timeval))
919 barf("valgrind's hacky non-blocking select(): data sizes error");
920
sewardj5f07b662002-04-23 16:52:51 +0000921 /* Detect the current time and simultaneously find out if we are
922 running on Valgrind. */
923 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
924 VG_USERREQ__READ_MILLISECOND_TIMER,
925 0, 0, 0, 0);
926
927 /* If a zero timeout specified, this call is harmless. Also go
928 this route if we're not running on Valgrind, for whatever
929 reason. */
930 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
931 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +0000932 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +0000933 (vki_fd_set*)wfds,
934 (vki_fd_set*)xfds,
935 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +0000936 if (is_kerror(res)) {
937 * (__errno_location()) = -res;
938 return -1;
939 } else {
940 return res;
941 }
942 }
sewardj08a4c3f2002-04-13 03:45:44 +0000943
sewardj5f07b662002-04-23 16:52:51 +0000944 /* If a timeout was specified, set ms_end to be the end millisecond
945 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000946 if (timeout) {
947 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
948 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +0000949 ms_end = ms_now;
950 ms_end += (timeout->tv_usec / 1000);
951 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +0000952 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +0000953 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +0000954 }
955
956 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
957
958 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +0000959 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000960 while (1) {
961 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +0000962 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
963 VG_USERREQ__READ_MILLISECOND_TIMER,
964 0, 0, 0, 0);
965 assert(ms_now != 0xFFFFFFFF);
966 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +0000967 /* timeout; nothing interesting happened. */
968 if (rfds) FD_ZERO(rfds);
969 if (wfds) FD_ZERO(wfds);
970 if (xfds) FD_ZERO(xfds);
971 return 0;
972 }
973 }
974
975 /* These could be trashed each time round the loop, so restore
976 them each time. */
977 if (rfds) rfds_copy = *rfds;
978 if (wfds) wfds_copy = *wfds;
979 if (xfds) xfds_copy = *xfds;
980
981 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
982
983 res = do_syscall_select( n,
984 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
985 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
986 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
987 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +0000988 if (is_kerror(res)) {
989 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +0000990 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +0000991 * (__errno_location()) = -res;
992 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +0000993 }
994 if (res > 0) {
995 /* one or more fds is ready. Copy out resulting sets and
996 return. */
997 if (rfds) *rfds = rfds_copy;
998 if (wfds) *wfds = wfds_copy;
999 if (xfds) *xfds = xfds_copy;
1000 return res;
1001 }
1002 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1003 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001004 nanosleep_interval.tv_sec = 0;
sewardj5f07b662002-04-23 16:52:51 +00001005 nanosleep_interval.tv_nsec = 100 * 1000 * 1000; /* 100 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001006 /* It's critical here that valgrind's nanosleep implementation
1007 is nonblocking. */
1008 (void)my_do_syscall2(__NR_nanosleep,
1009 (int)(&nanosleep_interval), (int)NULL);
1010 }
1011}
1012
1013
1014
1015
1016#include <sys/poll.h>
1017
sewardj72d58482002-04-24 02:20:20 +00001018#ifdef GLIBC_2_1
1019typedef unsigned long int nfds_t;
1020#endif
1021
sewardjf854f472002-04-21 12:19:41 +00001022int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1023{
sewardj5f07b662002-04-23 16:52:51 +00001024 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001025 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001026 struct vki_timespec nanosleep_interval;
1027
1028 ensure_valgrind("poll");
1029
sewardj5f07b662002-04-23 16:52:51 +00001030 /* Detect the current time and simultaneously find out if we are
1031 running on Valgrind. */
1032 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1033 VG_USERREQ__READ_MILLISECOND_TIMER,
1034 0, 0, 0, 0);
1035
sewardjf854f472002-04-21 12:19:41 +00001036 if (/* CHECK SIZES FOR struct pollfd */
1037 sizeof(struct timeval) != sizeof(struct vki_timeval))
1038 barf("valgrind's hacky non-blocking poll(): data sizes error");
1039
sewardj5f07b662002-04-23 16:52:51 +00001040 /* dummy initialisation to keep gcc -Wall happy */
1041 ms_end = 0;
1042
1043 /* If a zero timeout specified, this call is harmless. Also do
1044 this if not running on Valgrind. */
1045 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001046 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1047 if (is_kerror(res)) {
1048 * (__errno_location()) = -res;
1049 return -1;
1050 } else {
1051 return res;
1052 }
1053 }
1054
sewardj5f07b662002-04-23 16:52:51 +00001055 /* If a timeout was specified, set ms_end to be the end wallclock
1056 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001057 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001058 ms_end += (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001059 }
1060
1061 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1062
1063 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1064 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001065 assert(__timeout != 0);
1066
sewardjf854f472002-04-21 12:19:41 +00001067 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001068 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001069 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1070 VG_USERREQ__READ_MILLISECOND_TIMER,
1071 0, 0, 0, 0);
1072 assert(ms_now != 0xFFFFFFFF);
1073 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001074 /* timeout; nothing interesting happened. */
1075 for (i = 0; i < __nfds; i++)
1076 __fds[i].revents = 0;
1077 return 0;
1078 }
1079 }
1080
sewardj5f07b662002-04-23 16:52:51 +00001081 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001082 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1083 if (is_kerror(res)) {
1084 /* Some kind of error. Set errno and return. */
1085 * (__errno_location()) = -res;
1086 return -1;
1087 }
1088 if (res > 0) {
1089 /* One or more fds is ready. Return now. */
1090 return res;
1091 }
1092 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1093 /* nanosleep and go round again */
1094 nanosleep_interval.tv_sec = 0;
sewardj5f07b662002-04-23 16:52:51 +00001095 nanosleep_interval.tv_nsec = 99 * 1000 * 1000; /* 99 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001096 /* It's critical here that valgrind's nanosleep implementation
1097 is nonblocking. */
1098 (void)my_do_syscall2(__NR_nanosleep,
1099 (int)(&nanosleep_interval), (int)NULL);
1100 }
1101}