blob: fb70ec6ea8ee5edef89a6c9a47c8c756f64ce9d7 [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>
137
138/* ---------------------------------------------------
139 THREAD ATTRIBUTES
140 ------------------------------------------------ */
141
sewardj6af4b5d2002-04-16 04:40:49 +0000142int pthread_attr_init(pthread_attr_t *attr)
143{
144 ignored("pthread_attr_init");
145 return 0;
146}
147
148int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
149{
150 ignored("pthread_attr_setdetachstate");
151 return 0;
152}
153
sewardj30671ff2002-04-21 00:13:57 +0000154int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
155{
156 ignored("pthread_attr_setinheritsched");
157 return 0;
158}
sewardj6af4b5d2002-04-16 04:40:49 +0000159
sewardj30671ff2002-04-21 00:13:57 +0000160/* This is completely bogus. */
161int pthread_attr_getschedparam(const pthread_attr_t *attr,
162 struct sched_param *param)
163{
164 kludged("pthread_attr_getschedparam");
165 if (param) param->__sched_priority = 0; /* who knows */
166 return 0;
167}
168
169int pthread_attr_setschedparam(pthread_attr_t *attr,
170 const struct sched_param *param)
171{
172 ignored("pthread_attr_setschedparam");
173 return 0;
174}
175
176int pthread_attr_destroy(pthread_attr_t *attr)
177{
178 ignored("pthread_attr_destroy");
179 return 0;
180}
sewardjf8f819e2002-04-17 23:21:37 +0000181
182/* ---------------------------------------------------
183 THREADs
184 ------------------------------------------------ */
185
sewardj6072c362002-04-19 14:40:57 +0000186int pthread_equal(pthread_t thread1, pthread_t thread2)
187{
188 return thread1 == thread2 ? 1 : 0;
189}
190
191
sewardje663cb92002-04-12 10:26:32 +0000192int
193pthread_create (pthread_t *__restrict __thread,
194 __const pthread_attr_t *__restrict __attr,
195 void *(*__start_routine) (void *),
196 void *__restrict __arg)
197{
198 int res;
199 ensure_valgrind("pthread_create");
200 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
201 VG_USERREQ__PTHREAD_CREATE,
202 __thread, __attr, __start_routine, __arg);
203 return res;
204}
205
206
207
208int
209pthread_join (pthread_t __th, void **__thread_return)
210{
211 int res;
212 ensure_valgrind("pthread_join");
213 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
214 VG_USERREQ__PTHREAD_JOIN,
215 __th, __thread_return, 0, 0);
216 return res;
217}
218
219
sewardj3b5d8862002-04-20 13:53:23 +0000220void pthread_exit(void *retval)
221{
222 int res;
223 ensure_valgrind("pthread_exit");
224 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
225 VG_USERREQ__PTHREAD_EXIT,
226 retval, 0, 0, 0);
227 /* Doesn't return! */
228 /* However, we have to fool gcc into knowing that. */
229 barf("pthread_exit: still alive after request?!");
230}
231
sewardje663cb92002-04-12 10:26:32 +0000232
233static int thread_specific_errno[VG_N_THREADS];
234
235int* __errno_location ( void )
236{
237 int tid;
sewardj35805422002-04-21 13:05:34 +0000238 /* ensure_valgrind("__errno_location"); */
sewardje663cb92002-04-12 10:26:32 +0000239 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
240 VG_USERREQ__PTHREAD_GET_THREADID,
241 0, 0, 0, 0);
242 /* 'cos I'm paranoid ... */
243 if (tid < 0 || tid >= VG_N_THREADS)
244 barf("__errno_location: invalid ThreadId");
245 return & thread_specific_errno[tid];
246}
247
248
sewardjf8f819e2002-04-17 23:21:37 +0000249/* ---------------------------------------------------
250 MUTEX ATTRIBUTES
251 ------------------------------------------------ */
252
sewardje663cb92002-04-12 10:26:32 +0000253int pthread_mutexattr_init(pthread_mutexattr_t *attr)
254{
sewardjf8f819e2002-04-17 23:21:37 +0000255 attr->__mutexkind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj8937c812002-04-12 20:12:20 +0000256 return 0;
sewardje663cb92002-04-12 10:26:32 +0000257}
258
sewardjf8f819e2002-04-17 23:21:37 +0000259int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
260{
261 switch (type) {
sewardj2a1dcce2002-04-22 12:45:25 +0000262#ifndef GLIBC_2_1
sewardjf8f819e2002-04-17 23:21:37 +0000263 case PTHREAD_MUTEX_TIMED_NP:
sewardj2a1dcce2002-04-22 12:45:25 +0000264 case PTHREAD_MUTEX_ADAPTIVE_NP:
265#endif
sewardjf8f819e2002-04-17 23:21:37 +0000266 case PTHREAD_MUTEX_RECURSIVE_NP:
267 case PTHREAD_MUTEX_ERRORCHECK_NP:
sewardjf8f819e2002-04-17 23:21:37 +0000268 attr->__mutexkind = type;
269 return 0;
270 default:
271 return EINVAL;
272 }
273}
274
275int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
276{
277 return 0;
278}
279
280
281/* ---------------------------------------------------
282 MUTEXes
283 ------------------------------------------------ */
284
sewardje663cb92002-04-12 10:26:32 +0000285int pthread_mutex_init(pthread_mutex_t *mutex,
286 const pthread_mutexattr_t *mutexattr)
287{
sewardj604ec3c2002-04-18 22:38:41 +0000288 mutex->__m_count = 0;
289 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
290 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
291 if (mutexattr)
292 mutex->__m_kind = mutexattr->__mutexkind;
293 return 0;
sewardje663cb92002-04-12 10:26:32 +0000294}
295
sewardje663cb92002-04-12 10:26:32 +0000296int pthread_mutex_lock(pthread_mutex_t *mutex)
297{
298 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000299 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000300 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000301 char* str = "pthread_mutex_lock-NOT-INSIDE-VALGRIND\n";
302 write(2, str, strlen(str));
303 return 0;
304 } else {
305 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
306 VG_USERREQ__PTHREAD_MUTEX_LOCK,
307 mutex, 0, 0, 0);
308 return res;
309 }
310}
311
sewardj30671ff2002-04-21 00:13:57 +0000312int pthread_mutex_trylock(pthread_mutex_t *mutex)
313{
314 int res;
315 static int moans = 3;
316 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
317 char* str = "pthread_mutex_trylock-NOT-INSIDE-VALGRIND\n";
318 write(2, str, strlen(str));
319 return 0;
320 } else {
321 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
322 VG_USERREQ__PTHREAD_MUTEX_TRYLOCK,
323 mutex, 0, 0, 0);
324 return res;
325 }
326}
327
sewardje663cb92002-04-12 10:26:32 +0000328int pthread_mutex_unlock(pthread_mutex_t *mutex)
329{
330 int res;
sewardj604ec3c2002-04-18 22:38:41 +0000331 static int moans = 3;
sewardj45b4b372002-04-16 22:50:32 +0000332 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000333 char* str = "pthread_mutex_unlock-NOT-INSIDE-VALGRIND\n";
334 write(2, str, strlen(str));
335 return 0;
336 } else {
337 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
338 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
339 mutex, 0, 0, 0);
340 return res;
341 }
342}
343
sewardje663cb92002-04-12 10:26:32 +0000344int pthread_mutex_destroy(pthread_mutex_t *mutex)
345{
sewardj604ec3c2002-04-18 22:38:41 +0000346 /* Valgrind doesn't hold any resources on behalf of the mutex, so no
347 need to involve it. */
348 if (mutex->__m_count > 0)
349 return EBUSY;
sewardj6072c362002-04-19 14:40:57 +0000350 mutex->__m_count = 0;
351 mutex->__m_owner = (_pthread_descr)VG_INVALID_THREADID;
352 mutex->__m_kind = PTHREAD_MUTEX_ERRORCHECK_NP;
sewardj604ec3c2002-04-18 22:38:41 +0000353 return 0;
sewardje663cb92002-04-12 10:26:32 +0000354}
355
356
sewardjf8f819e2002-04-17 23:21:37 +0000357/* ---------------------------------------------------
sewardj6072c362002-04-19 14:40:57 +0000358 CONDITION VARIABLES
359 ------------------------------------------------ */
360
361/* LinuxThreads supports no attributes for conditions. Hence ... */
362
363int pthread_condattr_init(pthread_condattr_t *attr)
364{
365 return 0;
366}
367
sewardj0738a592002-04-20 13:59:33 +0000368int pthread_condattr_destroy(pthread_condattr_t *attr)
369{
370 return 0;
371}
sewardj6072c362002-04-19 14:40:57 +0000372
373int pthread_cond_init( pthread_cond_t *cond,
374 const pthread_condattr_t *cond_attr)
375{
376 cond->__c_waiting = (_pthread_descr)VG_INVALID_THREADID;
377 return 0;
378}
379
sewardjf854f472002-04-21 12:19:41 +0000380int pthread_cond_destroy(pthread_cond_t *cond)
381{
382 /* should check that no threads are waiting on this CV */
383 kludged("pthread_cond_destroy");
384 return 0;
385}
sewardj6072c362002-04-19 14:40:57 +0000386
387/* ---------------------------------------------------
388 SCHEDULING
389 ------------------------------------------------ */
390
391/* This is completely bogus. */
392int pthread_getschedparam(pthread_t target_thread,
393 int *policy,
394 struct sched_param *param)
395{
sewardj30671ff2002-04-21 00:13:57 +0000396 kludged("pthread_getschedparam");
sewardj6072c362002-04-19 14:40:57 +0000397 if (policy) *policy = SCHED_OTHER;
sewardj2a1dcce2002-04-22 12:45:25 +0000398# ifdef GLIBC_2_1
399 if (param) param->sched_priority = 0; /* who knows */
400# else
sewardj6072c362002-04-19 14:40:57 +0000401 if (param) param->__sched_priority = 0; /* who knows */
sewardj2a1dcce2002-04-22 12:45:25 +0000402# endif
sewardj6072c362002-04-19 14:40:57 +0000403 return 0;
404}
405
406int pthread_setschedparam(pthread_t target_thread,
407 int policy,
408 const struct sched_param *param)
409{
410 ignored("pthread_setschedparam");
411 return 0;
412}
413
sewardj3b5d8862002-04-20 13:53:23 +0000414int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
415{
416 int res;
417 ensure_valgrind("pthread_cond_wait");
418 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
419 VG_USERREQ__PTHREAD_COND_WAIT,
420 cond, mutex, 0, 0);
421 return res;
422}
423
424int pthread_cond_signal(pthread_cond_t *cond)
425{
426 int res;
427 ensure_valgrind("pthread_cond_signal");
428 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
429 VG_USERREQ__PTHREAD_COND_SIGNAL,
430 cond, 0, 0, 0);
431 return res;
432}
433
434int pthread_cond_broadcast(pthread_cond_t *cond)
435{
436 int res;
437 ensure_valgrind("pthread_cond_broadcast");
438 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
439 VG_USERREQ__PTHREAD_COND_BROADCAST,
440 cond, 0, 0, 0);
441 return res;
442}
443
sewardj6072c362002-04-19 14:40:57 +0000444
445/* ---------------------------------------------------
sewardjf8f819e2002-04-17 23:21:37 +0000446 CANCELLATION
447 ------------------------------------------------ */
448
sewardje663cb92002-04-12 10:26:32 +0000449int pthread_setcanceltype(int type, int *oldtype)
450{
sewardj2a3d28c2002-04-14 13:27:00 +0000451 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000452 return 0;
453}
454
455
456int pthread_cancel(pthread_t thread)
457{
458 int res;
459 ensure_valgrind("pthread_cancel");
460 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
461 VG_USERREQ__PTHREAD_CANCEL,
462 thread, 0, 0, 0);
463 return res;
464}
465
466
sewardjf8f819e2002-04-17 23:21:37 +0000467/* ---------------------------------------------------
468 THREAD-SPECIFICs
469 ------------------------------------------------ */
sewardj5e5fa512002-04-14 13:13:05 +0000470
471int pthread_key_create(pthread_key_t *key,
472 void (*destr_function) (void *))
473{
sewardj2a3d28c2002-04-14 13:27:00 +0000474 ignored("pthread_key_create");
sewardj5e5fa512002-04-14 13:13:05 +0000475 return 0;
476}
477
478int pthread_key_delete(pthread_key_t key)
479{
sewardj2a3d28c2002-04-14 13:27:00 +0000480 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000481 return 0;
482}
483
484int pthread_setspecific(pthread_key_t key, const void *pointer)
485{
sewardj2a3d28c2002-04-14 13:27:00 +0000486 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000487 return 0;
488}
489
490void * pthread_getspecific(pthread_key_t key)
491{
sewardj2a3d28c2002-04-14 13:27:00 +0000492 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000493 return NULL;
494}
495
sewardjf8f819e2002-04-17 23:21:37 +0000496
497/* ---------------------------------------------------
498 MISC
499 ------------------------------------------------ */
500
501/* What are these? Anybody know? I don't. */
502
503void _pthread_cleanup_push_defer ( void )
504{
505 // char* str = "_pthread_cleanup_push_defer\n";
506 // write(2, str, strlen(str));
507}
508
509void _pthread_cleanup_pop_restore ( void )
510{
511 // char* str = "_pthread_cleanup_pop_restore\n";
512 // write(2, str, strlen(str));
513}
514
515
516pthread_t pthread_self(void)
517{
518 int tid;
519 ensure_valgrind("pthread_self");
520 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
521 VG_USERREQ__PTHREAD_GET_THREADID,
522 0, 0, 0, 0);
523 if (tid < 0 || tid >= VG_N_THREADS)
524 barf("pthread_self: invalid ThreadId");
525 return tid;
526}
527
528
sewardje663cb92002-04-12 10:26:32 +0000529/* ---------------------------------------------------------------------
530 These are here (I think) because they are deemed cancellation
531 points by POSIX. For the moment we'll simply pass the call along
532 to the corresponding thread-unaware (?) libc routine.
533 ------------------------------------------------------------------ */
534
sewardje663cb92002-04-12 10:26:32 +0000535#include <stdlib.h>
536#include <signal.h>
sewardje663cb92002-04-12 10:26:32 +0000537#include <sys/types.h>
538#include <sys/socket.h>
539
540extern
541int __libc_sigaction
542 (int signum,
543 const struct sigaction *act,
544 struct sigaction *oldact);
545int sigaction(int signum,
546 const struct sigaction *act,
547 struct sigaction *oldact)
548{
sewardj2a1dcce2002-04-22 12:45:25 +0000549# ifdef GLIBC_2_1
550 return __sigaction(signum, act, oldact);
551# else
sewardj45b4b372002-04-16 22:50:32 +0000552 return __libc_sigaction(signum, act, oldact);
sewardj2a1dcce2002-04-22 12:45:25 +0000553# endif
sewardje663cb92002-04-12 10:26:32 +0000554}
555
556
557extern
558int __libc_connect(int sockfd,
559 const struct sockaddr *serv_addr,
560 socklen_t addrlen);
561int connect(int sockfd,
562 const struct sockaddr *serv_addr,
563 socklen_t addrlen)
564{
sewardj45b4b372002-04-16 22:50:32 +0000565 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000566}
567
568
569extern
570int __libc_fcntl(int fd, int cmd, long arg);
571int fcntl(int fd, int cmd, long arg)
572{
sewardj45b4b372002-04-16 22:50:32 +0000573 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000574}
575
576
577extern
578ssize_t __libc_write(int fd, const void *buf, size_t count);
579ssize_t write(int fd, const void *buf, size_t count)
580{
sewardj45b4b372002-04-16 22:50:32 +0000581 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000582}
583
584
585extern
586ssize_t __libc_read(int fd, void *buf, size_t count);
587ssize_t read(int fd, void *buf, size_t count)
588{
sewardj45b4b372002-04-16 22:50:32 +0000589 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000590}
591
592
593extern
594int __libc_open(const char *pathname, int flags);
595int open(const char *pathname, int flags)
596{
sewardj45b4b372002-04-16 22:50:32 +0000597 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000598}
599
600
601extern
602int __libc_close(int fd);
603int close(int fd)
604{
sewardj45b4b372002-04-16 22:50:32 +0000605 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000606}
607
608
609extern
610int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
611int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
612{
sewardj45b4b372002-04-16 22:50:32 +0000613 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000614}
615
616
617extern
618pid_t __libc_fork(void);
619pid_t fork(void)
620{
sewardj45b4b372002-04-16 22:50:32 +0000621 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000622}
623
624
625extern
626pid_t __libc_waitpid(pid_t pid, int *status, int options);
627pid_t waitpid(pid_t pid, int *status, int options)
628{
sewardj45b4b372002-04-16 22:50:32 +0000629 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000630}
631
632
633extern
634int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
635int nanosleep(const struct timespec *req, struct timespec *rem)
636{
637 return __libc_nanosleep(req, rem);
638}
639
640extern
641int __libc_fsync(int fd);
642int fsync(int fd)
643{
sewardj45b4b372002-04-16 22:50:32 +0000644 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000645}
646
sewardj70c75362002-04-13 04:18:32 +0000647extern
648off_t __libc_lseek(int fildes, off_t offset, int whence);
649off_t lseek(int fildes, off_t offset, int whence)
650{
sewardj45b4b372002-04-16 22:50:32 +0000651 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000652}
653
sewardj6af4b5d2002-04-16 04:40:49 +0000654extern
655void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
656void longjmp(jmp_buf env, int val)
657{
658 __libc_longjmp(env, val);
659}
660
661extern
662int __libc_send(int s, const void *msg, size_t len, int flags);
663int send(int s, const void *msg, size_t len, int flags)
664{
665 return __libc_send(s, msg, len, flags);
666}
667
sewardj1e8cdc92002-04-18 11:37:52 +0000668extern
669int __libc_recv(int s, void *buf, size_t len, int flags);
670int recv(int s, void *buf, size_t len, int flags)
671{
672 return __libc_recv(s, buf, len, flags);
673}
674
sewardj45b4b372002-04-16 22:50:32 +0000675
sewardj70c75362002-04-13 04:18:32 +0000676/*--------------------------------------------------*/
677
sewardje663cb92002-04-12 10:26:32 +0000678/* I've no idea what these are, but they get called quite a lot.
679 Anybody know? */
680
681#undef _IO_flockfile
682void _IO_flockfile ( _IO_FILE * file )
683{
684 // char* str = "_IO_flockfile\n";
685 // write(2, str, strlen(str));
686 // barf("_IO_flockfile");
687}
688
689#undef _IO_funlockfile
690void _IO_funlockfile ( _IO_FILE * file )
691{
692 // char* str = "_IO_funlockfile\n";
693 // write(2, str, strlen(str));
694 //barf("_IO_funlockfile");
695}
696
sewardj08a4c3f2002-04-13 03:45:44 +0000697/*--------------------------------------------------*/
698
699#include "vg_kerneliface.h"
700
701static
702__inline__
703int is_kerror ( int res )
704{
705 if (res >= -4095 && res <= -1)
706 return 1;
707 else
708 return 0;
709}
710
711
712static
713int my_do_syscall1 ( int syscallno, int arg1 )
714{
715 int __res;
716 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
717 : "=a" (__res)
718 : "0" (syscallno),
719 "d" (arg1) );
720 return __res;
721}
722
723static
724int my_do_syscall2 ( int syscallno,
sewardjf854f472002-04-21 12:19:41 +0000725 int arg1, int arg2 )
sewardj08a4c3f2002-04-13 03:45:44 +0000726{
727 int __res;
728 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
729 : "=a" (__res)
730 : "0" (syscallno),
731 "d" (arg1),
732 "c" (arg2) );
733 return __res;
734}
735
736static
sewardjf854f472002-04-21 12:19:41 +0000737int my_do_syscall3 ( int syscallno,
738 int arg1, int arg2, int arg3 )
739{
740 int __res;
741 __asm__ volatile ("pushl %%ebx; movl %%esi,%%ebx ; int $0x80 ; popl %%ebx"
742 : "=a" (__res)
743 : "0" (syscallno),
744 "S" (arg1),
745 "c" (arg2),
746 "d" (arg3) );
747 return __res;
748}
749
750static
sewardj08a4c3f2002-04-13 03:45:44 +0000751int do_syscall_select( int n,
752 vki_fd_set* readfds,
753 vki_fd_set* writefds,
754 vki_fd_set* exceptfds,
755 struct vki_timeval * timeout )
756{
757 int res;
758 int args[5];
759 args[0] = n;
760 args[1] = (int)readfds;
761 args[2] = (int)writefds;
762 args[3] = (int)exceptfds;
763 args[4] = (int)timeout;
764 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
sewardj02535bc2002-04-21 01:08:26 +0000765 return res;
sewardj08a4c3f2002-04-13 03:45:44 +0000766}
767
768
769/* This is a wrapper round select(), which makes it thread-safe,
770 meaning that only this thread will block, rather than the entire
771 process. This wrapper in turn depends on nanosleep() not to block
772 the entire process, but I think (hope? suspect?) that POSIX
773 pthreads guarantees that to be the case.
774
775 Basic idea is: modify the timeout parameter to select so that it
776 returns immediately. Poll like this until select returns non-zero,
777 indicating something interesting happened, or until our time is up.
778 Space out the polls with nanosleeps of say 20 milliseconds, which
779 is required to be nonblocking; this allows other threads to run.
sewardj02535bc2002-04-21 01:08:26 +0000780
781 Assumes:
782 * (checked via assert) types fd_set and vki_fd_set are identical.
783 * (checked via assert) types timeval and vki_timeval are identical.
784 * (unchecked) libc error numbers (EINTR etc) are the negation of the
785 kernel's error numbers (VKI_EINTR etc).
sewardj08a4c3f2002-04-13 03:45:44 +0000786*/
787#include <assert.h>
788
789
790int select ( int n,
791 fd_set *rfds,
792 fd_set *wfds,
793 fd_set *xfds,
794 struct timeval *timeout )
795{
796 int res;
797 fd_set rfds_copy;
798 fd_set wfds_copy;
799 fd_set xfds_copy;
800 struct vki_timeval t_now;
801 struct vki_timeval t_end;
802 struct vki_timeval zero_timeout;
803 struct vki_timespec nanosleep_interval;
804
805 ensure_valgrind("select");
806
807 /* We assume that the kernel and libc data layouts are identical
808 for the following types. These asserts provide a crude
809 check. */
810 if (sizeof(fd_set) != sizeof(vki_fd_set)
811 || sizeof(struct timeval) != sizeof(struct vki_timeval))
812 barf("valgrind's hacky non-blocking select(): data sizes error");
813
814 /* If a zero timeout specified, this call is harmless. */
sewardj02535bc2002-04-21 01:08:26 +0000815 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
816 res = do_syscall_select( n, (vki_fd_set*)rfds,
sewardj08a4c3f2002-04-13 03:45:44 +0000817 (vki_fd_set*)wfds,
818 (vki_fd_set*)xfds,
819 (struct vki_timeval*)timeout);
sewardj02535bc2002-04-21 01:08:26 +0000820 if (is_kerror(res)) {
821 * (__errno_location()) = -res;
822 return -1;
823 } else {
824 return res;
825 }
826 }
sewardj08a4c3f2002-04-13 03:45:44 +0000827
828 /* If a timeout was specified, set t_end to be the end wallclock
829 time. */
830 if (timeout) {
831 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
832 assert(res == 0);
833 t_end = t_now;
834 t_end.tv_usec += timeout->tv_usec;
835 t_end.tv_sec += timeout->tv_sec;
836 if (t_end.tv_usec >= 1000000) {
837 t_end.tv_usec -= 1000000;
838 t_end.tv_sec += 1;
839 }
840 /* Stay sane ... */
841 assert (t_end.tv_sec > t_now.tv_sec
842 || (t_end.tv_sec == t_now.tv_sec
843 && t_end.tv_usec >= t_now.tv_usec));
844 }
845
846 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
847
848 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
849 NULL, in which case t_end holds the end time. */
850 while (1) {
851 if (timeout) {
852 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
853 assert(res == 0);
854 if (t_now.tv_sec > t_end.tv_sec
855 || (t_now.tv_sec == t_end.tv_sec
856 && t_now.tv_usec > t_end.tv_usec)) {
857 /* timeout; nothing interesting happened. */
858 if (rfds) FD_ZERO(rfds);
859 if (wfds) FD_ZERO(wfds);
860 if (xfds) FD_ZERO(xfds);
861 return 0;
862 }
863 }
864
865 /* These could be trashed each time round the loop, so restore
866 them each time. */
867 if (rfds) rfds_copy = *rfds;
868 if (wfds) wfds_copy = *wfds;
869 if (xfds) xfds_copy = *xfds;
870
871 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
872
873 res = do_syscall_select( n,
874 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
875 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
876 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
877 & zero_timeout );
sewardj02535bc2002-04-21 01:08:26 +0000878 if (is_kerror(res)) {
879 /* Some kind of error (including EINTR). Set errno and
sewardj08a4c3f2002-04-13 03:45:44 +0000880 return. The sets are unspecified in this case. */
sewardj02535bc2002-04-21 01:08:26 +0000881 * (__errno_location()) = -res;
882 return -1;
sewardj08a4c3f2002-04-13 03:45:44 +0000883 }
884 if (res > 0) {
885 /* one or more fds is ready. Copy out resulting sets and
886 return. */
887 if (rfds) *rfds = rfds_copy;
888 if (wfds) *wfds = wfds_copy;
889 if (xfds) *xfds = xfds_copy;
890 return res;
891 }
892 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
893 /* nanosleep and go round again */
sewardj02535bc2002-04-21 01:08:26 +0000894 nanosleep_interval.tv_sec = 0;
sewardjf854f472002-04-21 12:19:41 +0000895 nanosleep_interval.tv_nsec = 75 * 1000 * 1000; /* 75 milliseconds */
896 /* It's critical here that valgrind's nanosleep implementation
897 is nonblocking. */
898 (void)my_do_syscall2(__NR_nanosleep,
899 (int)(&nanosleep_interval), (int)NULL);
900 }
901}
902
903
904
905
906#include <sys/poll.h>
907
908int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
909{
910 int res, i;
911 struct vki_timeval t_now;
912 struct vki_timeval t_end;
913 struct vki_timespec nanosleep_interval;
914
915 ensure_valgrind("poll");
916
917 if (/* CHECK SIZES FOR struct pollfd */
918 sizeof(struct timeval) != sizeof(struct vki_timeval))
919 barf("valgrind's hacky non-blocking poll(): data sizes error");
920
921 /* If a zero timeout specified, this call is harmless. */
922 if (__timeout == 0) {
923 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, __timeout);
924 if (is_kerror(res)) {
925 * (__errno_location()) = -res;
926 return -1;
927 } else {
928 return res;
929 }
930 }
931
932 /* If a timeout was specified, set t_end to be the end wallclock
933 time. */
934 if (__timeout > 0) {
935 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
936 assert(res == 0);
937 t_end = t_now;
938 t_end.tv_usec += 1000 * (__timeout % 1000);
939 t_end.tv_sec += (__timeout / 1000);
940 if (t_end.tv_usec >= 1000000) {
941 t_end.tv_usec -= 1000000;
942 t_end.tv_sec += 1;
943 }
944 /* Stay sane ... */
945 assert (t_end.tv_sec > t_now.tv_sec
946 || (t_end.tv_sec == t_now.tv_sec
947 && t_end.tv_usec >= t_now.tv_usec));
948 }
949
950 /* fprintf(stderr, "MY_POLL: before loop\n"); */
951
952 /* Either timeout < 0, meaning wait indefinitely, or timeout > 0,
953 in which case t_end holds the end time. */
954 while (1) {
955 assert(__timeout != 0);
956 if (__timeout > 0) {
957 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
958 assert(res == 0);
959 if (t_now.tv_sec > t_end.tv_sec
960 || (t_now.tv_sec == t_end.tv_sec
961 && t_now.tv_usec > t_end.tv_usec)) {
962 /* timeout; nothing interesting happened. */
963 for (i = 0; i < __nfds; i++)
964 __fds[i].revents = 0;
965 return 0;
966 }
967 }
968
969 /* These could be trashed each time round the loop, so restore
970 them each time. */
971 res = my_do_syscall3(__NR_poll, (int)__fds, __nfds, 0 );
972 if (is_kerror(res)) {
973 /* Some kind of error. Set errno and return. */
974 * (__errno_location()) = -res;
975 return -1;
976 }
977 if (res > 0) {
978 /* One or more fds is ready. Return now. */
979 return res;
980 }
981 /* fprintf(stderr, "MY_POLL: nanosleep\n"); */
982 /* nanosleep and go round again */
983 nanosleep_interval.tv_sec = 0;
984 nanosleep_interval.tv_nsec = 100 * 1000 * 1000; /* 100 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +0000985 /* It's critical here that valgrind's nanosleep implementation
986 is nonblocking. */
987 (void)my_do_syscall2(__NR_nanosleep,
988 (int)(&nanosleep_interval), (int)NULL);
989 }
990}