Blame nptl/tst-default-attr.c

Packit 6c4009
/* Verify that pthread_[gs]etattr_default_np work correctly.
Packit 6c4009
Packit 6c4009
   Copyright (C) 2013-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
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
#include <pthread.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
Packit 6c4009
#define RETURN_IF_FAIL(f, ...) \
Packit 6c4009
  ({									      \
Packit 6c4009
    int ret = f (__VA_ARGS__);						      \
Packit 6c4009
    if (ret != 0)							      \
Packit 6c4009
      {									      \
Packit 6c4009
	printf ("%s:%d: %s returned %d (errno = %d)\n", __FILE__, __LINE__,   \
Packit 6c4009
		#f, ret, errno);					      \
Packit 6c4009
	return ret;							      \
Packit 6c4009
      }									      \
Packit 6c4009
  })
Packit 6c4009
Packit 6c4009
static int (*verify_result) (pthread_attr_t *);
Packit 6c4009
static size_t stacksize = 1024 * 1024;
Packit 6c4009
static size_t guardsize;
Packit 6c4009
static bool do_join = true;
Packit 6c4009
static int running = 0;
Packit 6c4009
static int detach_failed = 0;
Packit 6c4009
static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
Packit 6c4009
static pthread_cond_t c = PTHREAD_COND_INITIALIZER;
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
thr (void *unused __attribute__ ((unused)))
Packit 6c4009
{
Packit 6c4009
  pthread_attr_t attr;
Packit 6c4009
  int ret;
Packit 6c4009
Packit 6c4009
  memset (&attr, 0xab, sizeof attr);
Packit 6c4009
  /* To verify that the pthread_setattr_default_np worked.  */
