blob: deeeb08592ee0ef6c51da84d1e77bc202f3aac37 [file] [log] [blame]
/* -*- Mode: C; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
#include "util.h"
static void breakpoint(void) {}
static int thread_to_main_fds[2];
static int main_to_child_fds[2];
static int wait_forever_fds[2];
static char ch = 'X';
static void* run_thread(__attribute__((unused)) void* p) {
/* Lower our priority so we won't get scheduled until everything
else is blocked */
setpriority(PRIO_PROCESS, 0, 4);
test_assert(1 == write(thread_to_main_fds[1], &ch, 1));
read(wait_forever_fds[0], &ch, 1);
test_assert(0);
return NULL;
}
static int run_child(void) {
test_assert(1 == read(main_to_child_fds[0], &ch, 1));
/* At this point, the parent's main thread should have exit_group()ed
and its extra thread should have died but not been scheduled yet.
Try to take a checkpoint in this state. */
breakpoint();
atomic_puts("EXIT-SUCCESS");
return 0;
}
static volatile int scratch = 0;
int main(void) {
pthread_t thread;
pid_t child;
int i;
test_assert(0 == pipe(thread_to_main_fds));
test_assert(0 == pipe(main_to_child_fds));
test_assert(0 == pipe(wait_forever_fds));
child = fork();
if (!child) {
return run_child();
}
atomic_printf("child %d\n", child);
test_assert(0 == pthread_create(&thread, NULL, run_thread, NULL));
test_assert(1 == read(thread_to_main_fds[0], &ch, 1));
/* thread should have blocked on its wait-forever read. Tell the
child to proceed after we exit_group. */
test_assert(1 == write(main_to_child_fds[1], &ch, 1));
/* Spin for a while to give run_child time to reach a runnable state */
for (i = 0; i < 10000000; ++i) {
scratch += 1;
}
return 0;
}