Beispiel #1
0
int main(int argc, char *argv[]) {
	int fd;
	ssize_t size;

	fd = open(TEST_FILE, O_CREAT | O_EXCL | O_RDWR, 0600);
	test_assert(0 <= fd);

	size = get_file_size(TEST_FILE);
	atomic_printf("initial file size: %d\n", size);
	test_assert(0 == size);

	truncate(TEST_FILE, 4096);
	size = get_file_size(TEST_FILE);
	atomic_printf("after truncate(4096): %d\n", size);
	test_assert(4096 == size);

	ftruncate(fd, 8192);
	size = get_file_size(TEST_FILE);
	atomic_printf("after truncate(8192): %d\n", size);
	test_assert(8192 == size);

	unlink(TEST_FILE);

	atomic_puts("EXIT-SUCCESS");
	return 0;
}
Beispiel #2
0
int main(int argc, char** argv) {
	int num_syscalls;
	int child;
	int i;

	bad_breakpoint();

	test_assert(argc == 2);
	num_syscalls = atoi(argv[1]);

	atomic_printf("%d: running %d syscalls ...\n", getpid(), num_syscalls);
	for (i = 0; i < num_syscalls; ++i) {
		sys_gettid();
	}

	if (0 == (child = fork())) {
		good_breakpoint();
		exit(0);
	}

	atomic_printf("child %d\n", child);

	waitpid(child, NULL, 0);

	atomic_puts("EXIT-SUCCESS");
	return 0;
}
Beispiel #3
0
int main(void) {
  size_t num_bytes = sysconf(_SC_PAGESIZE);
  int fd = open(DUMMY_FILE, O_CREAT | O_EXCL | O_RDWR, 0600);
  int* rpage;
  size_t i;

  test_assert(fd >= 0);

  overwrite_file(DUMMY_FILE, num_bytes);

  rpage = mmap(NULL, num_bytes, PROT_READ, MAP_SHARED, fd, 0);
  atomic_printf("rpage:%p\n", rpage);
  test_assert(rpage != (void*)-1);

  for (i = 0; i < num_bytes / sizeof(magic); ++i) {
    test_assert(rpage[i] == magic);
  }

  lseek(fd, 0, SEEK_SET);

  for (i = 0; i < num_bytes / sizeof(i); ++i) {
    int written;

    write(fd, &i, sizeof(i));
    written = rpage[i];
    atomic_printf("(wrote %d, read %d)", (int)i, written);
    test_assert(written == (ssize_t)i);
  }

  atomic_puts(" done");
  return 0;
}
Beispiel #4
0
static int interrupted_sleep(void) {
	struct timespec ts = { .tv_sec = 2 };

	alarm(1);
	errno = 0;
	/* The implementation of sleep() is technically allowed to use
	 * SIGALRM, so we have to use nanosleep() for pedantry. */
	nanosleep(&ts, NULL);
	return errno;
}

static int caught_signal;
static void handle_signal(int sig) {
	++caught_signal;
}

