/* -*- 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;
}
