blob: 11f5200a0d2e01821e2592d54b24c6c4732696e5 [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
26#include <pthread.h>
27#include <unistd.h>
28#include <string.h>
29
30
31/* ---------------------------------------------------------------------
32 Helpers. We have to be pretty self-sufficient.
33 ------------------------------------------------------------------ */
34
sewardj45b4b372002-04-16 22:50:32 +000035/* Extract from Valgrind the value of VG_(clo_trace_pthread_level).
36 Returns 0 (none) if not running on Valgrind. */
37static
38int get_pt_trace_level ( void )
39{
40 int res;
41 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
42 VG_USERREQ__GET_PTHREAD_TRACE_LEVEL,
43 0, 0, 0, 0);
44 return res;
45}
46
47
48
sewardje663cb92002-04-12 10:26:32 +000049static
50void myexit ( int arg )
51{
sewardj45b4b372002-04-16 22:50:32 +000052 int __res;
sewardje663cb92002-04-12 10:26:32 +000053 __asm__ volatile ("movl %%ecx, %%ebx ; int $0x80"
54 : "=a" (__res)
55 : "0" (__NR_exit),
56 "c" (arg) );
sewardj45b4b372002-04-16 22:50:32 +000057 /* We don't bother to mention the fact that this asm trashes %ebx,
58 since it won't return. If you ever do let it return ... fix
59 this! */
sewardje663cb92002-04-12 10:26:32 +000060}
61
62
63/* Give up without using printf etc, since they seem to give
64 segfaults. */
65static
66void ensure_valgrind ( char* caller )
67{
68 char* str;
69 int is_valgrind = RUNNING_ON_VALGRIND;
70 if (!is_valgrind) {
71 str = "\nvalgrind-ed process: vg_libpthread.so: "
72 "pthread call when\n";
73 write(2, str, strlen(str));
74 str = "not running on valgrind; aborting! "
75 "This is probably a bug in\n";
76 write(2, str, strlen(str));
77 str = "valgrind. Please report it to me at: "
78 "jseward@acm.org. Thanks.\n";
79 write(2, str, strlen(str));
80 str = "unexpectedly called function is: ";
81 write(2, str, strlen(str));
82 write(2, caller, strlen(caller));
83 str = "\n\n";
84 write(2, str, strlen(str));
85 myexit(1);
86 }
87}
88
89
90static
91void barf ( char* str )
92{
93 char buf[100];
94 buf[0] = 0;
95 strcat(buf, "\nvg_libpthread.so: ");
96 strcat(buf, str);
97 strcat(buf, "\n\n");
98 write(2, buf, strlen(buf));
99 myexit(1);
100}
101
102
sewardj2a3d28c2002-04-14 13:27:00 +0000103static void ignored ( char* msg )
104{
sewardj45b4b372002-04-16 22:50:32 +0000105 if (get_pt_trace_level() >= 1) {
106 char* ig = "vg_libpthread.so: IGNORED call to: ";
107 write(2, ig, strlen(ig));
108 write(2, msg, strlen(msg));
109 ig = "\n";
110 write(2, ig, strlen(ig));
111 }
sewardj2a3d28c2002-04-14 13:27:00 +0000112}
113
sewardje663cb92002-04-12 10:26:32 +0000114
115/* ---------------------------------------------------------------------
116 Pass pthread_ calls to Valgrind's request mechanism.
117 ------------------------------------------------------------------ */
118
sewardj6af4b5d2002-04-16 04:40:49 +0000119int pthread_attr_init(pthread_attr_t *attr)
120{
121 ignored("pthread_attr_init");
122 return 0;
123}
124
125int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
126{
127 ignored("pthread_attr_setdetachstate");
128 return 0;
129}
130
131
sewardje663cb92002-04-12 10:26:32 +0000132int
133pthread_create (pthread_t *__restrict __thread,
134 __const pthread_attr_t *__restrict __attr,
135 void *(*__start_routine) (void *),
136 void *__restrict __arg)
137{
138 int res;
139 ensure_valgrind("pthread_create");
140 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
141 VG_USERREQ__PTHREAD_CREATE,
142 __thread, __attr, __start_routine, __arg);
143 return res;
144}
145
146
147
148int
149pthread_join (pthread_t __th, void **__thread_return)
150{
151 int res;
152 ensure_valgrind("pthread_join");
153 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
154 VG_USERREQ__PTHREAD_JOIN,
155 __th, __thread_return, 0, 0);
156 return res;
157}
158
159
160/* What are these? Anybody know? I don't. */
161
162void _pthread_cleanup_push_defer ( void )
163{
164 // char* str = "_pthread_cleanup_push_defer\n";
165 // write(2, str, strlen(str));
166}
167
168void _pthread_cleanup_pop_restore ( void )
169{
170 // char* str = "_pthread_cleanup_pop_restore\n";
171 // write(2, str, strlen(str));
172}
173
174
175static int thread_specific_errno[VG_N_THREADS];
176
177int* __errno_location ( void )
178{
179 int tid;
180 ensure_valgrind("__errno_location");
181 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
182 VG_USERREQ__PTHREAD_GET_THREADID,
183 0, 0, 0, 0);
184 /* 'cos I'm paranoid ... */
185 if (tid < 0 || tid >= VG_N_THREADS)
186 barf("__errno_location: invalid ThreadId");
187 return & thread_specific_errno[tid];
188}
189
190
191int pthread_mutexattr_init(pthread_mutexattr_t *attr)
192{
sewardj2a3d28c2002-04-14 13:27:00 +0000193 ignored("pthread_mutexattr_init");
sewardj8937c812002-04-12 20:12:20 +0000194 return 0;
sewardje663cb92002-04-12 10:26:32 +0000195}
196
197int pthread_mutex_init(pthread_mutex_t *mutex,
198 const pthread_mutexattr_t *mutexattr)
199{
200 int res;
sewardje663cb92002-04-12 10:26:32 +0000201 ensure_valgrind("pthread_mutex_init");
202 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
203 VG_USERREQ__PTHREAD_MUTEX_INIT,
204 mutex, mutexattr, 0, 0);
205 return res;
206}
207
208int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
209{
sewardj6af4b5d2002-04-16 04:40:49 +0000210 ignored("pthread_mutexattr_destroy");
211 return 0;
212}
213
214int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
215{
216 ignored("pthread_mutexattr_settype");
217 return 0;
sewardje663cb92002-04-12 10:26:32 +0000218}
219
220int pthread_mutex_lock(pthread_mutex_t *mutex)
221{
222 int res;
sewardj45b4b372002-04-16 22:50:32 +0000223 static int moans = 5;
224 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000225 char* str = "pthread_mutex_lock-NOT-INSIDE-VALGRIND\n";
226 write(2, str, strlen(str));
227 return 0;
228 } else {
229 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
230 VG_USERREQ__PTHREAD_MUTEX_LOCK,
231 mutex, 0, 0, 0);
232 return res;
233 }
234}
235
236int pthread_mutex_unlock(pthread_mutex_t *mutex)
237{
238 int res;
sewardj45b4b372002-04-16 22:50:32 +0000239 static int moans = 5;
240 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000241 char* str = "pthread_mutex_unlock-NOT-INSIDE-VALGRIND\n";
242 write(2, str, strlen(str));
243 return 0;
244 } else {
245 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
246 VG_USERREQ__PTHREAD_MUTEX_UNLOCK,
247 mutex, 0, 0, 0);
248 return res;
249 }
250}
251
252pthread_t pthread_self(void)
253{
254 int tid;
255 ensure_valgrind("pthread_self");
256 VALGRIND_MAGIC_SEQUENCE(tid, 0 /* default */,
257 VG_USERREQ__PTHREAD_GET_THREADID,
258 0, 0, 0, 0);
259 if (tid < 0 || tid >= VG_N_THREADS)
260 barf("pthread_self: invalid ThreadId");
261 return tid;
262}
263
264int pthread_mutex_destroy(pthread_mutex_t *mutex)
265{
266 int res;
sewardj45b4b372002-04-16 22:50:32 +0000267 static int moans = 5;
268 if (!(RUNNING_ON_VALGRIND) && moans-- > 0) {
sewardje663cb92002-04-12 10:26:32 +0000269 char* str = "pthread_mutex_destroy-NOT-INSIDE-VALGRIND\n";
270 write(2, str, strlen(str));
271 return 0;
272 } else {
273 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
274 VG_USERREQ__PTHREAD_MUTEX_DESTROY,
275 mutex, 0, 0, 0);
276 }
277 return res;
278}
279
280
281int pthread_setcanceltype(int type, int *oldtype)
282{
sewardj2a3d28c2002-04-14 13:27:00 +0000283 ignored("pthread_setcanceltype");
sewardje663cb92002-04-12 10:26:32 +0000284 return 0;
285}
286
287
288int pthread_cancel(pthread_t thread)
289{
290 int res;
291 ensure_valgrind("pthread_cancel");
292 VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
293 VG_USERREQ__PTHREAD_CANCEL,
294 thread, 0, 0, 0);
295 return res;
296}
297
298
sewardj5e5fa512002-04-14 13:13:05 +0000299
300int pthread_key_create(pthread_key_t *key,
301 void (*destr_function) (void *))
302{
sewardj2a3d28c2002-04-14 13:27:00 +0000303 ignored("pthread_key_create");
sewardj5e5fa512002-04-14 13:13:05 +0000304 return 0;
305}
306
307int pthread_key_delete(pthread_key_t key)
308{
sewardj2a3d28c2002-04-14 13:27:00 +0000309 ignored("pthread_key_delete");
sewardj5e5fa512002-04-14 13:13:05 +0000310 return 0;
311}
312
313int pthread_setspecific(pthread_key_t key, const void *pointer)
314{
sewardj2a3d28c2002-04-14 13:27:00 +0000315 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000316 return 0;
317}
318
319void * pthread_getspecific(pthread_key_t key)
320{
sewardj2a3d28c2002-04-14 13:27:00 +0000321 ignored("pthread_setspecific");
sewardj5e5fa512002-04-14 13:13:05 +0000322 return NULL;
323}
324
sewardje663cb92002-04-12 10:26:32 +0000325/* ---------------------------------------------------------------------
326 These are here (I think) because they are deemed cancellation
327 points by POSIX. For the moment we'll simply pass the call along
328 to the corresponding thread-unaware (?) libc routine.
329 ------------------------------------------------------------------ */
330
331#include <stdio.h>
332#include <stdlib.h>
333#include <signal.h>
334#include <errno.h>
335#include <sys/types.h>
336#include <sys/socket.h>
337
338extern
339int __libc_sigaction
340 (int signum,
341 const struct sigaction *act,
342 struct sigaction *oldact);
343int sigaction(int signum,
344 const struct sigaction *act,
345 struct sigaction *oldact)
346{
sewardj45b4b372002-04-16 22:50:32 +0000347 return __libc_sigaction(signum, act, oldact);
sewardje663cb92002-04-12 10:26:32 +0000348}
349
350
351extern
352int __libc_connect(int sockfd,
353 const struct sockaddr *serv_addr,
354 socklen_t addrlen);
355int connect(int sockfd,
356 const struct sockaddr *serv_addr,
357 socklen_t addrlen)
358{
sewardj45b4b372002-04-16 22:50:32 +0000359 return __libc_connect(sockfd, serv_addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000360}
361
362
363extern
364int __libc_fcntl(int fd, int cmd, long arg);
365int fcntl(int fd, int cmd, long arg)
366{
sewardj45b4b372002-04-16 22:50:32 +0000367 return __libc_fcntl(fd, cmd, arg);
sewardje663cb92002-04-12 10:26:32 +0000368}
369
370
371extern
372ssize_t __libc_write(int fd, const void *buf, size_t count);
373ssize_t write(int fd, const void *buf, size_t count)
374{
sewardj45b4b372002-04-16 22:50:32 +0000375 return __libc_write(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000376}
377
378
379extern
380ssize_t __libc_read(int fd, void *buf, size_t count);
381ssize_t read(int fd, void *buf, size_t count)
382{
sewardj45b4b372002-04-16 22:50:32 +0000383 return __libc_read(fd, buf, count);
sewardje663cb92002-04-12 10:26:32 +0000384}
385
386
387extern
388int __libc_open(const char *pathname, int flags);
389int open(const char *pathname, int flags)
390{
sewardj45b4b372002-04-16 22:50:32 +0000391 return __libc_open(pathname, flags);
sewardje663cb92002-04-12 10:26:32 +0000392}
393
394
395extern
396int __libc_close(int fd);
397int close(int fd)
398{
sewardj45b4b372002-04-16 22:50:32 +0000399 return __libc_close(fd);
sewardje663cb92002-04-12 10:26:32 +0000400}
401
402
403extern
404int __libc_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
405int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
406{
sewardj45b4b372002-04-16 22:50:32 +0000407 return __libc_accept(s, addr, addrlen);
sewardje663cb92002-04-12 10:26:32 +0000408}
409
410
411extern
412pid_t __libc_fork(void);
413pid_t fork(void)
414{
sewardj45b4b372002-04-16 22:50:32 +0000415 return __libc_fork();
sewardje663cb92002-04-12 10:26:32 +0000416}
417
418
419extern
420pid_t __libc_waitpid(pid_t pid, int *status, int options);
421pid_t waitpid(pid_t pid, int *status, int options)
422{
sewardj45b4b372002-04-16 22:50:32 +0000423 return __libc_waitpid(pid, status, options);
sewardje663cb92002-04-12 10:26:32 +0000424}
425
426
427extern
428int __libc_nanosleep(const struct timespec *req, struct timespec *rem);
429int nanosleep(const struct timespec *req, struct timespec *rem)
430{
431 return __libc_nanosleep(req, rem);
432}
433
434extern
435int __libc_fsync(int fd);
436int fsync(int fd)
437{
sewardj45b4b372002-04-16 22:50:32 +0000438 return __libc_fsync(fd);
sewardje663cb92002-04-12 10:26:32 +0000439}
440
sewardj70c75362002-04-13 04:18:32 +0000441extern
442off_t __libc_lseek(int fildes, off_t offset, int whence);
443off_t lseek(int fildes, off_t offset, int whence)
444{
sewardj45b4b372002-04-16 22:50:32 +0000445 return __libc_lseek(fildes, offset, whence);
sewardj70c75362002-04-13 04:18:32 +0000446}
447
sewardj6af4b5d2002-04-16 04:40:49 +0000448extern
449void __libc_longjmp(jmp_buf env, int val) __attribute((noreturn));
450void longjmp(jmp_buf env, int val)
451{
452 __libc_longjmp(env, val);
453}
454
455extern
456int __libc_send(int s, const void *msg, size_t len, int flags);
457int send(int s, const void *msg, size_t len, int flags)
458{
459 return __libc_send(s, msg, len, flags);
460}
461
sewardj45b4b372002-04-16 22:50:32 +0000462
sewardj70c75362002-04-13 04:18:32 +0000463/*--------------------------------------------------*/
464
sewardje663cb92002-04-12 10:26:32 +0000465/* I've no idea what these are, but they get called quite a lot.
466 Anybody know? */
467
468#undef _IO_flockfile
469void _IO_flockfile ( _IO_FILE * file )
470{
471 // char* str = "_IO_flockfile\n";
472 // write(2, str, strlen(str));
473 // barf("_IO_flockfile");
474}
475
476#undef _IO_funlockfile
477void _IO_funlockfile ( _IO_FILE * file )
478{
479 // char* str = "_IO_funlockfile\n";
480 // write(2, str, strlen(str));
481 //barf("_IO_funlockfile");
482}
483
sewardj08a4c3f2002-04-13 03:45:44 +0000484/*--------------------------------------------------*/
485
486#include "vg_kerneliface.h"
487
488static
489__inline__
490int is_kerror ( int res )
491{
492 if (res >= -4095 && res <= -1)
493 return 1;
494 else
495 return 0;
496}
497
498
499static
500int my_do_syscall1 ( int syscallno, int arg1 )
501{
502 int __res;
503 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
504 : "=a" (__res)
505 : "0" (syscallno),
506 "d" (arg1) );
507 return __res;
508}
509
510static
511int my_do_syscall2 ( int syscallno,
512 int arg1, int arg2 )
513{
514 int __res;
515 __asm__ volatile ("pushl %%ebx; movl %%edx,%%ebx ; int $0x80 ; popl %%ebx"
516 : "=a" (__res)
517 : "0" (syscallno),
518 "d" (arg1),
519 "c" (arg2) );
520 return __res;
521}
522
523static
524int do_syscall_select( int n,
525 vki_fd_set* readfds,
526 vki_fd_set* writefds,
527 vki_fd_set* exceptfds,
528 struct vki_timeval * timeout )
529{
530 int res;
531 int args[5];
532 args[0] = n;
533 args[1] = (int)readfds;
534 args[2] = (int)writefds;
535 args[3] = (int)exceptfds;
536 args[4] = (int)timeout;
537 res = my_do_syscall1(__NR_select, (int)(&(args[0])) );
538 if (is_kerror(res)) {
539 * (__errno_location()) = -res;
540 return -1;
541 } else {
542 return res;
543 }
544}
545
546
547/* This is a wrapper round select(), which makes it thread-safe,
548 meaning that only this thread will block, rather than the entire
549 process. This wrapper in turn depends on nanosleep() not to block
550 the entire process, but I think (hope? suspect?) that POSIX
551 pthreads guarantees that to be the case.
552
553 Basic idea is: modify the timeout parameter to select so that it
554 returns immediately. Poll like this until select returns non-zero,
555 indicating something interesting happened, or until our time is up.
556 Space out the polls with nanosleeps of say 20 milliseconds, which
557 is required to be nonblocking; this allows other threads to run.
558*/
559#include <assert.h>
560
561
562int select ( int n,
563 fd_set *rfds,
564 fd_set *wfds,
565 fd_set *xfds,
566 struct timeval *timeout )
567{
568 int res;
569 fd_set rfds_copy;
570 fd_set wfds_copy;
571 fd_set xfds_copy;
572 struct vki_timeval t_now;
573 struct vki_timeval t_end;
574 struct vki_timeval zero_timeout;
575 struct vki_timespec nanosleep_interval;
576
577 ensure_valgrind("select");
578
579 /* We assume that the kernel and libc data layouts are identical
580 for the following types. These asserts provide a crude
581 check. */
582 if (sizeof(fd_set) != sizeof(vki_fd_set)
583 || sizeof(struct timeval) != sizeof(struct vki_timeval))
584 barf("valgrind's hacky non-blocking select(): data sizes error");
585
586 /* If a zero timeout specified, this call is harmless. */
587 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
588 return do_syscall_select( n, (vki_fd_set*)rfds,
589 (vki_fd_set*)wfds,
590 (vki_fd_set*)xfds,
591 (struct vki_timeval*)timeout);
592
593 /* If a timeout was specified, set t_end to be the end wallclock
594 time. */
595 if (timeout) {
596 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
597 assert(res == 0);
598 t_end = t_now;
599 t_end.tv_usec += timeout->tv_usec;
600 t_end.tv_sec += timeout->tv_sec;
601 if (t_end.tv_usec >= 1000000) {
602 t_end.tv_usec -= 1000000;
603 t_end.tv_sec += 1;
604 }
605 /* Stay sane ... */
606 assert (t_end.tv_sec > t_now.tv_sec
607 || (t_end.tv_sec == t_now.tv_sec
608 && t_end.tv_usec >= t_now.tv_usec));
609 }
610
611 /* fprintf(stderr, "MY_SELECT: before loop\n"); */
612
613 /* Either timeout == NULL, meaning wait indefinitely, or timeout !=
614 NULL, in which case t_end holds the end time. */
615 while (1) {
616 if (timeout) {
617 res = my_do_syscall2(__NR_gettimeofday, (int)&t_now, (int)NULL);
618 assert(res == 0);
619 if (t_now.tv_sec > t_end.tv_sec
620 || (t_now.tv_sec == t_end.tv_sec
621 && t_now.tv_usec > t_end.tv_usec)) {
622 /* timeout; nothing interesting happened. */
623 if (rfds) FD_ZERO(rfds);
624 if (wfds) FD_ZERO(wfds);
625 if (xfds) FD_ZERO(xfds);
626 return 0;
627 }
628 }
629
630 /* These could be trashed each time round the loop, so restore
631 them each time. */
632 if (rfds) rfds_copy = *rfds;
633 if (wfds) wfds_copy = *wfds;
634 if (xfds) xfds_copy = *xfds;
635
636 zero_timeout.tv_sec = zero_timeout.tv_usec = 0;
637
638 res = do_syscall_select( n,
639 rfds ? (vki_fd_set*)(&rfds_copy) : NULL,
640 wfds ? (vki_fd_set*)(&wfds_copy) : NULL,
641 xfds ? (vki_fd_set*)(&xfds_copy) : NULL,
642 & zero_timeout );
643 if (res < 0) {
644 /* some kind of error (including EINTR); errno is set, so just
645 return. The sets are unspecified in this case. */
646 return res;
647 }
648 if (res > 0) {
649 /* one or more fds is ready. Copy out resulting sets and
650 return. */
651 if (rfds) *rfds = rfds_copy;
652 if (wfds) *wfds = wfds_copy;
653 if (xfds) *xfds = xfds_copy;
654 return res;
655 }
656 /* fprintf(stderr, "MY_SELECT: nanosleep\n"); */
657 /* nanosleep and go round again */
658 nanosleep_interval.tv_sec = 0;
sewardj45b4b372002-04-16 22:50:32 +0000659 nanosleep_interval.tv_nsec = 40 * 1000 * 1000; /* 40 milliseconds */
sewardj08a4c3f2002-04-13 03:45:44 +0000660 /* It's critical here that valgrind's nanosleep implementation
661 is nonblocking. */
662 (void)my_do_syscall2(__NR_nanosleep,
663 (int)(&nanosleep_interval), (int)NULL);
664 }
665}