int main(int argc, char *argv[]) {
	int err;

	signal(SIGALRM, SIG_IGN);
	err = interrupted_sleep();
	atomic_printf("No sighandler; sleep exits with errno %d\n", err);
	test_assert(0 == err);

	signal(SIGALRM, handle_signal);
	err = interrupted_sleep();
	atomic_printf("With sighandler; sleep exits with errno %d\n", err);
	test_assert(1 == caught_signal);
	test_assert(EINTR == err);

	atomic_puts("EXIT-SUCCESS");
	return 1;
}
Beispiel #5
0
int main(int argc, char* argv[]) {
  size_t page_size = sysconf(_SC_PAGESIZE);
  uint8_t* map1 = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
                       MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  uint8_t* map1_end = map1 + 2 * page_size;
  uint8_t* map2;
  uint8_t* map2_end;

  test_assert(map1 != (void*)-1);

  atomic_printf("map1 = [%p, %p)\n", map1, map1_end);

  mprotect(map1 + page_size, page_size, PROT_NONE);

  map2 = mmap(map1_end, 2 * page_size, PROT_READ | PROT_WRITE,
              MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  map2_end = map2 + page_size;
  test_assert(map2 != (void*)-1);
  test_assert(map2 == map1_end);

  atomic_printf("map2 = [%p, %p)\n", map2, map2_end);

  mprotect(map2, page_size, PROT_NONE);

  atomic_puts("EXIT-SUCCESS");

  return 0;
}
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;
}
Beispiel #7
0
int main(void) {
  int filefd;
  int filefd_out;
  loff_t off = 0;

  filefd = open(token_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
  filefd_out = open(token_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
  write(filefd, TOKEN, TOKEN_SIZE);

  sendfile64(filefd_out, filefd, &off, TOKEN_SIZE);

  atomic_printf(
      "sendfile %zu bytes from %d to %d; off changed from 0 to %" PRId64 "\n",
      TOKEN_SIZE, filefd, filefd_out, off);
  lseek(filefd_out, 0, SEEK_SET);
  verify_token(filefd_out);

  lseek(filefd, 0, SEEK_SET);
  sendfile64(filefd_out, filefd, NULL, TOKEN_SIZE);

  atomic_printf("sendfile %zu bytes from %d to %d\n", TOKEN_SIZE, filefd,
                filefd_out);
  lseek(filefd_out, 0, SEEK_SET);
  verify_token(filefd_out);

  /* The test driver will clean up after us if the test failed
   * before this. */
  unlink(token_file);
  unlink(token_file_out);

  atomic_puts("EXIT-SUCCESS");

  return 0;
}
Beispiel #8
0
static void read_all_chunks(int sock, char* buf, ssize_t num_sockbuf_bytes,
                            char token) {
  ssize_t nread = 0;
  while (nread < num_sockbuf_bytes) {
    char* this_buf = buf + nread;
    ssize_t this_read = read(sock, this_buf, num_sockbuf_bytes - nread);
    int i;

    atomic_printf("M:   read %zd bytes this time,\n", this_read);
    test_assert(this_read > 0);
    /* XXX: we would like to assert that the written data
     * was read in more than one chunk, which should imply
     * that at least one write() from the other thread
     * blocked, but it's possible for multiple write()s to
     * complete and fill the read buffer here before the
     * reader returns. */
    /*test_assert(this_read < num_sockbuf_bytes);*/

    for (i = nread; i < nread + this_read; ++i) {
      if (token != buf[i]) {
        atomic_printf("M:   byte %d should be '%c', but is '%c'\n", i, token,
                      buf[i]);
      }
    }
    nread += this_read;
    atomic_printf("M:      %zd total so far\n", nread);
  }
}
Beispiel #9
0
int main(void) {
  int fd = timerfd_create(CLOCK_MONOTONIC, 0);
  struct itimerspec spec, old;
  uint64_t num_expirations;

  atomic_printf("created timerfd %d\n", fd);
  test_assert(fd >= 0);

  memset(&spec, 0, sizeof(spec));
  spec.it_value.tv_nsec = 100000000;
  atomic_printf("setting timer to expire in {sec:%ld,nsec:%ld}\n",
                spec.it_value.tv_sec, spec.it_value.tv_nsec);
  timerfd_settime(fd, 0, &spec, &old);

  atomic_printf("  (old expiration was {sec:%ld,nsec:%ld})\n",
                old.it_value.tv_sec, old.it_value.tv_nsec);
  test_assert(0 == old.it_value.tv_sec && 0 == old.it_value.tv_nsec);

  atomic_puts("sleeping 50ms ...");
  usleep(50000);

  timerfd_gettime(fd, &old);
  atomic_printf("  expiration now in {sec:%ld,nsec:%ld})\n",
                old.it_value.tv_sec, old.it_value.tv_nsec);
  test_assert(0 == old.it_value.tv_sec && old.it_value.tv_nsec <= 50000000);

  atomic_puts("waiting for timer to expire ...");
  read(fd, &num_expirations, sizeof(num_expirations));

  atomic_printf("  timer expired %" PRIu64 " times\n", num_expirations);
  test_assert(1 == num_expirations);

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
Beispiel #10
0
Datei: sioc.c Projekt: ckousik/rr
/**
 * Fetch and print the ifconfig for this machine.  Fill in
 * |req.ifr_name| with the first non-loopback interface name found.
 */
static void get_ifconfig(int sockfd, struct ifreq* req) {
  struct ifreq ifaces[100];
  struct ifconf ifconf;
  int ret;
  ssize_t num_ifaces;
  int i;
  int set_req_iface = 0;

  ifconf.ifc_len = sizeof(ifaces);
  ifconf.ifc_req = ifaces;

  ret = ioctl(sockfd, SIOCGIFCONF, &ifconf);
  num_ifaces = ifconf.ifc_len / sizeof(ifaces[0]);
  atomic_printf("SIOCGIFCONF(ret %d): %zd ifaces (%d bytes of ifreq)\n", ret,
                num_ifaces, ifconf.ifc_len);
  test_assert(0 == ret);
  test_assert(0 == (ifconf.ifc_len % sizeof(ifaces[0])));

  for (i = 0; i < num_ifaces; ++i) {
    const struct ifreq* ifc = &ifconf.ifc_req[i];
    atomic_printf("  iface %d: name:%s addr:%s\n", i, ifc->ifr_name,
                  sockaddr_name(&ifc->ifr_addr));
    if (!set_req_iface && strcmp("lo", ifc->ifr_name)) {
      strcpy(req->ifr_name, ifc->ifr_name);
      set_req_iface = 1;
    }
  }
  if (!set_req_iface) {
    atomic_puts("Only loopback interface found\n");
    atomic_puts("EXIT-SUCCESS");
    exit(0);
  }
}
Beispiel #11
0
int main(int argc, char *argv[]) {
	char token = start_token;
	struct timeval ts;


	/* (Kick on the syscallbuf if it's enabled.) */
	gettimeofday(&ts, NULL);

	socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfds);

	pthread_barrier_init(&barrier, NULL, 2);
	pthread_create(&reader, NULL, reader_thread, NULL);

	pthread_barrier_wait(&barrier);

	/* Force a blocked read() that's interrupted by a SIGUSR1,
	 * which then itself blocks on read() and succeeds. */
	atomic_puts("M: sleeping ...");
	usleep(500000);

	atomic_puts("M: killing reader ...");
	pthread_kill(reader, SIGUSR1);
	atomic_puts("M:   (quick nap)");
	usleep(100000);

	atomic_puts("M: killing reader again ...");
	pthread_kill(reader, SIGUSR2);

	atomic_puts("M:   (longer nap)");

	usleep(500000);
	atomic_printf("M: finishing level 2 reader by writing '%c' to socket ...\n",
		token);
	write(sockfds[0], &token, sizeof(token));
	++token;

	usleep(500000);
	atomic_printf("M: finishing level 1 reader by writing '%c' to socket ...\n",
		token);
	write(sockfds[0], &token, sizeof(token));
	++token;

	usleep(500000);
	atomic_printf("M: finishing original reader by writing '%c' to socket ...\n",
		token);
	write(sockfds[0], &token, sizeof(token));
	++token;

	atomic_puts("M:   ... done");

	pthread_join(reader, NULL);

	atomic_puts("EXIT-SUCCESS");
	return 0;
}
Beispiel #12
0
static void* thread(void* idp) {
  int tid = (intptr_t)idp;
  int i;

  atomic_printf("thread %d starting ...\n", tid);
  for (i = 0; i < NUM_TRIALS; ++i) {
    pthread_mutex_lock(&lock);
    sched_yield();
    pthread_mutex_unlock(&lock);
  }
  atomic_printf("  ... thread %d done.\n", tid);
  return NULL;
}
Beispiel #13
0
int main(void) {
  long pagesize = sysconf(_SC_PAGESIZE);
  long ncpus = sysconf(_SC_NPROCESSORS_ONLN);

  atomic_printf("sysconf says page size is %ld bytes\n", pagesize);
  test_assert(4096 == pagesize);

  atomic_printf("sysconf says %ld processors are online\n", ncpus);
  /* TODO: change this when rr supports parallel recording. */
  test_assert(1 == ncpus);

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
Beispiel #14
0
int main(int argc, char* argv[]) {
  gid_t groups[1024];
  int num_groups = getgroups(ALEN(groups), groups);
  int i;

  atomic_printf("User %d belongs to %d groups:\n  ", geteuid(), num_groups);
  for (i = 0; i < num_groups; ++i) {
    atomic_printf("%d,", groups[i]);
  }
  atomic_puts("");

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
Beispiel #15
0
int main(int argc, char* argv[]) {
  pid_t sid1;
  pid_t sid2;

  sid1 = getsid(0);
  sid2 = getsid(sid1);
  atomic_printf("getsid(0) session ID: %d\n", sid1);
  atomic_printf("getsid(getsid(0)) session ID: %d\n", sid2);

  if (sid1 == sid2) {
    atomic_puts("EXIT-SUCCESS");
  }

  return 0;
}
Beispiel #16
0
int main(void) {
  int sum;
  getegid();
  sum = cpuid_loop(1000);
  atomic_printf("EXIT-SUCCESS; sum=%d\n", sum);
  return 0;
}
Beispiel #17
0
Datei: sem.c Projekt: khuey/rr
int main(void) {
  pid_t child;
  int status;

  size_t page_size = sysconf(_SC_PAGESIZE);
  shmem = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
               MAP_ANONYMOUS | MAP_SHARED, -1, 0);
  test_assert(shmem != (void*)-1);

  semid = semget(IPC_PRIVATE, COUNT, 0666);
  test_assert(semid >= 0);

  if ((child = fork()) == 0) {
    return run_child();
  }

  atomic_printf("child %d\n", child);

  test_assert(child == waitpid(child, &status, __WALL));
  /* delete the sem before testing status, because we want to ensure the
     segment is deleted even if the test failed. */
  test_assert(0 == semctl(semid, 0, IPC_RMID, NULL));
  test_assert(status == 0);

  atomic_puts("EXIT-SUCCESS");

  return 0;
}
Beispiel #18
0
static void waittermsig(int sig, const char* waiter) {
  struct timespec ts = {.tv_sec = 1 };
  sigset_t set;
  siginfo_t si;

  sigemptyset(&set);
  sigaddset(&set, sig);
  sigtimedwait(&set, &si, &ts);

  atomic_printf("FAILED: %s: signal %d either not caught or didn't terminate "
                "process within 1 second\n",
                waiter, sig);
}

static void* kill_thread(void* dontcare) {
  const int termsig = SIGTERM;

  atomic_puts("killing...");
  kill(getpid(), termsig);
  waittermsig(termsig, "kill_thread");
  return NULL; /* not reached */
}

int main(int argc, char* argv[]) {
  pthread_t t;

  pthread_create(&t, NULL, kill_thread, NULL);
  pthread_join(t, NULL);
  atomic_puts("FAILED: joined thread that should have died");
  return 0;
}
Beispiel #19
0
int main(int argc, char* argv[]) {
  struct tms* buf;
  clock_t t;

  ALLOCATE_GUARD(buf, -1);
  test_assert((t = times(buf)) != (clock_t)-1);
  test_assert(buf->tms_cutime == 0);
  test_assert(buf->tms_utime >= 0);
  VERIFY_GUARD(buf);

  atomic_printf("tms_utime = %lld\n", (long long)buf->tms_utime);
  atomic_printf("result = %lld\n", (long long)t);

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
Beispiel #20
0
int main(int argc, char* argv[]) {
  char token = start_token;
  struct timeval ts;
  int i;

  /* (Kick on the syscallbuf if it's enabled.) */
  gettimeofday(&ts, NULL);

  socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfds);

  pthread_barrier_init(&barrier, NULL, 2);
  pthread_create(&reader, NULL, reader_thread, NULL);

  pthread_barrier_wait(&barrier);

  atomic_puts("M: sleeping ...");
  usleep(500000);
  for (i = 0; i < 4; ++i) {
    atomic_puts("M: killing reader ...");
    pthread_kill(reader, SIGUSR1);
    atomic_puts("M: sleeping ...");
    sleep(1);
  }
  atomic_printf("M: finishing original reader by writing '%c' to socket ...\n",
                token);
  write(sockfds[0], &token, sizeof(token));
  ++token;

  atomic_puts("M:   ... done");

  pthread_join(reader, NULL);

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
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;
}
Beispiel #22
0
int main(int argc, char* argv[]) {
  pid_t child;
  int status;

  depth = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
               MAP_ANONYMOUS | MAP_SHARED, -1, 0);
  test_assert(depth != MAP_FAILED);

  child = fork();

  if (!child) {
    struct sigaction act;
    int* fake_sp = &argc;

    act.sa_sigaction = SEGV_handler;
    act.sa_flags = SA_SIGINFO;
    sigemptyset(&act.sa_mask);
    test_assert(0 == sigaction(SIGSEGV, &act, NULL));

    void* p =
        (void*)((size_t)(fake_sp - 8 * PAGE_SIZE) & ~(size_t)(PAGE_SIZE - 1));

    test_assert(mmap(p, PAGE_SIZE, PROT_NONE,
                     MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0) == p);

    return recurse();
  }

  test_assert(wait(&status) == child);
  test_assert(WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV);

  atomic_printf("depth = %d\n", *depth);
  atomic_puts("EXIT-SUCCESS");
  return 0;
}
Beispiel #23
0
static void assert_prname_is(const char* tag, const char* name) {
  char prname[PRNAME_NUM_BYTES] = "";
  test_assert(0 == prctl(PR_GET_NAME, prname));

  atomic_printf("%s: prname is '%s'; expecting '%s'\n", tag, prname, name);
  test_assert(!strcmp(prname, name));
}
Beispiel #24
0
Datei: getcwd.c Projekt: khuey/rr
int main(int argc, char* argv[]) {
  ssize_t pagesize = sysconf(_SC_PAGESIZE);
  ssize_t two_pages_size = 2 * pagesize;
  void* two_pages = mmap(NULL, two_pages_size, PROT_READ | PROT_WRITE,
                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  void* two_pages_end = two_pages + two_pages_size;
  char* cwd;
  char* expected_cwd;

  test_assert(argc == 2);
  expected_cwd = argv[1];

  test_assert(two_pages != (void*)-1);
  /* Make the value returned into |path| overlap two physical
   * pages. */
  cwd = two_pages + pagesize - 3;
  /* Fill pages with non-zeroes to ensure the returned string is
   * properly null-terminated */
  memset(two_pages, 0xFF, two_pages_size);
  test_assert(cwd == getcwd(cwd, two_pages_end - (void*)cwd));
  atomic_printf("current working directory is %s; should be %s\n", cwd,
                expected_cwd);
  test_assert(!strcmp(cwd, expected_cwd));
  /* Make sure we didn't write too many bytes */
  test_assert((unsigned char)cwd[strlen(cwd) + 1] == 0xFF);

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
Beispiel #25
0
void print_nums(void) {
  int i;
  for (i = 1; i <= 5; ++i) {
    atomic_printf("%d ", i);
  }
  atomic_puts("");
}
Beispiel #26
0
static void* reader_thread(void* dontcare) {
    char token = start_token;
    struct sigaction act;
    int readsock = sockfds[1];
    char c = sentinel_token;
    int flags = 0;

    reader_tid = sys_gettid();

    flags = SA_RESTART;

    memset(&act, 0, sizeof(act));
    act.sa_handler = sighandler;
    act.sa_flags = flags;
    sigaction(SIGUSR1, &act, NULL);

    memset(&act, 0, sizeof(act));
    act.sa_handler = sighandler2;
    act.sa_flags = flags;
    sigaction(SIGUSR2, &act, NULL);

    pthread_barrier_wait(&barrier);

    atomic_puts("r: blocking on read, awaiting signal ...");

    test_assert(1 == read(readsock, &c, sizeof(c)));
    test_assert(2 == reader_caught_signal);
    token += reader_caught_signal;

    atomic_printf("r: ... read level 0 '%c'\n", c);
    test_assert(c == token);

    return NULL;
}
Beispiel #27
0
int main(void) {
  size_t page_size = sysconf(_SC_PAGESIZE);
  int fd = open(FILENAME, O_CREAT | O_EXCL | O_RDWR, 0600);
  int* wpage;
  size_t i;
  int* rpage;

  unlink(FILENAME);

  test_assert(fd >= 0);
  ftruncate(fd, page_size);

  wpage = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, fd, 0);
  test_assert(wpage != (void*)-1);
  for (i = 0; i < page_size / sizeof(int); ++i) {
    wpage[i] = i;
  }

  rpage = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
  test_assert(rpage != (void*)-1 && wpage != rpage);

  msync(wpage, page_size, MS_INVALIDATE);

  for (i = 0; i < page_size / sizeof(int); ++i) {
    test_assert(rpage[i] == (ssize_t)i);
    atomic_printf("%d,", rpage[i]);
  }

  atomic_puts("EXIT-SUCCESS");

  return 0;
}
Beispiel #28
0
int main(int argc, char* argv[]) {
  int fds[2];
  struct pollfd pfd;
  int i;

  pipe2(fds, O_NONBLOCK);

  pfd.fd = fds[0];
  pfd.events = POLLIN;
  for (i = 0; i < NUM_ITERATIONS; ++i) {
    char c;

    atomic_printf("iteration %d\n", i);

    if (0 == fork()) {
      usleep(250000);
      write(fds[1], "x", 1);
      return 0;
    }

    test_assert(1 == poll(&pfd, 1, -1));
    test_assert(POLLIN & pfd.revents);
    test_assert(1 == read(pfd.fd, &c, 1));
  }

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
Beispiel #29
0
static void check_mapping(int* page, int magic, ssize_t nr_ints) {
  int i;
  for (i = 0; i < nr_ints; ++i) {
    test_assert(page[i] == magic);
  }
  atomic_printf("  %p has the correct values\n", page);
}
Beispiel #30
0
int main(int argc, char *argv[]) {
	const size_t stack_size = 1 << 20;
	void* stack = mmap(NULL, stack_size,
			   PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
			   -1, 0);
	int pid;
	sigset_t set;

	sys_gettid();
	/* NB: no syscalls in between the sys_gettid() above and this
	 * clone(). */
	breakpoint();

	/* Warning: strace gets the parameter order wrong and will print
	   child_tidptr as 0 here. */
	pid = clone(child, stack + stack_size,
		CLONE_VM | CLONE_FS | CLONE_FILES |
		CLONE_THREAD | CLONE_SIGHAND |
		CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID,
		NULL, &child_tid, NULL, &child_tid);

	atomic_printf("clone()d pid: %d\n", pid);
	test_assert(pid > 0);

	futex(&child_tid, FUTEX_WAIT, pid, NULL, NULL, 0);
	test_assert(child_tid_copy == pid);
	/* clone() should have cleared child_tid now */
	test_assert(child_tid == 0);

	sys_gettid();

	sigfillset(&set);
	test_assert(0 == sigprocmask(SIG_BLOCK, &set, NULL));

	/* NB: no syscalls in between the sys_gettid() above and this
	 * clone(). */
	breakpoint();
	pid = clone(child, stack + stack_size,
		    CLONE_SIGHAND /*must also have CLONE_VM*/,
		    NULL, NULL, NULL);

	atomic_printf("clone(CLONE_SIGHAND)'d pid: %d\n", pid);
	test_assert(-1 == pid);

	atomic_puts("EXIT-SUCCESS");
	return 0;
}