(root)/
glibc-2.38/
nptl/
tst-default-attr.c
       1  /* Verify that pthread_[gs]etattr_default_np work correctly.
       2  
       3     Copyright (C) 2013-2023 Free Software Foundation, Inc.
       4     This file is part of the GNU C Library.
       5  
       6     The GNU C Library is free software; you can redistribute it and/or
       7     modify it under the terms of the GNU Lesser General Public
       8     License as published by the Free Software Foundation; either
       9     version 2.1 of the License, or (at your option) any later version.
      10  
      11     The GNU C Library is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14     Lesser General Public License for more details.
      15  
      16     You should have received a copy of the GNU Lesser General Public
      17     License along with the GNU C Library; if not, see
      18     <https://www.gnu.org/licenses/>.  */
      19  
      20  #include <pthread.h>
      21  #include <stdio.h>
      22  #include <stdint.h>
      23  #include <string.h>
      24  #include <unistd.h>
      25  #include <errno.h>
      26  #include <stdbool.h>
      27  
      28  #define RETURN_IF_FAIL(f, ...) \
      29    ({									      \
      30      int ret = f (__VA_ARGS__);						      \
      31      if (ret != 0)							      \
      32        {									      \
      33  	printf ("%s:%d: %s returned %d (errno = %d)\n", __FILE__, __LINE__,   \
      34  		#f, ret, errno);					      \
      35  	return ret;							      \
      36        }									      \
      37    })
      38  
      39  static int (*verify_result) (pthread_attr_t *);
      40  static size_t stacksize = 1024 * 1024;
      41  static size_t guardsize;
      42  static bool do_join = true;
      43  static int running = 0;
      44  static int detach_failed = 0;
      45  static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
      46  static pthread_cond_t c = PTHREAD_COND_INITIALIZER;
      47  
      48  static void *
      49  thr (void *unused __attribute__ ((unused)))
      50  {
      51    pthread_attr_t attr;
      52    int ret;
      53  
      54    memset (&attr, 0xab, sizeof attr);
      55    /* To verify that the pthread_setattr_default_np worked.  */
      56    if ((ret = pthread_getattr_default_np (&attr)) != 0)
      57      {
      58        printf ("pthread_getattr_default_np failed: %s\n", strerror (ret));
      59        goto out;
      60      }
      61  
      62    if ((ret = (*verify_result) (&attr)) != 0)
      63      goto out;
      64  
      65    memset (&attr, 0xab, sizeof attr);
      66    /* To verify that the attributes actually got applied.  */
      67    if ((ret = pthread_getattr_np (pthread_self (), &attr)) != 0)
      68      {
      69        printf ("pthread_getattr_default_np failed: %s\n", strerror (ret));
      70        goto out;
      71      }
      72  
      73    ret = (*verify_result) (&attr);
      74  
      75  out:
      76    if (!do_join)
      77      {
      78        pthread_mutex_lock (&m);
      79        running--;
      80        pthread_cond_signal (&c);
      81        pthread_mutex_unlock (&m);
      82  
      83        detach_failed |= ret;
      84      }
      85  
      86    return (void *) (uintptr_t) ret;
      87  }
      88  
      89  static int
      90  run_threads (const pthread_attr_t *attr)
      91  {
      92    pthread_t t;
      93    void *tret = NULL;
      94  
      95    RETURN_IF_FAIL (pthread_setattr_default_np, attr);
      96  
      97    /* Run twice to ensure that the attributes do not get overwritten in the
      98       first run somehow.  */
      99    for (int i = 0; i < 2; i++)
     100      {
     101        RETURN_IF_FAIL (pthread_create, &t, NULL, thr, NULL);
     102        if (do_join)
     103  	RETURN_IF_FAIL (pthread_join, t, &tret);
     104        else
     105  	{
     106  	  pthread_mutex_lock (&m);
     107  	  running++;
     108  	  pthread_mutex_unlock (&m);
     109  	}
     110  
     111        if (tret != NULL)
     112  	{
     113  	  puts ("Thread failed");
     114  	  return 1;
     115  	}
     116      }
     117  
     118    /* Stay in sync for detached threads and get their status.  */
     119    while (!do_join)
     120      {
     121        pthread_mutex_lock (&m);
     122        if (running == 0)
     123  	{
     124  	  pthread_mutex_unlock (&m);
     125  	  break;
     126  	}
     127        pthread_cond_wait (&c, &m);
     128        pthread_mutex_unlock (&m);
     129      }
     130  
     131    return 0;
     132  }
     133  
     134  static int
     135  verify_detach_result (pthread_attr_t *attr)
     136  {
     137    int state;
     138  
     139    RETURN_IF_FAIL (pthread_attr_getdetachstate, attr, &state);
     140  
     141    if (state != PTHREAD_CREATE_DETACHED)
     142      {
     143        puts ("failed to set detach state");
     144        return 1;
     145      }
     146  
     147    return 0;
     148  }
     149  
     150  static int
     151  do_detach_test (void)
     152  {
     153    pthread_attr_t attr;
     154  
     155    do_join = false;
     156    RETURN_IF_FAIL (pthread_attr_init, &attr);
     157    RETURN_IF_FAIL (pthread_attr_setdetachstate, &attr, PTHREAD_CREATE_DETACHED);
     158  
     159    RETURN_IF_FAIL (run_threads, &attr);
     160    return detach_failed;
     161  }
     162  
     163  static int
     164  verify_affinity_result (pthread_attr_t *attr)
     165  {
     166    cpu_set_t cpuset;
     167  
     168    RETURN_IF_FAIL (pthread_attr_getaffinity_np, attr, sizeof (cpuset), &cpuset);
     169    if (!CPU_ISSET (0, &cpuset))
     170      {
     171        puts ("failed to set cpu affinity");
     172        return 1;
     173      }
     174  
     175    return 0;
     176  }
     177  
     178  static int
     179  do_affinity_test (void)
     180  {
     181    pthread_attr_t attr;
     182  
     183    RETURN_IF_FAIL (pthread_attr_init, &attr);
     184  
     185    /* Processor affinity.  Like scheduling policy, this could fail if the user
     186       does not have the necessary privileges.  So we only spew a warning if
     187       pthread_create fails with EPERM.  A computer has at least one CPU.  */
     188    cpu_set_t cpuset;
     189    CPU_ZERO (&cpuset);
     190    CPU_SET (0, &cpuset);
     191    RETURN_IF_FAIL (pthread_attr_setaffinity_np, &attr, sizeof (cpuset), &cpuset);
     192  
     193    int ret = run_threads (&attr);
     194  
     195    if (ret == EPERM)
     196      {
     197        printf ("Skipping CPU Affinity test: %s\n", strerror (ret));
     198        return 0;
     199      }
     200    else if (ret != 0)
     201      return ret;
     202  
     203    return 0;
     204  }
     205  
     206  static int
     207  verify_sched_result (pthread_attr_t *attr)
     208  {
     209    int inherited, policy;
     210    struct sched_param param;
     211  
     212    RETURN_IF_FAIL (pthread_attr_getinheritsched, attr, &inherited);
     213    if (inherited != PTHREAD_EXPLICIT_SCHED)
     214      {
     215        puts ("failed to set EXPLICIT_SCHED (%d != %d)");
     216        return 1;
     217      }
     218  
     219    RETURN_IF_FAIL (pthread_attr_getschedpolicy, attr, &policy);
     220    if (policy != SCHED_RR)
     221      {
     222        printf ("failed to set SCHED_RR (%d != %d)\n", policy, SCHED_RR);
     223        return 1;
     224      }
     225  
     226    RETURN_IF_FAIL (pthread_attr_getschedparam, attr, &param);
     227    if (param.sched_priority != 42)
     228      {
     229        printf ("failed to set sched_priority (%d != %d)\n",
     230  	      param.sched_priority, 42);
     231        return 1;
     232      }
     233  
     234    return 0;
     235  }
     236  
     237  static int
     238  do_sched_test (void)
     239  {
     240    pthread_attr_t attr;
     241  
     242    RETURN_IF_FAIL (pthread_attr_init, &attr);
     243  
     244    /* Scheduling policy.  Note that we don't always test these since it's
     245       possible that the user the tests run as don't have the appropriate
     246       privileges.  */
     247    RETURN_IF_FAIL (pthread_attr_setinheritsched, &attr, PTHREAD_EXPLICIT_SCHED);
     248    RETURN_IF_FAIL (pthread_attr_setschedpolicy, &attr, SCHED_RR);
     249  
     250    struct sched_param param;
     251    param.sched_priority = 42;
     252    RETURN_IF_FAIL (pthread_attr_setschedparam, &attr, &param);
     253  
     254    int ret = run_threads (&attr);
     255  
     256    if (ret == EPERM)
     257      {
     258        printf ("Skipping Scheduler Attributes test: %s\n", strerror (ret));
     259        return 0;
     260      }
     261    else if (ret != 0)
     262      return ret;
     263  
     264    return 0;
     265  }
     266  
     267  static int
     268  verify_guardsize_result (pthread_attr_t *attr)
     269  {
     270    size_t guard;
     271  
     272    RETURN_IF_FAIL (pthread_attr_getguardsize, attr, &guard);
     273  
     274    if (guardsize != guard)
     275      {
     276        printf ("failed to set guardsize (%zu, %zu)\n", guardsize, guard);
     277        return 1;
     278      }
     279  
     280    return 0;
     281  }
     282  
     283  static int
     284  do_guardsize_test (void)
     285  {
     286    long int pagesize = sysconf (_SC_PAGESIZE);
     287    pthread_attr_t attr;
     288  
     289    if (pagesize < 0)
     290      {
     291        printf ("sysconf failed: %s\n", strerror (errno));
     292        return 1;
     293      }
     294  
     295    RETURN_IF_FAIL (pthread_getattr_default_np, &attr);
     296  
     297    /* Increase default guardsize by a page.  */
     298    RETURN_IF_FAIL (pthread_attr_getguardsize, &attr, &guardsize);
     299    guardsize += pagesize;
     300    RETURN_IF_FAIL (pthread_attr_setguardsize, &attr, guardsize);
     301    RETURN_IF_FAIL (run_threads, &attr);
     302  
     303    return 0;
     304  }
     305  
     306  static int
     307  verify_stacksize_result (pthread_attr_t *attr)
     308  {
     309    size_t stack;
     310  
     311    RETURN_IF_FAIL (pthread_attr_getstacksize, attr, &stack);
     312  
     313    if (stacksize != stack)
     314      {
     315        printf ("failed to set default stacksize (%zu, %zu)\n", stacksize, stack);
     316        return 1;
     317      }
     318  
     319    return 0;
     320  }
     321  
     322  static int
     323  do_stacksize_test (void)
     324  {
     325    long int pagesize = sysconf (_SC_PAGESIZE);
     326    pthread_attr_t attr;
     327  
     328    if (pagesize < 0)
     329      {
     330        printf ("sysconf failed: %s\n", strerror (errno));
     331        return 1;
     332      }
     333  
     334    /* Perturb the size by a page so that we're not aligned on the 64K boundary.
     335       pthread_create does this perturbation on x86 to avoid causing the 64k
     336       aliasing conflict.  We want to prevent pthread_create from doing that
     337       since it is not consistent for all architectures.  */
     338    stacksize += pagesize;
     339  
     340    RETURN_IF_FAIL (pthread_attr_init, &attr);
     341  
     342    /* Run twice to ensure that we don't give a false positive.  */
     343    RETURN_IF_FAIL (pthread_attr_setstacksize, &attr, stacksize);
     344    RETURN_IF_FAIL (run_threads, &attr);
     345    stacksize *= 2;
     346    RETURN_IF_FAIL (pthread_attr_setstacksize, &attr, stacksize);
     347    RETURN_IF_FAIL (run_threads, &attr);
     348    return 0;
     349  }
     350  
     351  /* We test each attribute separately because sched and affinity tests may need
     352     additional user privileges that may not be available during the test run.
     353     Each attribute test is a set of two functions, viz. a function to set the
     354     default attribute (do_foo_test) and another to verify its result
     355     (verify_foo_result).  Each test spawns a thread and checks (1) if the
     356     attribute values were applied correctly and (2) if the change in the default
     357     value reflected.  */
     358  static int
     359  do_test (void)
     360  {
     361    puts ("stacksize test");
     362    verify_result = verify_stacksize_result;
     363    RETURN_IF_FAIL (do_stacksize_test);
     364  
     365    puts ("guardsize test");
     366    verify_result = verify_guardsize_result;
     367    RETURN_IF_FAIL (do_guardsize_test);
     368  
     369    puts ("sched test");
     370    verify_result = verify_sched_result;
     371    RETURN_IF_FAIL (do_sched_test);
     372  
     373    puts ("affinity test");
     374    verify_result = verify_affinity_result;
     375    RETURN_IF_FAIL (do_affinity_test);
     376  
     377    puts ("detach test");
     378    verify_result = verify_detach_result;
     379    RETURN_IF_FAIL (do_detach_test);
     380  
     381    return 0;
     382  }
     383  
     384  #define TEST_FUNCTION do_test ()
     385  #include "../test-skeleton.c"