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