blob: 9081c7dfd3f1e99e2879bd6f53e5e33dee211ae2 [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
sewardj45b4b372002-04-16 22:50:32 +0000773
sewardj70c75362002-04-13 04:18:32 +0000774/*--------------------------------------------------*/
775
sewardje663cb92002-04-12 10:26:32 +0000776/* I've no idea what these are, but they get called quite a lot.
777 Anybody know? */
778
779#undef _IO_flockfile
780void _IO_flockfile ( _IO_FILE * file )
781{
782 // char* str = "_IO_flockfile\n";
783 // write(2, str, strlen(str));
784 // barf("_IO_flockfile");
785}
786
787#undef _IO_funlockfile
788void _IO_funlockfile ( _IO_FILE * file )
789{
790 // char* str = "_IO_funlockfile\n";
791 // write(2, str, strlen(str));
792 //barf("_IO_funlockfile");
793}
794
sewardj08a4c3f2002-04-13 03:45:44 +0000795/*--------------------------------------------------*/
796
797#include "vg_kerneliface.h"
798
799static
800__inline__
801int is_kerror ( int res )
802{
803 if (res >= -4095 && res <= -1)
804 return 1;
805 else
806 return 0;
807}
808
809
810static
811int my_do_syscall1 ( int syscallno, int arg1 )
812{
813 int __res;
814 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
815 : "=a" (__res)
816 : "0" (syscallno),
817 "d" (arg1) );
818 return __res;
819}
820
821static
822int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +0000823 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +0000824{
825 int __res;
826 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
827 : "=a" (__res)
828 : "0" (syscallno),
829 "d" (arg1),
830 "c" (arg2) );
831 return __res;
832}
833
834static
sewardjf854f472002-04-21 12:19:41 +0000835int my_do_syscall3 ( int syscallno,
836 int arg1, int arg2, int arg3 )
837{
838 int __res;
839 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
840 : "=a" (__res)
841 : "0" (syscallno),
842 "S" (arg1),
843 "c" (arg2),
844 "d" (arg3) );
845 return __res;
846}
847
848static
sewardj08a4c3f2002-04-13 03:45:44 +0000849int do_syscall_select( int n,
850 vki_fd_set* readfds,
851 vki_fd_set* writefds,
852 vki_fd_set* exceptfds,
853 struct vki_timeval * timeout )
854{
855 int res;
856 int args[5];
857 args[0] = n;
858 args[1] = (int)readfds;
859 args[2] = (int)writefds;
860 args[3] = (int)exceptfds;
861 args[4] = (int)timeout;
862 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +0000863 return res;
sewardj08a4c3f2002-04-13 03:45:44 +0000864}
865
866
867/* This is a wrapper round select(), which makes it thread-safe,
868 meaning that only this thread will block, rather than the entire
869 process. This wrapper in turn depends on nanosleep() not to block
870 the entire process, but I think (hope? suspect?) that POSIX
871 pthreads guarantees that to be the case.
872
873 Basic idea is: modify the timeout parameter to select so that it
874 returns immediately. Poll like this until select returns non-zero,
875 indicating something interesting happened, or until our time is up.
876 Space out the polls with nanosleeps of say 20 milliseconds, which
877 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +0000878
879 Assumes:
880 * (checked via assert) types fd_set and vki_fd_set are identical.
881 * (checked via assert) types timeval and vki_timeval are identical.
882 * (unchecked) libc error numbers (EINTR etc) are the negation of the
883 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +0000884*/
sewardj08a4c3f2002-04-13 03:45:44 +0000885
886
887int select ( int n,
888 fd_set *rfds,
889 fd_set *wfds,
890 fd_set *xfds,
891 struct timeval *timeout )
892{
sewardj5f07b662002-04-23 16:52:51 +0000893 unsigned int ms_now, ms_end;
sewardj08a4c3f2002-04-13 03:45:44 +0000894 int res;
895 fd_set rfds_copy;
896 fd_set wfds_copy;
897 fd_set xfds_copy;
898 struct vki_timeval t_now;
sewardj08a4c3f2002-04-13 03:45:44 +0000899 struct vki_timeval zero_timeout;
900 struct vki_timespec nanosleep_interval;
901
sewardj5f07b662002-04-23 16:52:51 +0000902 /* gcc's complains about ms_end being used uninitialised -- classic
903 case it can't understand, where ms_end is both defined and used
904 only if timeout != NULL. Hence ... */
905 ms_end = 0;
sewardj08a4c3f2002-04-13 03:45:44 +0000906
907 /* We assume that the kernel and libc data layouts are identical
908 for the following types. These asserts provide a crude
909 check. */
910 if (sizeof(fd_set) != sizeof(vki_fd_set)
911 || sizeof(struct timeval) != sizeof(struct vki_timeval))
912 barf("valgrind's hacky non-blocking select(): data sizes error");
913
sewardj5f07b662002-04-23 16:52:51 +0000914 /* Detect the current time and simultaneously find out if we are
915 running on Valgrind. */
916 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
917 VG_USERREQ__READ_MILLISECOND_TIMER,
918 0, 0, 0, 0);
919
920 /* If a zero timeout specified, this call is harmless. Also go
921 this route if we're not running on Valgrind, for whatever
922 reason. */
923 if ( (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
924 || (ms_now == 0xFFFFFFFF) ) {
sewardj02535bc2002-04-21 01:08:26 +0000925 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +0000926 (vki_fd_set*)wfds,
927 (vki_fd_set*)xfds,
928 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +0000929 if (is_kerror(res)) {
930 * (__errno_location()) = -res;
931 return -1;
932 } else {
933 return res;
934 }
935 }
sewardj08a4c3f2002-04-13 03:45:44 +0000936
sewardj5f07b662002-04-23 16:52:51 +0000937 /* If a timeout was specified, set ms_end to be the end millisecond
938 counter [wallclock] time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000939 if (timeout) {
940 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
941 assert(res == 0);
sewardj5f07b662002-04-23 16:52:51 +0000942 ms_end = ms_now;
943 ms_end += (timeout->tv_usec / 1000);
944 ms_end += (timeout->tv_sec * 1000);
sewardj08a4c3f2002-04-13 03:45:44 +0000945 /* Stay sane ... */
sewardj5f07b662002-04-23 16:52:51 +0000946 assert (ms_end >= ms_now);
sewardj08a4c3f2002-04-13 03:45:44 +0000947 }
948
949 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
950
951 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
sewardj5f07b662002-04-23 16:52:51 +0000952 NULL, in which case ms_end holds the end time. */
sewardj08a4c3f2002-04-13 03:45:44 +0000953 while (1) {
954 if (timeout) {
sewardj5f07b662002-04-23 16:52:51 +0000955 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
956 VG_USERREQ__READ_MILLISECOND_TIMER,
957 0, 0, 0, 0);
958 assert(ms_now != 0xFFFFFFFF);
959 if (ms_now >= ms_end) {
sewardj08a4c3f2002-04-13 03:45:44 +0000960 /* timeout; nothing interesting happened. */
961 if (rfds) FD_ZERO(rfds);
962 if (wfds) FD_ZERO(wfds);
963 if (xfds) FD_ZERO(xfds);
964 return 0;
965 }
966 }
967
968 /* These could be trashed each time round the loop, so restore
969 them each time. */
970 if (rfds) rfds_copy = *rfds;
971 if (wfds) wfds_copy = *wfds;
972 if (xfds) xfds_copy = *xfds;
973
974 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
975
976 res = do_syscall_select( n,
977 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
978 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
979 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
980 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +0000981 if (is_kerror(res)) {
982 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +0000983 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +0000984 * (__errno_location()) = -res;
985 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +0000986 }
987 if (res > 0) {
988 /* one or more fds is ready. Copy out resulting sets and
989 return. */
990 if (rfds) *rfds = rfds_copy;
991 if (wfds) *wfds = wfds_copy;
992 if (xfds) *xfds = xfds_copy;
993 return res;
994 }
995 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
996 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +0000997 nanosleep_interval.tv_sec = 0;
sewardj5f07b662002-04-23 16:52:51 +0000998 nanosleep_interval.tv_nsec = 100 * 1000 * 1000; /* 100 milliseconds */
sewardjf854f472002-04-21 12:19:41 +0000999 /* It's critical here that valgrind's nanosleep implementation
1000 is nonblocking. */
1001 (void)my_do_syscall2(__NR_nanosleep,
1002 (int)(&nanosleep_interval), (int)NULL);
1003 }
1004}
1005
1006
1007
1008
1009#include <sys/poll.h>
1010
sewardj72d58482002-04-24 02:20:20 +00001011#ifdef GLIBC_2_1
1012typedef unsigned long int nfds_t;
1013#endif
1014
sewardjf854f472002-04-21 12:19:41 +00001015int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
1016{
sewardj5f07b662002-04-23 16:52:51 +00001017 unsigned int ms_now, ms_end;
sewardjf854f472002-04-21 12:19:41 +00001018 int res, i;
sewardjf854f472002-04-21 12:19:41 +00001019 struct vki_timespec nanosleep_interval;
1020
1021 ensure_valgrind("poll");
1022
sewardj5f07b662002-04-23 16:52:51 +00001023 /* Detect the current time and simultaneously find out if we are
1024 running on Valgrind. */
1025 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1026 VG_USERREQ__READ_MILLISECOND_TIMER,
1027 0, 0, 0, 0);
1028
sewardjf854f472002-04-21 12:19:41 +00001029 if (/* CHECK SIZES FOR struct pollfd */
1030 sizeof(struct timeval) != sizeof(struct vki_timeval))
1031 barf("valgrind's hacky non-blocking poll(): data sizes error");
1032
sewardj5f07b662002-04-23 16:52:51 +00001033 /* dummy initialisation to keep gcc -Wall happy */
1034 ms_end = 0;
1035
1036 /* If a zero timeout specified, this call is harmless. Also do
1037 this if not running on Valgrind. */
1038 if (__timeout == 0 || ms_now == 0xFFFFFFFF) {
sewardjf854f472002-04-21 12:19:41 +00001039 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
1040 if (is_kerror(res)) {
1041 * (__errno_location()) = -res;
1042 return -1;
1043 } else {
1044 return res;
1045 }
1046 }
1047
sewardj5f07b662002-04-23 16:52:51 +00001048 /* If a timeout was specified, set ms_end to be the end wallclock
1049 time. Easy considering that __timeout is in milliseconds. */
sewardjf854f472002-04-21 12:19:41 +00001050 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001051 ms_end += (unsigned int)__timeout;
sewardjf854f472002-04-21 12:19:41 +00001052 }
1053
1054 /* fprintf(stderr, "MY_POLL: before loop\n"); */
1055
1056 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
1057 in which case t_end holds the end time. */
sewardj5f07b662002-04-23 16:52:51 +00001058 assert(__timeout != 0);
1059
sewardjf854f472002-04-21 12:19:41 +00001060 while (1) {
sewardjf854f472002-04-21 12:19:41 +00001061 if (__timeout > 0) {
sewardj5f07b662002-04-23 16:52:51 +00001062 VALGRIND_MAGIC_SEQUENCE(ms_now, 0xFFFFFFFF /* default */,
1063 VG_USERREQ__READ_MILLISECOND_TIMER,
1064 0, 0, 0, 0);
1065 assert(ms_now != 0xFFFFFFFF);
1066 if (ms_now >= ms_end) {
sewardjf854f472002-04-21 12:19:41 +00001067 /* timeout; nothing interesting happened. */
1068 for (i = 0; i < __nfds; i++)
1069 __fds[i].revents = 0;
1070 return 0;
1071 }
1072 }
1073
sewardj5f07b662002-04-23 16:52:51 +00001074 /* Do a return-immediately poll. */
sewardjf854f472002-04-21 12:19:41 +00001075 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
1076 if (is_kerror(res)) {
1077 /* Some kind of error. Set errno and return. */
1078 * (__errno_location()) = -res;
1079 return -1;
1080 }
1081 if (res > 0) {
1082 /* One or more fds is ready. Return now. */
1083 return res;
1084 }
1085 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
1086 /* nanosleep and go round again */
1087 nanosleep_interval.tv_sec = 0;
sewardj5f07b662002-04-23 16:52:51 +00001088 nanosleep_interval.tv_nsec = 99 * 1000 * 1000; /* 99 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +00001089 /* It's critical here that valgrind's nanosleep implementation
1090 is nonblocking. */
1091 (void)my_do_syscall2(__NR_nanosleep,
1092 (int)(&nanosleep_interval), (int)NULL);
1093 }
1094}