Packit 6c4009
  if ((ret = pthread_getattr_default_np (&attr)) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("pthread_getattr_default_np failed: %s\n", strerror (ret));
Packit 6c4009
      goto out;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if ((ret = (*verify_result) (&attr)) != 0)
Packit 6c4009
    goto out;
Packit 6c4009
Packit 6c4009
  memset (&attr, 0xab, sizeof attr);
Packit 6c4009
  /* To verify that the attributes actually got applied.  */
Packit 6c4009
  if ((ret = pthread_getattr_np (pthread_self (), &attr)) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("pthread_getattr_default_np failed: %s\n", strerror (ret));
Packit 6c4009
      goto out;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  ret = (*verify_result) (&attr);
Packit 6c4009
Packit 6c4009
out:
Packit 6c4009
  if (!do_join)
Packit 6c4009
    {
Packit 6c4009
      pthread_mutex_lock (&m);
Packit 6c4009
      running--;
Packit 6c4009
      pthread_cond_signal (&c);
Packit 6c4009
      pthread_mutex_unlock (&m);
Packit 6c4009
Packit 6c4009
      detach_failed |= ret;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return (void *) (uintptr_t) ret;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
run_threads (const pthread_attr_t *attr)
Packit 6c4009
{
Packit 6c4009
  pthread_t t;
Packit 6c4009
  void *tret = NULL;
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_setattr_default_np, attr);
Packit 6c4009
Packit 6c4009
  /* Run twice to ensure that the attributes do not get overwritten in the
Packit 6c4009
     first run somehow.  */
Packit 6c4009
  for (int i = 0; i < 2; i++)
Packit 6c4009
    {
Packit 6c4009
      RETURN_IF_FAIL (pthread_create, &t, NULL, thr, NULL);
Packit 6c4009
      if (do_join)
Packit 6c4009
	RETURN_IF_FAIL (pthread_join, t, &tret);
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  pthread_mutex_lock (&m);
Packit 6c4009
	  running++;
Packit 6c4009
	  pthread_mutex_unlock (&m);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (tret != NULL)
Packit 6c4009
	{
Packit 6c4009
	  puts ("Thread failed");
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Stay in sync for detached threads and get their status.  */
Packit 6c4009
  while (!do_join)
Packit 6c4009
    {
Packit 6c4009
      pthread_mutex_lock (&m);
Packit 6c4009
      if (running == 0)
Packit 6c4009
	{
Packit 6c4009
	  pthread_mutex_unlock (&m);
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
      pthread_cond_wait (&c, &m);
Packit 6c4009
      pthread_mutex_unlock (&m);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
verify_detach_result (pthread_attr_t *attr)
Packit 6c4009
{
Packit 6c4009
  int state;
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_getdetachstate, attr, &state);
Packit 6c4009
Packit 6c4009
  if (state != PTHREAD_CREATE_DETACHED)
Packit 6c4009
    {
Packit 6c4009
      puts ("failed to set detach state");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_detach_test (void)
Packit 6c4009
{
Packit 6c4009
  pthread_attr_t attr;
Packit 6c4009
Packit 6c4009
  do_join = false;
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_init, &attr);
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_setdetachstate, &attr, PTHREAD_CREATE_DETACHED);
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (run_threads, &attr);
Packit 6c4009
  return detach_failed;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
verify_affinity_result (pthread_attr_t *attr)
Packit 6c4009
{
Packit 6c4009
  cpu_set_t cpuset;
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_getaffinity_np, attr, sizeof (cpuset), &cpuset);
Packit 6c4009
  if (!CPU_ISSET (0, &cpuset))
Packit 6c4009
    {
Packit 6c4009
      puts ("failed to set cpu affinity");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_affinity_test (void)
Packit 6c4009
{
Packit 6c4009
  pthread_attr_t attr;
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_init, &attr);
Packit 6c4009
Packit 6c4009
  /* Processor affinity.  Like scheduling policy, this could fail if the user
Packit 6c4009
     does not have the necessary privileges.  So we only spew a warning if
Packit 6c4009
     pthread_create fails with EPERM.  A computer has at least one CPU.  */
Packit 6c4009
  cpu_set_t cpuset;
Packit 6c4009
  CPU_ZERO (&cpuset);
Packit 6c4009
  CPU_SET (0, &cpuset);
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_setaffinity_np, &attr, sizeof (cpuset), &cpuset);
Packit 6c4009
Packit 6c4009
  int ret = run_threads (&attr);
Packit 6c4009
Packit 6c4009
  if (ret == EPERM)
Packit 6c4009
    {
Packit 6c4009
      printf ("Skipping CPU Affinity test: %s\n", strerror (ret));
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
  else if (ret != 0)
Packit 6c4009
    return ret;
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
verify_sched_result (pthread_attr_t *attr)
Packit 6c4009
{
Packit 6c4009
  int inherited, policy;
Packit 6c4009
  struct sched_param param;
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_getinheritsched, attr, &inherited);
Packit 6c4009
  if (inherited != PTHREAD_EXPLICIT_SCHED)
Packit 6c4009
    {
Packit 6c4009
      puts ("failed to set EXPLICIT_SCHED (%d != %d)");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_getschedpolicy, attr, &policy);
Packit 6c4009
  if (policy != SCHED_RR)
Packit 6c4009
    {
Packit 6c4009
      printf ("failed to set SCHED_RR (%d != %d)\n", policy, SCHED_RR);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_getschedparam, attr, ¶m;;
Packit 6c4009
  if (param.sched_priority != 42)
Packit 6c4009
    {
Packit 6c4009
      printf ("failed to set sched_priority (%d != %d)\n",
Packit 6c4009
	      param.sched_priority, 42);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_sched_test (void)
Packit 6c4009
{
Packit 6c4009
  pthread_attr_t attr;
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_init, &attr);
Packit 6c4009
Packit 6c4009
  /* Scheduling policy.  Note that we don't always test these since it's
Packit 6c4009
     possible that the user the tests run as don't have the appropriate
Packit 6c4009
     privileges.  */
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_setinheritsched, &attr, PTHREAD_EXPLICIT_SCHED);
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_setschedpolicy, &attr, SCHED_RR);
Packit 6c4009
Packit 6c4009
  struct sched_param param;
Packit 6c4009
  param.sched_priority = 42;
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_setschedparam, &attr, ¶m;;
Packit 6c4009
Packit 6c4009
  int ret = run_threads (&attr);
Packit 6c4009
Packit 6c4009
  if (ret == EPERM)
Packit 6c4009
    {
Packit 6c4009
      printf ("Skipping Scheduler Attributes test: %s\n", strerror (ret));
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
  else if (ret != 0)
Packit 6c4009
    return ret;
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
verify_guardsize_result (pthread_attr_t *attr)
Packit 6c4009
{
Packit 6c4009
  size_t guard;
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_getguardsize, attr, &guard);
Packit 6c4009
Packit 6c4009
  if (guardsize != guard)
Packit 6c4009
    {
Packit 6c4009
      printf ("failed to set guardsize (%zu, %zu)\n", guardsize, guard);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_guardsize_test (void)
Packit 6c4009
{
Packit 6c4009
  long int pagesize = sysconf (_SC_PAGESIZE);
Packit 6c4009
  pthread_attr_t attr;
Packit 6c4009
Packit 6c4009
  if (pagesize < 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("sysconf failed: %s\n", strerror (errno));
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_getattr_default_np, &attr);
Packit 6c4009
Packit 6c4009
  /* Increase default guardsize by a page.  */
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_getguardsize, &attr, &guardsize);
Packit 6c4009
  guardsize += pagesize;
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_setguardsize, &attr, guardsize);
Packit 6c4009
  RETURN_IF_FAIL (run_threads, &attr);
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
verify_stacksize_result (pthread_attr_t *attr)
Packit 6c4009
{
Packit 6c4009
  size_t stack;
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_getstacksize, attr, &stack);
Packit 6c4009
Packit 6c4009
  if (stacksize != stack)
Packit 6c4009
    {
Packit 6c4009
      printf ("failed to set default stacksize (%zu, %zu)\n", stacksize, stack);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_stacksize_test (void)
Packit 6c4009
{
Packit 6c4009
  long int pagesize = sysconf (_SC_PAGESIZE);
Packit 6c4009
  pthread_attr_t attr;
Packit 6c4009
Packit 6c4009
  if (pagesize < 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("sysconf failed: %s\n", strerror (errno));
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Perturb the size by a page so that we're not aligned on the 64K boundary.
Packit 6c4009
     pthread_create does this perturbation on x86 to avoid causing the 64k
Packit 6c4009
     aliasing conflict.  We want to prevent pthread_create from doing that
Packit 6c4009
     since it is not consistent for all architectures.  */
Packit 6c4009
  stacksize += pagesize;
Packit 6c4009
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_init, &attr);
Packit 6c4009
Packit 6c4009
  /* Run twice to ensure that we don't give a false positive.  */
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_setstacksize, &attr, stacksize);
Packit 6c4009
  RETURN_IF_FAIL (run_threads, &attr);
Packit 6c4009
  stacksize *= 2;
Packit 6c4009
  RETURN_IF_FAIL (pthread_attr_setstacksize, &attr, stacksize);
Packit 6c4009
  RETURN_IF_FAIL (run_threads, &attr);
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* We test each attribute separately because sched and affinity tests may need
Packit 6c4009
   additional user privileges that may not be available during the test run.
Packit 6c4009
   Each attribute test is a set of two functions, viz. a function to set the
Packit 6c4009
   default attribute (do_foo_test) and another to verify its result
Packit 6c4009
   (verify_foo_result).  Each test spawns a thread and checks (1) if the
Packit 6c4009
   attribute values were applied correctly and (2) if the change in the default
Packit 6c4009
   value reflected.  */
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  puts ("stacksize test");
Packit 6c4009
  verify_result = verify_stacksize_result;
Packit 6c4009
  RETURN_IF_FAIL (do_stacksize_test);
Packit 6c4009
Packit 6c4009
  puts ("guardsize test");
Packit 6c4009
  verify_result = verify_guardsize_result;
Packit 6c4009
  RETURN_IF_FAIL (do_guardsize_test);
Packit 6c4009
Packit 6c4009
  puts ("sched test");
Packit 6c4009
  verify_result = verify_sched_result;
Packit 6c4009
  RETURN_IF_FAIL (do_sched_test);
Packit 6c4009
Packit 6c4009
  puts ("affinity test");
Packit 6c4009
  verify_result = verify_affinity_result;
Packit 6c4009
  RETURN_IF_FAIL (do_affinity_test);
Packit 6c4009
Packit 6c4009
  puts ("detach test");
Packit 6c4009
  verify_result = verify_detach_result;
Packit 6c4009
  RETURN_IF_FAIL (do_detach_test);
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#include "../test-skeleton.c"