test/threaded_execve: make it also test a case when leader is not in syscall
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/test/threaded_execve.c b/test/threaded_execve.c
index 9cf3dae..628589a 100644
--- a/test/threaded_execve.c
+++ b/test/threaded_execve.c
@@ -10,24 +10,24 @@
*
* # Should not be confused by traced execve-ing thread
* # replacing traced leader:
- * [LEADER_EXIT=1] strace -oLOG -f ./threaded_execve
+ * strace -oLOG -f ./threaded_execve
*
* # Same, but different output mode. Output after execve
* # should go into leader's LOG.<pid> file, not into execve'ed
* # thread's log file:
- * [LEADER_EXIT=1] strace -oLOG -ff ./threaded_execve
+ * strace -oLOG -ff ./threaded_execve
*
* # Should not be confused by non-traced execve-ing thread
* # replacing traced leader:
- * [LEADER_EXIT=1] strace -oLOG ./threaded_execve
- * ^^^^^^^^^^^^^^^^^^^^^
+ * strace -oLOG ./threaded_execve
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* In Linux 3.2, non-traced execve-ing thread does not
* become traced after execve, even though it has pid == leader's pid
* after execve. And yet, strace's waitpid doesn't return ECHILD.
*
* # Run for NUM seconds, not just one second.
* # Watch top to check for memory leaks in strace:
- * [LEADER_EXIT=1] strace -oLOG -f ./threaded_execve <NUM>
+ * strace -oLOG -f ./threaded_execve <NUM>
*
*/
#define NUM_THREADS 1
@@ -65,6 +65,7 @@
#define syscall_exit(v) syscall(__NR_exit, (v));
static char my_name[PATH_MAX];
+static int leader_final_action;
static int
thread1(void *unused)
@@ -77,18 +78,20 @@
static int
thread2(void *unused)
{
+ char buf[64];
+ sprintf(buf, "%d", leader_final_action);
write(1, "2", 1);
usleep(20*1000);
/* This fails with ENOENT if leader has exited by now! :) */
- execl("/proc/self/exe", "exe", "exe", NULL);
+ execl("/proc/self/exe", "exe", "exe", buf, NULL);
/* So fall back to resolved name */
- execl(my_name, "exe", "exe", NULL);
+ execl(my_name, "exe", "exe", buf, NULL);
for(;;) pause();
return 0;
}
static void
-thread_leader(int die)
+thread_leader(void)
{
/* malloc gives sufficiently aligned buffer.
* long buf[] does not! (on ia64).
@@ -111,27 +114,31 @@
| 0 /* no signal to send on death */
, NULL);
- if (die) syscall_exit(42);
- for(;;) pause();
+ /* Various states leader can be while other thread execve's: */
+ switch (leader_final_action % 3) {
+ case 0: syscall_exit(42); /* leader is dead */
+ case 1: for(;;) pause(); /* leader is in syscall */
+ default: for(;;) continue; /* leader is in userspace */
+ }
}
int
main(int argc, char **argv)
{
- int die = getenv("LEADER_EXIT") != NULL;
-
if (readlink("/proc/self/exe", my_name, sizeof(my_name)-1) <= 0)
return 1;
setbuf(stdout, NULL);
- if (argv[1] && strcmp(argv[1], "exe") == 0)
- thread_leader(die);
+ if (argv[1] && strcmp(argv[1], "exe") == 0) {
+ leader_final_action = atoi(argv[2]) + 1;
+ thread_leader();
+ }
printf("%d: thread leader\n", getpid());
alarm(argv[1] ? atoi(argv[1]) : 1);
- thread_leader(die);
+ thread_leader();
return 0;
}