Blame nptl/tst-mutex8.c

Packit 6c4009
/* Copyright (C) 2003-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* This test checks behavior not required by POSIX.  */
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <pthread.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <elf/dl-tunables.h>
Packit 6c4009
Packit 6c4009
static pthread_mutex_t *m;
Packit 6c4009
static pthread_barrier_t b;
Packit 6c4009
static pthread_cond_t c;
Packit 6c4009
static bool done;
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
cl (void *arg)
Packit 6c4009
{
Packit 6c4009
  if (pthread_mutex_unlock (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("cl: mutex_unlocked failed");
Packit 6c4009
      exit (1);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
tf (void *arg)
Packit 6c4009
{
Packit 6c4009
  if (pthread_mutex_lock (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("tf: mutex_lock failed");
Packit 6c4009
      return (void *) 1l;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  int e = pthread_barrier_wait (&b);
Packit 6c4009
  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
Packit 6c4009
    {
Packit 6c4009
      puts ("barrier_wait failed");
Packit 6c4009
      return (void *) 1l;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (arg == NULL)
Packit 6c4009
    do
Packit 6c4009
      if (pthread_cond_wait (&c, m) != 0)
Packit 6c4009
	{
Packit 6c4009
	  puts ("tf: cond_wait failed");
Packit 6c4009
	  return (void *) 1l;
Packit 6c4009
	}
Packit 6c4009
    while (! done);
Packit 6c4009
  else
Packit 6c4009
    do
Packit 6c4009
      {
Packit 6c4009
	pthread_cleanup_push (cl, NULL);
Packit 6c4009
Packit 6c4009
	if (pthread_cond_wait (&c, m) != 0)
Packit 6c4009
	  {
Packit 6c4009
	    puts ("tf: cond_wait failed");
Packit 6c4009
	    return (void *) 1l;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	pthread_cleanup_pop (0);
Packit 6c4009
      }
Packit 6c4009
    while (! done);
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_unlock (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("tf: mutex_unlock failed");
Packit 6c4009
      return (void *) 1l;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
check_type (const char *mas, pthread_mutexattr_t *ma)
Packit 6c4009
{
Packit 6c4009
  int e;
Packit 6c4009
Packit 6c4009
  /* Check if a mutex will be elided.  Lock elision can only be activated via
Packit 6c4009
     the tunables framework.  By default, lock elision is disabled.  */
Packit 6c4009
  bool assume_elided_mutex = false;
Packit 6c4009
#if HAVE_TUNABLES
Packit 6c4009
  int ma_type = PTHREAD_MUTEX_TIMED_NP;
Packit 6c4009
  if (ma != NULL)
Packit 6c4009
    {
Packit 6c4009
      e = pthread_mutexattr_gettype (ma, &ma_type);
Packit 6c4009
      if (e != 0)
Packit 6c4009
	{
Packit 6c4009
	  printf ("pthread_mutexattr_gettype failed with %d (%m)\n", e);
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  if (ma_type == PTHREAD_MUTEX_TIMED_NP)
Packit 6c4009
    {
Packit 6c4009
      /* This type of mutex can be elided if elision is enabled via the tunables
Packit 6c4009
	 framework.  Some tests below are failing if the mutex is elided.
Packit 6c4009
	 Thus we only run those if we assume that the mutex won't be elided.  */
Packit 6c4009
      if (TUNABLE_GET_FULL (glibc, elision, enable, int32_t, NULL) == 1)
Packit 6c4009
	assume_elided_mutex = true;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  e = pthread_mutex_init (m, ma);
Packit 6c4009
  if (e != 0)
Packit 6c4009
    {
Packit 6c4009
#ifdef ENABLE_PI
Packit 6c4009
      if (e == ENOTSUP)
Packit 6c4009
	{
Packit 6c4009
	  puts ("PI mutexes unsupported");
Packit 6c4009
	  return 0;
Packit 6c4009
	}
Packit 6c4009
#endif
Packit 6c4009
      printf ("1st mutex_init failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_destroy (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("immediate mutex_destroy failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_init (m, ma) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("2nd mutex_init failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_lock (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("1st mutex_lock failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Elided mutexes don't fail destroy, thus only test this if we don't assume
Packit 6c4009
     elision.  */
Packit 6c4009
  if (assume_elided_mutex == false)
Packit 6c4009
    {
Packit 6c4009
      e = pthread_mutex_destroy (m);
Packit 6c4009
      if (e == 0)
Packit 6c4009
	{
Packit 6c4009
	  printf ("mutex_destroy of self-locked mutex succeeded for %s\n", mas);
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
      if (e != EBUSY)
Packit 6c4009
	{
Packit 6c4009
	  printf ("\
Packit 6c4009
mutex_destroy of self-locked mutex did not return EBUSY %s\n",
Packit 6c4009
		  mas);
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_unlock (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("1st mutex_unlock failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_trylock (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("mutex_trylock failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Elided mutexes don't fail destroy.  */
Packit 6c4009
  if (assume_elided_mutex == false)
Packit 6c4009
    {
Packit 6c4009
      e = pthread_mutex_destroy (m);
Packit 6c4009
      if (e == 0)
Packit 6c4009
	{
Packit 6c4009
	  printf ("mutex_destroy of self-trylocked mutex succeeded for %s\n",
Packit 6c4009
		  mas);
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
      if (e != EBUSY)
Packit 6c4009
	{
Packit 6c4009
	  printf ("\
Packit 6c4009
mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
Packit 6c4009
		  mas);
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_unlock (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("2nd mutex_unlock failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  pthread_t th;
Packit 6c4009
  if (pthread_create (&th, NULL, tf, NULL) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("1st create failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
  done = false;
Packit 6c4009
Packit 6c4009
  e = pthread_barrier_wait (&b);
Packit 6c4009
  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
Packit 6c4009
    {
Packit 6c4009
      puts ("1st barrier_wait failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_lock (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("2nd mutex_lock failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_unlock (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("3rd mutex_unlock failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Elided mutexes don't fail destroy.  */
Packit 6c4009
  if (assume_elided_mutex == false)
Packit 6c4009
    {
Packit 6c4009
      e = pthread_mutex_destroy (m);
Packit 6c4009
      if (e == 0)
Packit 6c4009
	{
Packit 6c4009
	  printf ("mutex_destroy of condvar-used mutex succeeded for %s\n",
Packit 6c4009
		  mas);
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
      if (e != EBUSY)
Packit 6c4009
	{
Packit 6c4009
	  printf ("\
Packit 6c4009
mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  done = true;
Packit 6c4009
  if (pthread_cond_signal (&c) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("cond_signal failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  void *r;
Packit 6c4009
  if (pthread_join (th, &r) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("join failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
  if (r != NULL)
Packit 6c4009
    {
Packit 6c4009
      puts ("thread didn't return NULL");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_destroy (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("mutex_destroy after condvar-use failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_init (m, ma) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("3rd mutex_init failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_create (&th, NULL, tf, (void *) 1) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("2nd create failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
  done = false;
Packit 6c4009
Packit 6c4009
  e = pthread_barrier_wait (&b);
Packit 6c4009
  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
Packit 6c4009
    {
Packit 6c4009
      puts ("2nd barrier_wait failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_lock (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("3rd mutex_lock failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_unlock (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("4th mutex_unlock failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Elided mutexes don't fail destroy.  */
Packit 6c4009
  if (assume_elided_mutex == false)
Packit 6c4009
    {
Packit 6c4009
      e = pthread_mutex_destroy (m);
Packit 6c4009
      if (e == 0)
Packit 6c4009
	{
Packit 6c4009
	  printf ("2nd mutex_destroy of condvar-used mutex succeeded for %s\n",
Packit 6c4009
		  mas);
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
      if (e != EBUSY)
Packit 6c4009
	{
Packit 6c4009
	  printf ("\
Packit 6c4009
2nd mutex_destroy of condvar-used mutex did not return EBUSY for %s\n",
Packit 6c4009
		  mas);
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_cancel (th) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("cond_cancel failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_join (th, &r) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("join failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
  if (r != PTHREAD_CANCELED)
Packit 6c4009
    {
Packit 6c4009
      puts ("thread not canceled");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutex_destroy (m) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("mutex_destroy after condvar-canceled failed for %s\n", mas);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  pthread_mutex_t mm;
Packit 6c4009
  m = &mm;
Packit 6c4009
Packit 6c4009
  if (pthread_barrier_init (&b, NULL, 2) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("barrier_init failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_cond_init (&c, NULL) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("cond_init failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  puts ("check normal mutex");
Packit 6c4009
  int res = check_type ("normal", NULL);
Packit 6c4009
Packit 6c4009
  pthread_mutexattr_t ma;
Packit 6c4009
  if (pthread_mutexattr_init (&ma) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("1st mutexattr_init failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
  if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("1st mutexattr_settype failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
#ifdef ENABLE_PI
Packit 6c4009
  if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT))
Packit 6c4009
    {
Packit 6c4009
      puts ("1st pthread_mutexattr_setprotocol failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
  puts ("check recursive mutex");
Packit 6c4009
  res |= check_type ("recursive", &ma);
Packit 6c4009
  if (pthread_mutexattr_destroy (&ma) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("1st mutexattr_destroy failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (pthread_mutexattr_init (&ma) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("2nd mutexattr_init failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
  if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("2nd mutexattr_settype failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
#ifdef ENABLE_PI
Packit 6c4009
  if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT))
Packit 6c4009
    {
Packit 6c4009
      puts ("2nd pthread_mutexattr_setprotocol failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
  puts ("check error-checking mutex");
Packit 6c4009
  res |= check_type ("error-checking", &ma);
Packit 6c4009
  if (pthread_mutexattr_destroy (&ma) != 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("2nd mutexattr_destroy failed");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return res;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#include "../test-skeleton.c"