15dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes/* 25dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * Create NUM_THREADS threads which print "1" and sleep in pause(). 35dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * Then create another thread which prints "2", and re-execs the program. 45dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * The leader then either sleeps in pause(), or exits if $LEADER_EXIT is set. 55dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * This triggers "execve'ed thread replaces thread leader" case. 65dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * 75dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * gcc -Wall -Os -o threaded_execve threaded_execve.c 85dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * 95dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * Try running it under strace like this: 105dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * 115dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * # Should not be confused by traced execve-ing thread 125dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * # replacing traced leader: 135dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * strace -oLOG -f ./threaded_execve 145dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * 155dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * # Same, but different output mode. Output after execve 165dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * # should go into leader's LOG.<pid> file, not into execve'ed 175dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * # thread's log file: 185dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * strace -oLOG -ff ./threaded_execve 195dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * 205dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * # Should not be confused by non-traced execve-ing thread 215dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * # replacing traced leader: 225dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * strace -oLOG ./threaded_execve 235dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 245dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * In Linux 3.2, non-traced execve-ing thread does not 255dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * become traced after execve, even though it has pid == leader's pid 265dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * after execve. And yet, strace's waitpid doesn't return ECHILD. 275dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * 285dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * # Run for NUM seconds, not just one second. 295dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * # Watch top to check for memory leaks in strace: 305dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * strace -oLOG -f ./threaded_execve <NUM> 315dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * 325dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes */ 335dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#define NUM_THREADS 1 345dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 355dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#define _GNU_SOURCE 1 365dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <assert.h> 375dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <limits.h> 385dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <stddef.h> 395dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <stdlib.h> 405dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <string.h> 415dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <unistd.h> 425dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <errno.h> 435dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <stdio.h> 445dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <sched.h> 455dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <signal.h> 465dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <dirent.h> 475dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <fcntl.h> 485dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <sys/types.h> 495dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <sys/wait.h> 505dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#include <sys/syscall.h> 515dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 525dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes/* Define clone2 for all arches */ 535dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#ifdef __ia64__ 545dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughesextern int __clone2(int (*fn) (void *), void *child_stack_base, 555dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes size_t stack_size, int flags, void *arg, ...); 565dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#define clone2 __clone2 575dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#elif defined(__metag__) 585dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#define clone2(func, stack_base, size, flags, arg...) \ 595dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes clone(func, stack_base, flags, arg) 605dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#else 615dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#define clone2(func, stack_base, size, flags, arg...) \ 625dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes clone(func, (stack_base) + (size), flags, arg) 635dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#endif 645dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes/* Direct calls to syscalls, avoiding libc wrappers */ 655dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#define syscall_tgkill(pid, tid, sig) syscall(__NR_tgkill, (pid), (tid), (sig)) 665dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#define syscall_getpid() syscall(__NR_getpid) 675dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#define syscall_gettid() syscall(__NR_gettid) 685dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes#define syscall_exit(v) syscall(__NR_exit, (v)); 695dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 705dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughesstatic char my_name[PATH_MAX]; 715dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughesstatic int leader_final_action; 725dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 735dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughesstatic int 745dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughesthread1(void *unused) 755dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes{ 765dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes write(1, "1", 1); 775dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes for(;;) pause(); 785dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes return 0; 795dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes} 805dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 815dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughesstatic int 825dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughesthread2(void *unused) 835dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes{ 845dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes char buf[64]; 855dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes sprintf(buf, "%d", leader_final_action); 865dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes write(1, "2", 1); 875dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes usleep(20*1000); 885dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes /* This fails with ENOENT if leader has exited by now! :) */ 895dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes execl("/proc/self/exe", "exe", "exe", buf, NULL); 905dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes /* So fall back to resolved name */ 915dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes execl(my_name, "exe", "exe", buf, NULL); 925dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes for(;;) pause(); 935dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes return 0; 945dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes} 955dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 965dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughesstatic void 975dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughesthread_leader(void) 985dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes{ 995dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes /* malloc gives sufficiently aligned buffer. 1005dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes * long buf[] does not! (on ia64). 1015dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes */ 1025dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes int cnt = NUM_THREADS; 1035dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes while (--cnt >= 0) { 1045dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes /* As seen in pthread_create(): */ 1055dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes clone2(thread1, malloc(16 * 1024), 16 * 1024, 0 1065dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes | CLONE_VM 1075dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes | CLONE_FS 1085dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM 1095dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes | 0 /* no signal to send on death */ 1105dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes , NULL); 1115dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes usleep(20*1000); 1125dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes } 1135dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes clone2(thread2, malloc(16 * 1024), 16 * 1024, 0 1145dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes | CLONE_VM 1155dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes | CLONE_FS 1165dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM 1175dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes | 0 /* no signal to send on death */ 1185dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes , NULL); 1195dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 1205dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes /* Various states leader can be while other thread execve's: */ 1215dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes switch (leader_final_action % 3) { 1225dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes case 0: syscall_exit(42); /* leader is dead */ 1235dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes case 1: for(;;) pause(); /* leader is in syscall */ 1245dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes default: for(;;) continue; /* leader is in userspace */ 1255dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes } 1265dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes} 1275dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 1285dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughesint 1295dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughesmain(int argc, char **argv) 1305dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes{ 1315dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes if (readlink("/proc/self/exe", my_name, sizeof(my_name)-1) <= 0) 1325dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes return 1; 1335dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 1345dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes setbuf(stdout, NULL); 1355dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 1365dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes if (argv[1] && strcmp(argv[1], "exe") == 0) { 1375dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes leader_final_action = atoi(argv[2]) + 1; 1385dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes thread_leader(); 1395dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes } 1405dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 1415dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes printf("%d: thread leader\n", getpid()); 1425dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 1435dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes alarm(argv[1] ? atoi(argv[1]) : 1); 1445dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes thread_leader(); 1455dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes 1465dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes return 0; 1475dec78d0c2663930cd1bbcecbbcee47f68bc52f3Elliott Hughes} 148