Blame nptl/pthread_getattr_np.c

Packit 6c4009
/* Copyright (C) 2002-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>, 2002.
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 <assert.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <inttypes.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdio_ext.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <sys/resource.h>
Packit 6c4009
#include "pthreadP.h"
Packit 6c4009
#include <lowlevellock.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)
Packit 6c4009
{
Packit 6c4009
  struct pthread *thread = (struct pthread *) thread_id;
Packit 6c4009
  struct pthread_attr *iattr = (struct pthread_attr *) attr;
Packit 6c4009
  int ret = 0;
Packit 6c4009
Packit 6c4009
  lll_lock (thread->lock, LLL_PRIVATE);
Packit 6c4009
Packit 6c4009
  /* The thread library is responsible for keeping the values in the
Packit 6c4009
     thread desriptor up-to-date in case the user changes them.  */
Packit 6c4009
  memcpy (&iattr->schedparam, &thread->schedparam,
Packit 6c4009
	  sizeof (struct sched_param));
Packit 6c4009
  iattr->schedpolicy = thread->schedpolicy;
Packit 6c4009
Packit 6c4009
  /* Clear the flags work.  */
Packit 6c4009
  iattr->flags = thread->flags;
Packit 6c4009
Packit 6c4009
  /* The thread might be detached by now.  */
Packit 6c4009
  if (IS_DETACHED (thread))
Packit 6c4009
    iattr->flags |= ATTR_FLAG_DETACHSTATE;
Packit 6c4009
Packit 6c4009
  /* This is the guardsize after adjusting it.  */
Packit 6c4009
  iattr->guardsize = thread->reported_guardsize;
Packit 6c4009
Packit 6c4009
  /* The sizes are subject to alignment.  */
Packit 6c4009
  if (__glibc_likely (thread->stackblock != NULL))
