blob: 12c1843ac075e43c8778be1ac64ffc3eec44feb1 [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
sewardjbe32e452002-04-24 20:29:58 +0000674
675extern
676int __libc_open64(const char *pathname, int flags, ...);
677int open64(const char *pathname, int flags, ...)
678{
679 return __libc_open64(pathname, flags);
680}
681
sewardje663cb92002-04-12 10:26:32 +0000682
683extern
684int __libc_open(const char *pathname, int flags);
685int open(const char *pathname, int flags)
686{
sewardj45b4b372002-04-16 22:50:32 +0000687 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000688}
689
690
691extern
692int __libc_close(int fd);
693int close(int fd)
694{
sewardj45b4b372002-04-16 22:50:32 +0000695 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000696}
697
698
699extern
700int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
701int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
702{
sewardj45b4b372002-04-16 22:50:32 +0000703 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000704}
705
706
707extern
708pid_t __libc_fork(void);
709pid_t fork(void)
710{
sewardj45b4b372002-04-16 22:50:32 +0000711 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000712}
713
714
715extern
716pid_t __libc_waitpid(pid_t pid, int *status, int options);
717pid_t waitpid(pid_t pid, int *status, int options)
718{
sewardj45b4b372002-04-16 22:50:32 +0000719 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000720}
721
722
723extern
724int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
725int nanosleep(const struct timespec *req, struct timespec *rem)
726{
727 return __libc_nanosleep(req, rem);
728}
729
sewardjbe32e452002-04-24 20:29:58 +0000730
sewardje663cb92002-04-12 10:26:32 +0000731extern
732int __libc_fsync(int fd);
733int fsync(int fd)
734{
sewardj45b4b372002-04-16 22:50:32 +0000735 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000736}
737
sewardjbe32e452002-04-24 20:29:58 +0000738
sewardj70c75362002-04-13 04:18:32 +0000739extern
740off_t __libc_lseek(int fildes, off_t offset, int whence);
741off_t lseek(int fildes, off_t offset, int whence)
742{
sewardj45b4b372002-04-16 22:50:32 +0000743 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000744}
745
sewardjbe32e452002-04-24 20:29:58 +0000746
747extern
748__off64_t __libc_lseek64(int fildes, __off64_t offset, int whence);
749__off64_t lseek64(int fildes, __off64_t offset, int whence)
750{
751 return __libc_lseek64(fildes, offset, whence);
752}
753
754
sewardj6af4b5d2002-04-16 04:40:49 +0000755extern
756void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
757void longjmp(jmp_buf env, int val)
758{
759 __libc_longjmp(env, val);
760}
761
sewardjbe32e452002-04-24 20:29:58 +0000762
sewardj6af4b5d2002-04-16 04:40:49 +0000763extern
764int __libc_send(int s, const void *msg, size_t len, int flags);
765int send(int s, const void *msg, size_t len, int flags)
766{
767 return __libc_send(s, msg, len, flags);
768}
769
sewardjbe32e452002-04-24 20:29:58 +0000770
sewardj1e8cdc92002-04-18 11:37:52 +0000771extern
772int __libc_recv(int s, void *buf, size_t len, int flags);
773int recv(int s, void *buf, size_t len, int flags)
774{
775 return __libc_recv(s, buf, len, flags);
776}
777
sewardjbe32e452002-04-24 20:29:58 +0000778
sewardj796d6a22002-04-24 02:28:34 +0000779extern
780int __libc_sendto(int s, const void *msg, size_t len, int flags,
781 const struct sockaddr *to, socklen_t tolen);
782int sendto(int s, const void *msg, size_t len, int flags,
783 const struct sockaddr *to, socklen_t tolen)
784{
785 return __libc_sendto(s, msg, len, flags, to, tolen);
786}
787
sewardjbe32e452002-04-24 20:29:58 +0000788
sewardj369b1702002-04-24 13:28:15 +0000789extern
790int __libc_system(const char* str);
791int system(const char* str)
792{
793 return __libc_system(str);
794}
795
sewardjbe32e452002-04-24 20:29:58 +0000796
sewardjab0b1c32002-04-24 19:26:47 +0000797extern
798pid_t __libc_wait(int *status);
799pid_t wait(int *status)
800{
801 return __libc_wait(status);
802}
803
sewardj45b4b372002-04-16 22:50:32 +0000804
sewardj70c75362002-04-13 04:18:32 +0000805/*--------------------------------------------------*/
806
sewardje663cb92002-04-12 10:26:32 +0000807/* I've no idea what these are, but they get called quite a lot.
808 Anybody know? */
809
810#undef _IO_flockfile
811void _IO_flockfile ( _IO_FILE * file )
812{
813 // char* str = "_IO_flockfile\n";
814 // write(2, str, strlen(str));
815 // barf("_IO_flockfile");
816}
817
818#undef _IO_funlockfile
819void _IO_funlockfile ( _IO_FILE * file )
820{
821 // char* str = "_IO_funlockfile\n";
822 // write(2, str, strlen(str));
823 //barf("_IO_funlockfile");
824}
825
sewardj08a4c3f2002-04-13 03:45:44 +0000826/*--------------------------------------------------*/
827
828#include "vg_kerneliface.h"
829
830static
831__inline__
832int is_kerror ( int res )
833{
834 if (res >= -4095 && res <= -1)
835 return 1;
836 else
837 return 0;
838}
839
840
841static
842int my_do_syscall1 ( int syscallno, int arg1 )
843{
844 int __res;
845 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
846 : "=a" (__res)
847 : "0" (syscallno),
848 "d" (arg1) );
849 return __res;
850}
851
852static
853int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +0000854 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +0000855{
856 int __res;
857 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
858 : "=a" (__res)
859 : "0" (syscallno),
860 "d" (arg1),
861 "c" (arg2) );
862 return __res;
863}
864
865static
sewardjf854f472002-04-21 12:19:41 +0000866int my_do_syscall3 ( int syscallno,
867 int arg1, int arg2, int arg3 )
868{
869 int __res;
870 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
871 : "=a" (__res)
872 : "0" (syscallno),
873 "S" (arg1),
874 "c" (arg2),
875 "d" (arg3) );
876 return __res;
877}
878
879static
sewardj08a4c3f2002-04-13 03:45:44 +0000880int do_syscall_select( int n,
881 vki_fd_set* readfds,
882 vki_fd_set* writefds,
883 vki_fd_set* exceptfds,
884 struct vki_timeval * timeout )
885{
886 int res;
887 int args[5];
888 args[0] = n;
889 args[1] = (int)readfds;
890 args[2] = (int)writefds;
891 args[3] = (int)exceptfds;
892 args[4] = (int)timeout;
893 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +0000894 return res;
sewardj08a4c3f2002-04-13 03:45:44 +0000895}
896
897
898/* This is a wrapper round select(), which makes it thread-safe,
899 meaning that only this thread will block, rather than the entire
900 process. This wrapper in turn depends on nanosleep() not to block
901 the entire process, but I think (hope? suspect?) that POSIX
902 pthreads guarantees that to be the case.
903
904 Basic idea is: modify the timeout parameter to select so that it
905 returns immediately. Poll like this until select returns non-zero,
906 indicating something interesting happened, or until our time is up.
907 Space out the polls with nanosleeps of say 20 milliseconds, which
908 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +0000909
910 Assumes:
911 * (checked via assert) types fd_set and vki_fd_set are identical.
912 * (checked via assert) types timeval and vki_timeval are identical.
913 * (unchecked) libc error numbers (EINTR etc) are the negation of the
914 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +0000915*/
sewardj08a4c3f2002-04-13 03:45:44 +0000916
917
918int select ( int n,
919 fd_set *rfds,
920 fd_set *wfds,
921 fd_set *xfds,
922 struct timeval *timeout )
923{
sewardj5f07b662002-04-23 16:52:51 +0000924 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +0000925 int res;
926 fd_set rfds_copy;
927 fd_set wfds_copy;
928 fd_set xfds_copy;
929 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +0000930 struct vki_timeval zero_timeout;
931 struct vki_timespec nanosleep_interval;
932
sewardj5f07b662002-04-23 16:52:51 +0000933 /* gcc's complains about ms_end being used uninitialised -- classic
934 case it can't understand, where ms_end is both defined and used
935 only if timeout != NULL. Hence ... */
936 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +0000937
938 /* We assume that the kernel and libc data layouts are identical
939 for the following types. These asserts provide a crude
940 check. */
941 if (sizeof(fd_set) != sizeof(vki_fd_set)
942 || sizeof(struct timeval) != sizeof(struct vki_timeval))
943 barf("valgrind's hacky non-blocking select(): data sizes error");
944
sewardj5f07b662002-04-23 16:52:51 +0000945 /* Detect the current time and simultaneously find out if we are
946 running on Valgrind. */
947 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
948 VG_USERREQ__READ_MILLISECOND_TIMER,
949 0, 0, 0, 0);
950
951 /* If a zero timeout specified, this call is harmless. Also go
952 this route if we're not running on Valgrind, for whatever
953 reason. */
954 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
955 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +0000956 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +0000957 (vki_fd_set*)wfds,
958 (vki_fd_set*)xfds,
959 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +0000960 if (is_kerror(res)) {
961 * (__errno_location()) = -res;
962 return -1;
963 } else {
964 return res;
965 }
966 }
sewardj08a4c3f2002-04-13 03:45:44 +0000967
sewardj5f07b662002-04-23 16:52:51 +0000968 /* If a timeout was specified, set ms_end to be the end millisecond
969 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000970 if (timeout) {
971 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
972 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +0000973 ms_end = ms_now;
974 ms_end += (timeout->tv_usec / 1000);
975 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +0000976 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +0000977 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +0000978 }
979
980 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
981
982 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +0000983 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000984 while (1) {
985 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +0000986 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
987 VG_USERREQ__READ_MILLISECOND_TIMER,
988 0, 0, 0, 0);
989 assert(ms_now != 0xFFFFFFFF);
990 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +0000991 /* timeout; nothing interesting happened. */
992 if (rfds) FD_ZERO(rfds);
993 if (wfds) FD_ZERO(wfds);
994 if (xfds) FD_ZERO(xfds);
995 return 0;
996 }
997 }
998
999 /* These could be trashed each time round the loop, so restore
1000 them each time. */
1001 if (rfds) rfds_copy = *rfds;
1002 if (wfds) wfds_copy = *wfds;
1003 if (xfds) xfds_copy = *xfds;
1004
1005 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
1006
1007 res = do_syscall_select( n,
1008 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
1009 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
1010 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
1011 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +00001012 if (is_kerror(res)) {
1013 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +00001014 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +00001015 * (__errno_location()) = -res;
1016 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +00001017 }
1018 if (res > 0) {
1019 /* one or more fds is ready. Copy out resulting sets and
1020 return. */
1021 if (rfds) *rfds = rfds_copy;
1022 if (wfds) *wfds = wfds_copy;
1023 if (xfds) *xfds = xfds_copy;
1024 return res;
1025 }
1026 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
1027 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +00001028 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001029 nanosleep_interval.tv_nsec = 50 * 1000 * 1000; /* 50 milliseconds */
sewardjf854f472002-04-21 12:19:41 +00001030 /* It's critical here that valgrind's nanosleep implementation
1031 is nonblocking. */
1032 (void)my_do_syscall2(__NR_nanosleep,
1033 (int)(&nanosleep_interval), (int)NULL);
1034 }
1035}
1036
1037
1038
1039
1040#include <sys/poll.h>
1041
sewardj72d58482002-04-24 02:20:20 +00001042#ifdef GLIBC_2_1
1043typedef unsigned long int nfds_t;
1044#endif
1045
sewardjf854f472002-04-21 12:19:41 +00001046int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1047{
sewardj5f07b662002-04-23 16:52:51 +00001048 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001049 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001050 struct vki_timespec nanosleep_interval;
1051
1052 ensure_valgrind("poll");
1053
sewardj5f07b662002-04-23 16:52:51 +00001054 /* Detect the current time and simultaneously find out if we are
1055 running on Valgrind. */
1056 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1057 VG_USERREQ__READ_MILLISECOND_TIMER,
1058 0, 0, 0, 0);
1059
sewardjf854f472002-04-21 12:19:41 +00001060 if (/* CHECK SIZES FOR struct pollfd */
1061 sizeof(struct timeval) != sizeof(struct vki_timeval))
1062 barf("valgrind's hacky non-blocking poll(): data sizes error");
1063
sewardj5f07b662002-04-23 16:52:51 +00001064 /* dummy initialisation to keep gcc -Wall happy */
1065 ms_end = 0;
1066
1067 /* If a zero timeout specified, this call is harmless. Also do
1068 this if not running on Valgrind. */
1069 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001070 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1071 if (is_kerror(res)) {
1072 * (__errno_location()) = -res;
1073 return -1;
1074 } else {
1075 return res;
1076 }
1077 }
1078
sewardj5f07b662002-04-23 16:52:51 +00001079 /* If a timeout was specified, set ms_end to be the end wallclock
1080 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001081 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001082 ms_end += (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001083 }
1084
1085 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1086
1087 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1088 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001089 assert(__timeout != 0);
1090
sewardjf854f472002-04-21 12:19:41 +00001091 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001092 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001093 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1094 VG_USERREQ__READ_MILLISECOND_TIMER,
1095 0, 0, 0, 0);
1096 assert(ms_now != 0xFFFFFFFF);
1097 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001098 /* timeout; nothing interesting happened. */
1099 for (i = 0; i < __nfds; i++)
1100 __fds[i].revents = 0;
1101 return 0;
1102 }
1103 }
1104
sewardj5f07b662002-04-23 16:52:51 +00001105 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001106 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1107 if (is_kerror(res)) {
1108 /* Some kind of error. Set errno and return. */
1109 * (__errno_location()) = -res;
1110 return -1;
1111 }
1112 if (res > 0) {
1113 /* One or more fds is ready. Return now. */
1114 return res;
1115 }
1116 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1117 /* nanosleep and go round again */
1118 nanosleep_interval.tv_sec = 0;
sewardj956cc1b2002-04-25 01:33:50 +00001119 nanosleep_interval.tv_nsec = 51 * 1000 * 1000; /* 51 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001120 /* It's critical here that valgrind's nanosleep implementation
1121 is nonblocking. */
1122 (void)my_do_syscall2(__NR_nanosleep,
1123 (int)(&nanosleep_interval), (int)NULL);
1124 }
1125}