(root)/
glibc-2.38/
nptl/
pthread_getattr_np.c
       1  /* Copyright (C) 2002-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <assert.h>
      19  #include <errno.h>
      20  #include <inttypes.h>
      21  #include <stdio.h>
      22  #include <stdio_ext.h>
      23  #include <stdlib.h>
      24  #include <string.h>
      25  #include <sys/resource.h>
      26  #include "pthreadP.h"
      27  #include <lowlevellock.h>
      28  #include <ldsodefs.h>
      29  
      30  
      31  int
      32  __pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)
      33  {
      34    struct pthread *thread = (struct pthread *) thread_id;
      35  
      36    /* Prepare the new thread attribute.  */
      37    int ret = __pthread_attr_init (attr);
      38    if (ret != 0)
      39      return ret;
      40  
      41    struct pthread_attr *iattr = (struct pthread_attr *) attr;
      42  
      43    lll_lock (thread->lock, LLL_PRIVATE);
      44  
      45    /* The thread library is responsible for keeping the values in the
      46       thread descriptor up-to-date in case the user changes them.  */
      47    memcpy (&iattr->schedparam, &thread->schedparam,
      48  	  sizeof (struct sched_param));
      49    iattr->schedpolicy = thread->schedpolicy;
      50  
      51    /* Clear the flags work.  */
      52    iattr->flags = thread->flags;
      53  
      54    /* The thread might be detached by now.  */
      55    if (IS_DETACHED (thread))
      56      iattr->flags |= ATTR_FLAG_DETACHSTATE;
      57  
      58    /* This is the guardsize after adjusting it.  */
      59    iattr->guardsize = thread->reported_guardsize;
      60  
      61    /* The sizes are subject to alignment.  */
      62    if (__glibc_likely (thread->stackblock != NULL))
      63      {
      64        /* The stack size reported to the user should not include the
      65  	 guard size.  */
      66        iattr->stacksize = thread->stackblock_size - thread->guardsize;
      67  #if _STACK_GROWS_DOWN
      68        iattr->stackaddr = (char *) thread->stackblock
      69  			 + thread->stackblock_size;
      70  #else
      71        iattr->stackaddr = (char *) thread->stackblock;
      72  #endif
      73      }
      74    else
      75      {
      76        /* No stack information available.  This must be for the initial
      77  	 thread.  Get the info in some magical way.  */
      78  
      79        /* Stack size limit.  */
      80        struct rlimit rl;
      81  
      82        /* The safest way to get the top of the stack is to read
      83  	 /proc/self/maps and locate the line into which
      84  	 __libc_stack_end falls.  */
      85        FILE *fp = fopen ("/proc/self/maps", "rce");
      86        if (fp == NULL)
      87  	ret = errno;
      88        /* We need the limit of the stack in any case.  */
      89        else
      90  	{
      91  	  if (__getrlimit (RLIMIT_STACK, &rl) != 0)
      92  	    ret = errno;
      93  	  else
      94  	    {
      95  	      /* We consider the main process stack to have ended with
      96  	         the page containing __libc_stack_end.  There is stuff below
      97  		 it in the stack too, like the program arguments, environment
      98  		 variables and auxv info, but we ignore those pages when
      99  		 returning size so that the output is consistent when the
     100  		 stack is marked executable due to a loaded DSO requiring
     101  		 it.  */
     102  	      void *stack_end = (void *) ((uintptr_t) __libc_stack_end
     103  					  & -(uintptr_t) GLRO(dl_pagesize));
     104  #if _STACK_GROWS_DOWN
     105  	      stack_end += GLRO(dl_pagesize);
     106  #endif
     107  	      /* We need no locking.  */
     108  	      __fsetlocking (fp, FSETLOCKING_BYCALLER);
     109  
     110  	      /* Until we found an entry (which should always be the case)
     111  		 mark the result as a failure.  */
     112  	      ret = ENOENT;
     113  
     114  	      char *line = NULL;
     115  	      size_t linelen = 0;
     116  #if _STACK_GROWS_DOWN
     117  	      uintptr_t last_to = 0;
     118  #endif
     119  
     120  	      while (! feof_unlocked (fp))
     121  		{
     122  		  if (__getline (&line, &linelen, fp) <= 0)
     123  		    break;
     124  
     125  		  uintptr_t from;
     126  		  uintptr_t to;
     127  		  if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2)
     128  		    continue;
     129  		  if (from <= (uintptr_t) __libc_stack_end
     130  		      && (uintptr_t) __libc_stack_end < to)
     131  		    {
     132  		      /* Found the entry.  Now we have the info we need.  */
     133  		      iattr->stackaddr = stack_end;
     134  		      iattr->stacksize =
     135  		        rl.rlim_cur - (size_t) (to - (uintptr_t) stack_end);
     136  
     137  		      /* Cut it down to align it to page size since otherwise we
     138  		         risk going beyond rlimit when the kernel rounds up the
     139  		         stack extension request.  */
     140  		      iattr->stacksize = (iattr->stacksize
     141  					  & -(intptr_t) GLRO(dl_pagesize));
     142  #if _STACK_GROWS_DOWN
     143  		      /* The limit might be too high.  */
     144  		      if ((size_t) iattr->stacksize
     145  			  > (size_t) iattr->stackaddr - last_to)
     146  			iattr->stacksize = (size_t) iattr->stackaddr - last_to;
     147  #else
     148  		      /* The limit might be too high.  */
     149  		      if ((size_t) iattr->stacksize
     150  			  > to - (size_t) iattr->stackaddr)
     151  			iattr->stacksize = to - (size_t) iattr->stackaddr;
     152  #endif
     153  		      /* We succeed and no need to look further.  */
     154  		      ret = 0;
     155  		      break;
     156  		    }
     157  #if _STACK_GROWS_DOWN
     158  		  last_to = to;
     159  #endif
     160  		}
     161  
     162  	      free (line);
     163  	    }
     164  
     165  	  fclose (fp);
     166  	}
     167      }
     168  
     169    iattr->flags |= ATTR_FLAG_STACKADDR;
     170  
     171    if (ret == 0)
     172      {
     173        size_t size = 16;
     174        cpu_set_t *cpuset = NULL;
     175  
     176        do
     177  	{
     178  	  size <<= 1;
     179  
     180  	  void *newp = realloc (cpuset, size);
     181  	  if (newp == NULL)
     182  	    {
     183  	      ret = ENOMEM;
     184  	      break;
     185  	    }
     186  	  cpuset = (cpu_set_t *) newp;
     187  
     188  	  ret = __pthread_getaffinity_np (thread_id, size, cpuset);
     189  	}
     190        /* Pick some ridiculous upper limit.  Is 8 million CPUs enough?  */
     191        while (ret == EINVAL && size < 1024 * 1024);
     192  
     193        if (ret == 0)
     194  	ret = __pthread_attr_setaffinity_np (attr, size, cpuset);
     195        else if (ret == ENOSYS)
     196  	/* There is no such functionality.  */
     197  	ret = 0;
     198        free (cpuset);
     199      }
     200  
     201    lll_unlock (thread->lock, LLL_PRIVATE);
     202  
     203    if (ret != 0)
     204      __pthread_attr_destroy (attr);
     205  
     206    return ret;
     207  }
     208  versioned_symbol (libc, __pthread_getattr_np, pthread_getattr_np, GLIBC_2_32);
     209  
     210  #if SHLIB_COMPAT (libc, GLIBC_2_2_3, GLIBC_2_32)
     211  strong_alias (__pthread_getattr_np, __pthread_getattr_np_alias)
     212  compat_symbol (libc, __pthread_getattr_np_alias,
     213  	       pthread_getattr_np, GLIBC_2_2_3);
     214  #endif