Packit 6c4009
    {
Packit 6c4009
      /* The stack size reported to the user should not include the
Packit 6c4009
	 guard size.  */
Packit 6c4009
      iattr->stacksize = thread->stackblock_size - thread->guardsize;
Packit 6c4009
#if _STACK_GROWS_DOWN
Packit 6c4009
      iattr->stackaddr = (char *) thread->stackblock
Packit 6c4009
			 + thread->stackblock_size;
Packit 6c4009
#else
Packit 6c4009
      iattr->stackaddr = (char *) thread->stackblock;
Packit 6c4009
#endif
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* No stack information available.  This must be for the initial
Packit 6c4009
	 thread.  Get the info in some magical way.  */
Packit 6c4009
Packit 6c4009
      /* Stack size limit.  */
Packit 6c4009
      struct rlimit rl;
Packit 6c4009
Packit 6c4009
      /* The safest way to get the top of the stack is to read
Packit 6c4009
	 /proc/self/maps and locate the line into which
Packit 6c4009
	 __libc_stack_end falls.  */
Packit 6c4009
      FILE *fp = fopen ("/proc/self/maps", "rce");
Packit 6c4009
      if (fp == NULL)
Packit 6c4009
	ret = errno;
Packit 6c4009
      /* We need the limit of the stack in any case.  */
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  if (getrlimit (RLIMIT_STACK, &rl) != 0)
Packit 6c4009
	    ret = errno;
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      /* We consider the main process stack to have ended with
Packit 6c4009
	         the page containing __libc_stack_end.  There is stuff below
Packit 6c4009
		 it in the stack too, like the program arguments, environment
Packit 6c4009
		 variables and auxv info, but we ignore those pages when
Packit 6c4009
		 returning size so that the output is consistent when the
Packit 6c4009
		 stack is marked executable due to a loaded DSO requiring
Packit 6c4009
		 it.  */
Packit 6c4009
	      void *stack_end = (void *) ((uintptr_t) __libc_stack_end
Packit 6c4009
					  & -(uintptr_t) GLRO(dl_pagesize));
Packit 6c4009
#if _STACK_GROWS_DOWN
Packit 6c4009
	      stack_end += GLRO(dl_pagesize);
Packit 6c4009
#endif
Packit 6c4009
	      /* We need no locking.  */
Packit 6c4009
	      __fsetlocking (fp, FSETLOCKING_BYCALLER);
Packit 6c4009
Packit 6c4009
	      /* Until we found an entry (which should always be the case)
Packit 6c4009
		 mark the result as a failure.  */
Packit 6c4009
	      ret = ENOENT;
Packit 6c4009
Packit 6c4009
	      char *line = NULL;
Packit 6c4009
	      size_t linelen = 0;
Packit 6c4009
#if _STACK_GROWS_DOWN
Packit 6c4009
	      uintptr_t last_to = 0;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	      while (! feof_unlocked (fp))
Packit 6c4009
		{
Packit 6c4009
		  if (__getdelim (&line, &linelen, '\n', fp) <= 0)
Packit 6c4009
		    break;
Packit 6c4009
Packit 6c4009
		  uintptr_t from;
Packit 6c4009
		  uintptr_t to;
Packit 6c4009
		  if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2)
Packit 6c4009
		    continue;
Packit 6c4009
		  if (from <= (uintptr_t) __libc_stack_end
Packit 6c4009
		      && (uintptr_t) __libc_stack_end < to)
Packit 6c4009
		    {
Packit 6c4009
		      /* Found the entry.  Now we have the info we need.  */
Packit 6c4009
		      iattr->stackaddr = stack_end;
Packit 6c4009
		      iattr->stacksize =
Packit 6c4009
		        rl.rlim_cur - (size_t) (to - (uintptr_t) stack_end);
Packit 6c4009
Packit 6c4009
		      /* Cut it down to align it to page size since otherwise we
Packit 6c4009
		         risk going beyond rlimit when the kernel rounds up the
Packit 6c4009
		         stack extension request.  */
Packit 6c4009
		      iattr->stacksize = (iattr->stacksize
Packit 6c4009
					  & -(intptr_t) GLRO(dl_pagesize));
Packit 6c4009
#if _STACK_GROWS_DOWN
Packit 6c4009
		      /* The limit might be too high.  */
Packit 6c4009
		      if ((size_t) iattr->stacksize
Packit 6c4009
			  > (size_t) iattr->stackaddr - last_to)
Packit 6c4009
			iattr->stacksize = (size_t) iattr->stackaddr - last_to;
Packit 6c4009
#else
Packit 6c4009
		      /* The limit might be too high.  */
Packit 6c4009
		      if ((size_t) iattr->stacksize
Packit 6c4009
			  > to - (size_t) iattr->stackaddr)
Packit 6c4009
			iattr->stacksize = to - (size_t) iattr->stackaddr;
Packit 6c4009
#endif
Packit 6c4009
		      /* We succeed and no need to look further.  */
Packit 6c4009
		      ret = 0;
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
#if _STACK_GROWS_DOWN
Packit 6c4009
		  last_to = to;
Packit 6c4009
#endif
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      free (line);
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  fclose (fp);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  iattr->flags |= ATTR_FLAG_STACKADDR;
Packit 6c4009
Packit 6c4009
  if (ret == 0)
Packit 6c4009
    {
Packit 6c4009
      size_t size = 16;
Packit 6c4009
      cpu_set_t *cpuset = NULL;
Packit 6c4009
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  size <<= 1;
Packit 6c4009
Packit 6c4009
	  void *newp = realloc (cpuset, size);
Packit 6c4009
	  if (newp == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      ret = ENOMEM;
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  cpuset = (cpu_set_t *) newp;
Packit 6c4009
Packit 6c4009
	  ret = __pthread_getaffinity_np (thread_id, size, cpuset);
Packit 6c4009
	}
Packit 6c4009
      /* Pick some ridiculous upper limit.  Is 8 million CPUs enough?  */
Packit 6c4009
      while (ret == EINVAL && size < 1024 * 1024);
Packit 6c4009
Packit 6c4009
      if (ret == 0)
Packit 6c4009
	{
Packit 6c4009
	  iattr->cpuset = cpuset;
Packit 6c4009
	  iattr->cpusetsize = size;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  free (cpuset);
Packit 6c4009
	  if (ret == ENOSYS)
Packit 6c4009
	    {
Packit 6c4009
	      /* There is no such functionality.  */
Packit 6c4009
	      ret = 0;
Packit 6c4009
	      iattr->cpuset = NULL;
Packit 6c4009
	      iattr->cpusetsize = 0;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  lll_unlock (thread->lock, LLL_PRIVATE);
Packit 6c4009
Packit 6c4009
  return ret;
Packit 6c4009
}