Blame nptl/tst-cancel17.c

Packit Service 82fcde
/* Copyright (C) 2003-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <aio.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <pthread.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static pthread_barrier_t b;
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Cleanup handling test.  */
Packit Service 82fcde
static int cl_called;
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
cl (void *arg)
Packit Service 82fcde
{
Packit Service 82fcde
  ++cl_called;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static void *
Packit Service 82fcde
tf (void *arg)
Packit Service 82fcde
{
Packit Service 82fcde
  int r = pthread_barrier_wait (&b);
Packit Service 82fcde
  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("tf: barrier_wait failed");
Packit Service 82fcde
      exit (1);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  pthread_cleanup_push (cl, NULL);
Packit Service 82fcde
Packit Service 82fcde
  const struct aiocb *l[1] = { arg };
Packit Service 82fcde
Packit Service 82fcde
  TEMP_FAILURE_RETRY (aio_suspend (l, 1, NULL));
Packit Service 82fcde
Packit Service 82fcde
  pthread_cleanup_pop (0);
Packit Service 82fcde
Packit Service 82fcde
  puts ("tf: aio_suspend returned");
Packit Service 82fcde
Packit Service 82fcde
  exit (1);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static void *
Packit Service 82fcde
tf2 (void *arg)
Packit Service 82fcde
{
Packit Service 82fcde
  int r = pthread_barrier_wait (&b);
Packit Service 82fcde
  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("tf2: barrier_wait failed");
Packit Service 82fcde
      exit (1);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  pthread_cleanup_push (cl, NULL);
Packit Service 82fcde
Packit Service 82fcde
  const struct aiocb *l[1] = { arg };
Packit Service 82fcde
  struct timespec ts = { .tv_sec = 1000, .tv_nsec = 0 };
Packit Service 82fcde
Packit Service 82fcde
  TEMP_FAILURE_RETRY (aio_suspend (l, 1, &ts);;
Packit Service 82fcde
Packit Service 82fcde
  pthread_cleanup_pop (0);
Packit Service 82fcde
Packit Service 82fcde
  puts ("tf2: aio_suspend returned");
Packit Service 82fcde
Packit Service 82fcde
  exit (1);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
do_test (void)
Packit Service 82fcde
{
Packit Service 82fcde
  int fds[2];
Packit Service 82fcde
  if (pipe (fds) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("pipe failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  struct aiocb a, a2, *ap;
Packit Service 82fcde
  char mem[1];
Packit Service 82fcde
  memset (&a, '\0', sizeof (a));
Packit Service 82fcde
  a.aio_fildes = fds[0];
Packit Service 82fcde
  a.aio_buf = mem;
Packit Service 82fcde
  a.aio_nbytes = sizeof (mem);
Packit Service 82fcde
  if (aio_read (&a) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("aio_read failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (pthread_barrier_init (&b, NULL, 2) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("barrier_init failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  pthread_t th;
Packit Service 82fcde
  if (pthread_create (&th, NULL, tf, &a) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("1st create failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  int r = pthread_barrier_wait (&b);
Packit Service 82fcde
  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("barrier_wait failed");
Packit Service 82fcde
      exit (1);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  struct timespec  ts = { .tv_sec = 0, .tv_nsec = 100000000 };
Packit Service 82fcde
  while (nanosleep (&ts, &ts) != 0)
Packit Service 82fcde
    continue;
Packit Service 82fcde
Packit Service 82fcde
  puts ("going to cancel tf in-time");
Packit Service 82fcde
  if (pthread_cancel (th) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("1st cancel failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  void *status;
Packit Service 82fcde
  if (pthread_join (th, &status) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("1st join failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (status != PTHREAD_CANCELED)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("1st thread not canceled");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (cl_called == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("tf cleanup handler not called");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (cl_called > 1)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("tf cleanup handler called more than once");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  cl_called = 0;
Packit Service 82fcde
Packit Service 82fcde
  if (pthread_create (&th, NULL, tf2, &a) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("2nd create failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  r = pthread_barrier_wait (&b);
Packit Service 82fcde
  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("2nd barrier_wait failed");
Packit Service 82fcde
      exit (1);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  ts.tv_sec = 0;
Packit Service 82fcde
  ts.tv_nsec = 100000000;
Packit Service 82fcde
  while (nanosleep (&ts, &ts) != 0)
Packit Service 82fcde
    continue;
Packit Service 82fcde
Packit Service 82fcde
  puts ("going to cancel tf2 in-time");
Packit Service 82fcde
  if (pthread_cancel (th) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("2nd cancel failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (pthread_join (th, &status) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("2nd join failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (status != PTHREAD_CANCELED)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("2nd thread not canceled");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (cl_called == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("tf2 cleanup handler not called");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (cl_called > 1)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("tf2 cleanup handler called more than once");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  puts ("in-time cancellation succeeded");
Packit Service 82fcde
Packit Service 82fcde
  ap = &a;
Packit Service 82fcde
  if (aio_cancel (fds[0], &a) != AIO_CANCELED)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("aio_cancel failed");
Packit Service 82fcde
      /* If aio_cancel failed, we cannot reuse aiocb a.  */
Packit Service 82fcde
      ap = &a2;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
  cl_called = 0;
Packit Service 82fcde
Packit Service 82fcde
  size_t len2 = fpathconf (fds[1], _PC_PIPE_BUF);
Packit Service 82fcde
  size_t page_size = sysconf (_SC_PAGESIZE);
Packit Service 82fcde
  len2 = 20 * (len2 < page_size ? page_size : len2) + sizeof (mem) + 1;
Packit Service 82fcde
  char *mem2 = malloc (len2);
Packit Service 82fcde
  if (mem2 == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("could not allocate memory for pipe write");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  memset (ap, '\0', sizeof (*ap));
Packit Service 82fcde
  ap->aio_fildes = fds[1];
Packit Service 82fcde
  ap->aio_buf = mem2;
Packit Service 82fcde
  ap->aio_nbytes = len2;
Packit Service 82fcde
  if (aio_write (ap) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("aio_write failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (pthread_create (&th, NULL, tf, ap) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("3rd create failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  puts ("going to cancel tf early");
Packit Service 82fcde
  if (pthread_cancel (th) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("3rd cancel failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  r = pthread_barrier_wait (&b);
Packit Service 82fcde
  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("3rd barrier_wait failed");
Packit Service 82fcde
      exit (1);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (pthread_join (th, &status) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("3rd join failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (status != PTHREAD_CANCELED)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("3rd thread not canceled");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (cl_called == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("tf cleanup handler not called");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (cl_called > 1)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("tf cleanup handler called more than once");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  cl_called = 0;
Packit Service 82fcde
Packit Service 82fcde
  if (pthread_create (&th, NULL, tf2, ap) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("4th create failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  puts ("going to cancel tf2 early");
Packit Service 82fcde
  if (pthread_cancel (th) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("4th cancel failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  r = pthread_barrier_wait (&b);
Packit Service 82fcde
  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("4th barrier_wait failed");
Packit Service 82fcde
      exit (1);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (pthread_join (th, &status) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("4th join failed");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (status != PTHREAD_CANCELED)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("4th thread not canceled");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (cl_called == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("tf2 cleanup handler not called");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (cl_called > 1)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("tf2 cleanup handler called more than once");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  puts ("early cancellation succeeded");
Packit Service 82fcde
Packit Service 82fcde
  if (ap == &a2)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* The aio_read(&a) was not canceled because the read request was
Packit Service 82fcde
	 already in progress. In the meanwhile aio_write(ap) wrote something
Packit Service 82fcde
	 to the pipe and the read request either has already been finished or
Packit Service 82fcde
	 is able to read the requested byte.
Packit Service 82fcde
	 Wait for the read request before returning from this function because
Packit Service 82fcde
	 the return value and error code from the read syscall will be written
Packit Service 82fcde
	 to the struct aiocb a, which lies on the stack of this function.
Packit Service 82fcde
	 Otherwise the stack from subsequent function calls - e.g. _dl_fini -
Packit Service 82fcde
	 will be corrupted, which can lead to undefined behaviour like a
Packit Service 82fcde
	 segmentation fault.  */
Packit Service 82fcde
      const struct aiocb *l[1] = { &a };
Packit Service 82fcde
      TEMP_FAILURE_RETRY (aio_suspend(l, 1, NULL));
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#define TEST_FUNCTION do_test ()
Packit Service 82fcde
#include "../test-skeleton.c"