blob: 8541f6cd8bce85ef859410855f5a349c4b5e88d5 [file] [log] [blame]
/* -*- Mode: C; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
#include "util.h"
/* This test spawns a ptracer and a ptracee, where the ptracee has 10
sub-threads.
The pracer attaches to all the ptracee's threads, then exits.
We check that all ptracee threads are resumed. */
static int status_pipe[2];
static int tid_pipe[2];
static int ready_pipe[2];
static int thread_wait_pipe[2];
static void write_tid(void) {
pid_t tid = sys_gettid();
test_assert(sizeof(tid) == write(tid_pipe[1], &tid, sizeof(tid)));
}
static pid_t read_tid(void) {
pid_t tid;
test_assert(sizeof(tid) == read(tid_pipe[0], &tid, sizeof(tid)));
return tid;
}
static void* child_thread(__attribute__((unused)) void* p) {
char ch = 0;
write_tid();
test_assert(1 == read(thread_wait_pipe[0], &ch, 1));
test_assert('W' == ch);
return NULL;
}
static int child_runner(void) {
char ch = 0;
pthread_t threads[10];
int i;
write_tid();
for (i = 0; i < 10; ++i) {
pthread_create(&threads[i], NULL, child_thread, NULL);
}
atomic_printf("Waiting on ready_pipe\n");
test_assert(1 == read(ready_pipe[0], &ch, 1));
test_assert(ch == 'R');
for (i = 0; i < 10; ++i) {
char ch2 = 'W';
test_assert(1 == write(thread_wait_pipe[1], &ch2, 1));
}
for (i = 0; i < 10; ++i) {
atomic_printf("Joining thread %d\n", i);
pthread_join(threads[i], NULL);
}
char ok = 'K';
test_assert(1 == write(status_pipe[1], &ok, 1));
return 77;
}
static int ptracer(void) {
pid_t child;
int status;
char ready = 'R';
int i;
pid_t child_tids[11];
if (0 == (child = fork())) {
return child_runner();
}
for (i = 0; i < 11; ++i) {
child_tids[i] = read_tid();
}
for (i = 0; i < 11; ++i) {
int ret;
test_assert(0 == ptrace(PTRACE_ATTACH, child_tids[i], NULL, NULL));
ret = waitpid(child_tids[i], &status, __WALL);
atomic_printf("waitpid on %d gives %d with errno=%d\n", child_tids[i], ret,
errno);
test_assert(ret == child_tids[i]);
test_assert(status == ((SIGSTOP << 8) | 0x7f));
}
test_assert(1 == write(ready_pipe[1], &ready, 1));
/* Now just exit, and all child threads should resume */
return 44;
}
int main(void) {
char ch = 0;
pid_t ptracer_pid;
int status;
test_assert(0 == pipe(ready_pipe));
test_assert(0 == pipe(tid_pipe));
test_assert(0 == pipe(status_pipe));
test_assert(0 == pipe(thread_wait_pipe));
if (0 == (ptracer_pid = fork())) {
return ptracer();
}
test_assert(ptracer_pid == waitpid(ptracer_pid, &status, 0));
test_assert(WIFEXITED(status) && WEXITSTATUS(status) == 44);
test_assert(1 == read(status_pipe[0], &ch, 1));
test_assert(ch == 'K');
atomic_puts("EXIT-SUCCESS");
return 0;
}