Blame malloc/arena.c

Packit Service 82fcde
/* Malloc implementation for multiple threads without lock contention.
Packit Service 82fcde
   Copyright (C) 2001-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public License as
Packit Service 82fcde
   published by the Free Software Foundation; either version 2.1 of the
Packit Service 82fcde
   License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; see the file COPYING.LIB.  If
Packit Service 82fcde
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <stdbool.h>
Packit Service 82fcde
Packit Service 82fcde
#if HAVE_TUNABLES
Packit Service 82fcde
# define TUNABLE_NAMESPACE malloc
Packit Service 82fcde
#endif
Packit Service 82fcde
#include <elf/dl-tunables.h>
Packit Service 82fcde
Packit Service 82fcde
/* Compile-time constants.  */
Packit Service 82fcde
Packit Service 82fcde
#define HEAP_MIN_SIZE (32 * 1024)
Packit Service 82fcde
#ifndef HEAP_MAX_SIZE
Packit Service 82fcde
# ifdef DEFAULT_MMAP_THRESHOLD_MAX
Packit Service 82fcde
#  define HEAP_MAX_SIZE (2 * DEFAULT_MMAP_THRESHOLD_MAX)
Packit Service 82fcde
# else
Packit Service 82fcde
#  define HEAP_MAX_SIZE (1024 * 1024) /* must be a power of two */
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* HEAP_MIN_SIZE and HEAP_MAX_SIZE limit the size of mmap()ed heaps
Packit Service 82fcde
   that are dynamically created for multi-threaded programs.  The
Packit Service 82fcde
   maximum size must be a power of two, for fast determination of
Packit Service 82fcde
   which heap belongs to a chunk.  It should be much larger than the
Packit Service 82fcde
   mmap threshold, so that requests with a size just below that
Packit Service 82fcde
   threshold can be fulfilled without creating too many heaps.  */
Packit Service 82fcde
Packit Service 82fcde
/***************************************************************************/
Packit Service 82fcde
Packit Service 82fcde
#define top(ar_ptr) ((ar_ptr)->top)
Packit Service 82fcde
Packit Service 82fcde
/* A heap is a single contiguous memory region holding (coalesceable)
Packit Service 82fcde
   malloc_chunks.  It is allocated with mmap() and always starts at an
Packit Service 82fcde
   address aligned to HEAP_MAX_SIZE.  */
Packit Service 82fcde
Packit Service 82fcde
typedef struct _heap_info
Packit Service 82fcde
{
Packit Service 82fcde
  mstate ar_ptr; /* Arena for this heap. */
Packit Service 82fcde
  struct _heap_info *prev; /* Previous heap. */
Packit Service 82fcde
  size_t size;   /* Current size in bytes. */
Packit Service 82fcde
  size_t mprotect_size; /* Size in bytes that has been mprotected
Packit Service 82fcde
                           PROT_READ|PROT_WRITE.  */
Packit Service 82fcde
  /* Make sure the following data is properly aligned, particularly
Packit Service 82fcde
     that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
Packit Service 82fcde
     MALLOC_ALIGNMENT. */
Packit Service 82fcde
  char pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK];
Packit Service 82fcde
} heap_info;
Packit Service 82fcde
Packit Service 82fcde
/* Get a compile-time error if the heap_info padding is not correct
Packit Service 82fcde
   to make alignment work as expected in sYSMALLOc.  */
Packit Service 82fcde
extern int sanity_check_heap_info_alignment[(sizeof (heap_info)
Packit Service 82fcde
                                             + 2 * SIZE_SZ) % MALLOC_ALIGNMENT
Packit Service 82fcde
                                            ? -1 : 1];
Packit Service 82fcde
Packit Service 82fcde
/* Thread specific data.  */
Packit Service 82fcde
Packit Service 82fcde
static __thread mstate thread_arena attribute_tls_model_ie;
Packit Service 82fcde
Packit Service 82fcde
/* Arena free list.  free_list_lock synchronizes access to the
Packit Service 82fcde
   free_list variable below, and the next_free and attached_threads
Packit Service 82fcde
   members of struct malloc_state objects.  No other locks must be
Packit Service 82fcde
   acquired after free_list_lock has been acquired.  */
Packit Service 82fcde
Packit Service 82fcde
__libc_lock_define_initialized (static, free_list_lock);
Packit Service 82fcde
static size_t narenas = 1;
Packit Service 82fcde
static mstate free_list;
Packit Service 82fcde
Packit Service 82fcde
/* list_lock prevents concurrent writes to the next member of struct
Packit Service 82fcde
   malloc_state objects.
Packit Service 82fcde
Packit Service 82fcde
   Read access to the next member is supposed to synchronize with the
Packit Service 82fcde
   atomic_write_barrier and the write to the next member in
Packit Service 82fcde
   _int_new_arena.  This suffers from data races; see the FIXME
Packit Service 82fcde
   comments in _int_new_arena and reused_arena.
Packit Service 82fcde
Packit Service 82fcde
   list_lock also prevents concurrent forks.  At the time list_lock is
Packit Service 82fcde
   acquired, no arena lock must have been acquired, but it is
Packit Service 82fcde
   permitted to acquire arena locks subsequently, while list_lock is
Packit Service 82fcde
   acquired.  */
Packit Service 82fcde
__libc_lock_define_initialized (static, list_lock);
Packit Service 82fcde
Packit Service 82fcde
/* Already initialized? */
Packit Service 82fcde
int __malloc_initialized = -1;
Packit Service 82fcde
Packit Service 82fcde
/**************************************************************************/
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* arena_get() acquires an arena and locks the corresponding mutex.
Packit Service 82fcde
   First, try the one last locked successfully by this thread.  (This
Packit Service 82fcde
   is the common case and handled with a macro for speed.)  Then, loop
Packit Service 82fcde
   once over the circularly linked list of arenas.  If no arena is
Packit Service 82fcde
   readily available, create a new one.  In this latter case, `size'
Packit Service 82fcde
   is just a hint as to how much memory will be required immediately
Packit Service 82fcde
   in the new arena. */
Packit Service 82fcde
Packit Service 82fcde
#define arena_get(ptr, size) do { \
Packit Service 82fcde
      ptr = thread_arena;						      \
Packit Service 82fcde
      arena_lock (ptr, size);						      \
Packit Service 82fcde
  } while (0)
Packit Service 82fcde
Packit Service 82fcde
#define arena_lock(ptr, size) do {					      \
Packit Service 82fcde
      if (ptr)								      \
Packit Service 82fcde
        __libc_lock_lock (ptr->mutex);					      \
Packit Service 82fcde
      else								      \
Packit Service 82fcde
        ptr = arena_get2 ((size), NULL);				      \
Packit Service 82fcde
  } while (0)
Packit Service 82fcde
Packit Service 82fcde
/* find the heap and corresponding arena for a given ptr */
Packit Service 82fcde
Packit Service 82fcde
#define heap_for_ptr(ptr) \
Packit Service 82fcde
  ((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1)))
Packit Service 82fcde
#define arena_for_chunk(ptr) \
Packit Service 82fcde
  (chunk_main_arena (ptr) ? &main_arena : heap_for_ptr (ptr)->ar_ptr)
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/**************************************************************************/
Packit Service 82fcde
Packit Service 82fcde
/* atfork support.  */
Packit Service 82fcde
Packit Service 82fcde
/* The following three functions are called around fork from a
Packit Service 82fcde
   multi-threaded process.  We do not use the general fork handler
Packit Service 82fcde
   mechanism to make sure that our handlers are the last ones being
Packit Service 82fcde
   called, so that other fork handlers can use the malloc
Packit Service 82fcde
   subsystem.  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
__malloc_fork_lock_parent (void)
Packit Service 82fcde
{
Packit Service 82fcde
  if (__malloc_initialized < 1)
Packit Service 82fcde
    return;
Packit Service 82fcde
Packit Service 82fcde
  /* We do not acquire free_list_lock here because we completely
Packit Service 82fcde
     reconstruct free_list in __malloc_fork_unlock_child.  */
Packit Service 82fcde
Packit Service 82fcde
  __libc_lock_lock (list_lock);
Packit Service 82fcde
Packit Service 82fcde
  for (mstate ar_ptr = &main_arena;; )
Packit Service 82fcde
    {
Packit Service 82fcde
      __libc_lock_lock (ar_ptr->mutex);
Packit Service 82fcde
      ar_ptr = ar_ptr->next;
Packit Service 82fcde
      if (ar_ptr == &main_arena)
Packit Service 82fcde
        break;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
__malloc_fork_unlock_parent (void)
Packit Service 82fcde
{
Packit Service 82fcde
  if (__malloc_initialized < 1)
Packit Service 82fcde
    return;
Packit Service 82fcde
Packit Service 82fcde
  for (mstate ar_ptr = &main_arena;; )
Packit Service 82fcde
    {
Packit Service 82fcde
      __libc_lock_unlock (ar_ptr->mutex);
Packit Service 82fcde
      ar_ptr = ar_ptr->next;
Packit Service 82fcde
      if (ar_ptr == &main_arena)
Packit Service 82fcde
        break;
Packit Service 82fcde
    }
Packit Service 82fcde
  __libc_lock_unlock (list_lock);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
__malloc_fork_unlock_child (void)
Packit Service 82fcde
{
Packit Service 82fcde
  if (__malloc_initialized < 1)
Packit Service 82fcde
    return;
Packit Service 82fcde
Packit Service 82fcde
  /* Push all arenas to the free list, except thread_arena, which is
Packit Service 82fcde
     attached to the current thread.  */
Packit Service 82fcde
  __libc_lock_init (free_list_lock);
Packit Service 82fcde
  if (thread_arena != NULL)
Packit Service 82fcde
    thread_arena->attached_threads = 1;
Packit Service 82fcde
  free_list = NULL;
Packit Service 82fcde
  for (mstate ar_ptr = &main_arena;; )
Packit Service 82fcde
    {
Packit Service 82fcde
      __libc_lock_init (ar_ptr->mutex);
Packit Service 82fcde
      if (ar_ptr != thread_arena)
Packit Service 82fcde
        {
Packit Service 82fcde
	  /* This arena is no longer attached to any thread.  */
Packit Service 82fcde
	  ar_ptr->attached_threads = 0;
Packit Service 82fcde
          ar_ptr->next_free = free_list;
Packit Service 82fcde
          free_list = ar_ptr;
Packit Service 82fcde
        }
Packit Service 82fcde
      ar_ptr = ar_ptr->next;
Packit Service 82fcde
      if (ar_ptr == &main_arena)
Packit Service 82fcde
        break;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  __libc_lock_init (list_lock);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#if HAVE_TUNABLES
Packit Service 82fcde
static inline int do_set_mallopt_check (int32_t value);
Packit Service 82fcde
void
Packit Service 82fcde
TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp)
Packit Service 82fcde
{
Packit Service 82fcde
  int32_t value = (int32_t) valp->numval;
Packit Service 82fcde
  if (value != 0)
Packit Service 82fcde
    __malloc_check_init ();
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
# define TUNABLE_CALLBACK_FNDECL(__name, __type) \
Packit Service 82fcde
static inline int do_ ## __name (__type value);				      \
Packit Service 82fcde
void									      \
Packit Service 82fcde
TUNABLE_CALLBACK (__name) (tunable_val_t *valp)				      \
Packit Service 82fcde
{									      \
Packit Service 82fcde
  __type value = (__type) (valp)->numval;				      \
Packit Service 82fcde
  do_ ## __name (value);						      \
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
TUNABLE_CALLBACK_FNDECL (set_mmap_threshold, size_t)
Packit Service 82fcde
TUNABLE_CALLBACK_FNDECL (set_mmaps_max, int32_t)
Packit Service 82fcde
TUNABLE_CALLBACK_FNDECL (set_top_pad, size_t)
Packit Service 82fcde
TUNABLE_CALLBACK_FNDECL (set_perturb_byte, int32_t)
Packit Service 82fcde
TUNABLE_CALLBACK_FNDECL (set_trim_threshold, size_t)
Packit Service 82fcde
TUNABLE_CALLBACK_FNDECL (set_arena_max, size_t)
Packit Service 82fcde
TUNABLE_CALLBACK_FNDECL (set_arena_test, size_t)
Packit Service 82fcde
#if USE_TCACHE
Packit Service 82fcde
TUNABLE_CALLBACK_FNDECL (set_tcache_max, size_t)
Packit Service 82fcde
TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t)
Packit Service 82fcde
TUNABLE_CALLBACK_FNDECL (set_tcache_unsorted_limit, size_t)
Packit Service 82fcde
#endif
Packit Service 82fcde
#else
Packit Service 82fcde
/* Initialization routine. */
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
extern char **_environ;
Packit Service 82fcde
Packit Service 82fcde
static char *
Packit Service 82fcde
next_env_entry (char ***position)
Packit Service 82fcde
{
Packit Service 82fcde
  char **current = *position;
Packit Service 82fcde
  char *result = NULL;
Packit Service 82fcde
Packit Service 82fcde
  while (*current != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (__builtin_expect ((*current)[0] == 'M', 0)
Packit Service 82fcde
          && (*current)[1] == 'A'
Packit Service 82fcde
          && (*current)[2] == 'L'
Packit Service 82fcde
          && (*current)[3] == 'L'
Packit Service 82fcde
          && (*current)[4] == 'O'
Packit Service 82fcde
          && (*current)[5] == 'C'
Packit Service 82fcde
          && (*current)[6] == '_')
Packit Service 82fcde
        {
Packit Service 82fcde
          result = &(*current)[7];
Packit Service 82fcde
Packit Service 82fcde
          /* Save current position for next visit.  */
Packit Service 82fcde
          *position = ++current;
Packit Service 82fcde
Packit Service 82fcde
          break;
Packit Service 82fcde
        }
Packit Service 82fcde
Packit Service 82fcde
      ++current;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
static void *
Packit Service 82fcde
__failing_morecore (ptrdiff_t d)
Packit Service 82fcde
{
Packit Service 82fcde
  return (void *) MORECORE_FAILURE;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
extern struct dl_open_hook *_dl_open_hook;
Packit Service 82fcde
libc_hidden_proto (_dl_open_hook);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
ptmalloc_init (void)
Packit Service 82fcde
{
Packit Service 82fcde
  if (__malloc_initialized >= 0)
Packit Service 82fcde
    return;
Packit Service 82fcde
Packit Service 82fcde
  __malloc_initialized = 0;
Packit Service 82fcde
Packit Service 82fcde
#ifdef SHARED
Packit Service 82fcde
  /* In case this libc copy is in a non-default namespace, never use brk.
Packit Service 82fcde
     Likewise if dlopened from statically linked program.  */
Packit Service 82fcde
  Dl_info di;
Packit Service 82fcde
  struct link_map *l;
Packit Service 82fcde
Packit Service 82fcde
  if (_dl_open_hook != NULL
Packit Service 82fcde
      || (_dl_addr (ptmalloc_init, &di, &l, NULL) != 0
Packit Service 82fcde
          && l->l_ns != LM_ID_BASE))
Packit Service 82fcde
    __morecore = __failing_morecore;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  thread_arena = &main_arena;
Packit Service 82fcde
Packit Service 82fcde
  malloc_init_state (&main_arena);
Packit Service 82fcde
Packit Service 82fcde
#if HAVE_TUNABLES
Packit Service 82fcde
  TUNABLE_GET (check, int32_t, TUNABLE_CALLBACK (set_mallopt_check));
Packit Service 82fcde
  TUNABLE_GET (top_pad, size_t, TUNABLE_CALLBACK (set_top_pad));
Packit Service 82fcde
  TUNABLE_GET (perturb, int32_t, TUNABLE_CALLBACK (set_perturb_byte));
Packit Service 82fcde
  TUNABLE_GET (mmap_threshold, size_t, TUNABLE_CALLBACK (set_mmap_threshold));
Packit Service 82fcde
  TUNABLE_GET (trim_threshold, size_t, TUNABLE_CALLBACK (set_trim_threshold));
Packit Service 82fcde
  TUNABLE_GET (mmap_max, int32_t, TUNABLE_CALLBACK (set_mmaps_max));
Packit Service 82fcde
  TUNABLE_GET (arena_max, size_t, TUNABLE_CALLBACK (set_arena_max));
Packit Service 82fcde
  TUNABLE_GET (arena_test, size_t, TUNABLE_CALLBACK (set_arena_test));
Packit Service 82fcde
# if USE_TCACHE
Packit Service 82fcde
  TUNABLE_GET (tcache_max, size_t, TUNABLE_CALLBACK (set_tcache_max));
Packit Service 82fcde
  TUNABLE_GET (tcache_count, size_t, TUNABLE_CALLBACK (set_tcache_count));
Packit Service 82fcde
  TUNABLE_GET (tcache_unsorted_limit, size_t,
Packit Service 82fcde
	       TUNABLE_CALLBACK (set_tcache_unsorted_limit));
Packit Service 82fcde
# endif
Packit Service 82fcde
#else
Packit Service 82fcde
  const char *s = NULL;
Packit Service 82fcde
  if (__glibc_likely (_environ != NULL))
Packit Service 82fcde
    {
Packit Service 82fcde
      char **runp = _environ;
Packit Service 82fcde
      char *envline;
Packit Service 82fcde
Packit Service 82fcde
      while (__builtin_expect ((envline = next_env_entry (&runp)) != NULL,
Packit Service 82fcde
                               0))
Packit Service 82fcde
        {
Packit Service 82fcde
          size_t len = strcspn (envline, "=");
Packit Service 82fcde
Packit Service 82fcde
          if (envline[len] != '=')
Packit Service 82fcde
            /* This is a "MALLOC_" variable at the end of the string
Packit Service 82fcde
               without a '=' character.  Ignore it since otherwise we
Packit Service 82fcde
               will access invalid memory below.  */
Packit Service 82fcde
            continue;
Packit Service 82fcde
Packit Service 82fcde
          switch (len)
Packit Service 82fcde
            {
Packit Service 82fcde
            case 6:
Packit Service 82fcde
              if (memcmp (envline, "CHECK_", 6) == 0)
Packit Service 82fcde
                s = &envline[7];
Packit Service 82fcde
              break;
Packit Service 82fcde
            case 8:
Packit Service 82fcde
              if (!__builtin_expect (__libc_enable_secure, 0))
Packit Service 82fcde
                {
Packit Service 82fcde
                  if (memcmp (envline, "TOP_PAD_", 8) == 0)
Packit Service 82fcde
                    __libc_mallopt (M_TOP_PAD, atoi (&envline[9]));
Packit Service 82fcde
                  else if (memcmp (envline, "PERTURB_", 8) == 0)
Packit Service 82fcde
                    __libc_mallopt (M_PERTURB, atoi (&envline[9]));
Packit Service 82fcde
                }
Packit Service 82fcde
              break;
Packit Service 82fcde
            case 9:
Packit Service 82fcde
              if (!__builtin_expect (__libc_enable_secure, 0))
Packit Service 82fcde
                {
Packit Service 82fcde
                  if (memcmp (envline, "MMAP_MAX_", 9) == 0)
Packit Service 82fcde
                    __libc_mallopt (M_MMAP_MAX, atoi (&envline[10]));
Packit Service 82fcde
                  else if (memcmp (envline, "ARENA_MAX", 9) == 0)
Packit Service 82fcde
                    __libc_mallopt (M_ARENA_MAX, atoi (&envline[10]));
Packit Service 82fcde
                }
Packit Service 82fcde
              break;
Packit Service 82fcde
            case 10:
Packit Service 82fcde
              if (!__builtin_expect (__libc_enable_secure, 0))
Packit Service 82fcde
                {
Packit Service 82fcde
                  if (memcmp (envline, "ARENA_TEST", 10) == 0)
Packit Service 82fcde
                    __libc_mallopt (M_ARENA_TEST, atoi (&envline[11]));
Packit Service 82fcde
                }
Packit Service 82fcde
              break;
Packit Service 82fcde
            case 15:
Packit Service 82fcde
              if (!__builtin_expect (__libc_enable_secure, 0))
Packit Service 82fcde
                {
Packit Service 82fcde
                  if (memcmp (envline, "TRIM_THRESHOLD_", 15) == 0)
Packit Service 82fcde
                    __libc_mallopt (M_TRIM_THRESHOLD, atoi (&envline[16]));
Packit Service 82fcde
                  else if (memcmp (envline, "MMAP_THRESHOLD_", 15) == 0)
Packit Service 82fcde
                    __libc_mallopt (M_MMAP_THRESHOLD, atoi (&envline[16]));
Packit Service 82fcde
                }
Packit Service 82fcde
              break;
Packit Service 82fcde
            default:
Packit Service 82fcde
              break;
Packit Service 82fcde
            }
Packit Service 82fcde
        }
Packit Service 82fcde
    }
Packit Service 82fcde
  if (s && s[0] != '\0' && s[0] != '0')
Packit Service 82fcde
    __malloc_check_init ();
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#if HAVE_MALLOC_INIT_HOOK
Packit Service 82fcde
  void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);
Packit Service 82fcde
  if (hook != NULL)
Packit Service 82fcde
    (*hook)();
Packit Service 82fcde
#endif
Packit Service 82fcde
  __malloc_initialized = 1;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Managing heaps and arenas (for concurrent threads) */
Packit Service 82fcde
Packit Service 82fcde
#if MALLOC_DEBUG > 1
Packit Service 82fcde
Packit Service 82fcde
/* Print the complete contents of a single heap to stderr. */
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
dump_heap (heap_info *heap)
Packit Service 82fcde
{
Packit Service 82fcde
  char *ptr;
Packit Service 82fcde
  mchunkptr p;
Packit Service 82fcde
Packit Service 82fcde
  fprintf (stderr, "Heap %p, size %10lx:\n", heap, (long) heap->size);
Packit Service 82fcde
  ptr = (heap->ar_ptr != (mstate) (heap + 1)) ?
Packit Service 82fcde
        (char *) (heap + 1) : (char *) (heap + 1) + sizeof (struct malloc_state);
Packit Service 82fcde
  p = (mchunkptr) (((unsigned long) ptr + MALLOC_ALIGN_MASK) &
Packit Service 82fcde
                   ~MALLOC_ALIGN_MASK);
Packit Service 82fcde
  for (;; )
Packit Service 82fcde
    {
Packit Service 82fcde
      fprintf (stderr, "chunk %p size %10lx", p, (long) p->size);
Packit Service 82fcde
      if (p == top (heap->ar_ptr))
Packit Service 82fcde
        {
Packit Service 82fcde
          fprintf (stderr, " (top)\n");
Packit Service 82fcde
          break;
Packit Service 82fcde
        }
Packit Service 82fcde
      else if (p->size == (0 | PREV_INUSE))
Packit Service 82fcde
        {
Packit Service 82fcde
          fprintf (stderr, " (fence)\n");
Packit Service 82fcde
          break;
Packit Service 82fcde
        }
Packit Service 82fcde
      fprintf (stderr, "\n");
Packit Service 82fcde
      p = next_chunk (p);
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
#endif /* MALLOC_DEBUG > 1 */
Packit Service 82fcde
Packit Service 82fcde
/* If consecutive mmap (0, HEAP_MAX_SIZE << 1, ...) calls return decreasing
Packit Service 82fcde
   addresses as opposed to increasing, new_heap would badly fragment the
Packit Service 82fcde
   address space.  In that case remember the second HEAP_MAX_SIZE part
Packit Service 82fcde
   aligned to HEAP_MAX_SIZE from last mmap (0, HEAP_MAX_SIZE << 1, ...)
Packit Service 82fcde
   call (if it is already aligned) and try to reuse it next time.  We need
Packit Service 82fcde
   no locking for it, as kernel ensures the atomicity for us - worst case
Packit Service 82fcde
   we'll call mmap (addr, HEAP_MAX_SIZE, ...) for some value of addr in
Packit Service 82fcde
   multiple threads, but only one will succeed.  */
Packit Service 82fcde
static char *aligned_heap_area;
Packit Service 82fcde
Packit Service 82fcde
/* Create a new heap.  size is automatically rounded up to a multiple
Packit Service 82fcde
   of the page size. */
Packit Service 82fcde
Packit Service 82fcde
static heap_info *
Packit Service 82fcde
new_heap (size_t size, size_t top_pad)
Packit Service 82fcde
{
Packit Service 82fcde
  size_t pagesize = GLRO (dl_pagesize);
Packit Service 82fcde
  char *p1, *p2;
Packit Service 82fcde
  unsigned long ul;
Packit Service 82fcde
  heap_info *h;
Packit Service 82fcde
Packit Service 82fcde
  if (size + top_pad < HEAP_MIN_SIZE)
Packit Service 82fcde
    size = HEAP_MIN_SIZE;
Packit Service 82fcde
  else if (size + top_pad <= HEAP_MAX_SIZE)
Packit Service 82fcde
    size += top_pad;
Packit Service 82fcde
  else if (size > HEAP_MAX_SIZE)
Packit Service 82fcde
    return 0;
Packit Service 82fcde
  else
Packit Service 82fcde
    size = HEAP_MAX_SIZE;
Packit Service 82fcde
  size = ALIGN_UP (size, pagesize);
Packit Service 82fcde
Packit Service 82fcde
  /* A memory region aligned to a multiple of HEAP_MAX_SIZE is needed.
Packit Service 82fcde
     No swap space needs to be reserved for the following large
Packit Service 82fcde
     mapping (on Linux, this is the case for all non-writable mappings
Packit Service 82fcde
     anyway). */
Packit Service 82fcde
  p2 = MAP_FAILED;
Packit Service 82fcde
  if (aligned_heap_area)
Packit Service 82fcde
    {
Packit Service 82fcde
      p2 = (char *) MMAP (aligned_heap_area, HEAP_MAX_SIZE, PROT_NONE,
Packit Service 82fcde
                          MAP_NORESERVE);
Packit Service 82fcde
      aligned_heap_area = NULL;
Packit Service 82fcde
      if (p2 != MAP_FAILED && ((unsigned long) p2 & (HEAP_MAX_SIZE - 1)))
Packit Service 82fcde
        {
Packit Service 82fcde
          __munmap (p2, HEAP_MAX_SIZE);
Packit Service 82fcde
          p2 = MAP_FAILED;
Packit Service 82fcde
        }
Packit Service 82fcde
    }
Packit Service 82fcde
  if (p2 == MAP_FAILED)
Packit Service 82fcde
    {
Packit Service 82fcde
      p1 = (char *) MMAP (0, HEAP_MAX_SIZE << 1, PROT_NONE, MAP_NORESERVE);
Packit Service 82fcde
      if (p1 != MAP_FAILED)
Packit Service 82fcde
        {
Packit Service 82fcde
          p2 = (char *) (((unsigned long) p1 + (HEAP_MAX_SIZE - 1))
Packit Service 82fcde
                         & ~(HEAP_MAX_SIZE - 1));
Packit Service 82fcde
          ul = p2 - p1;
Packit Service 82fcde
          if (ul)
Packit Service 82fcde
            __munmap (p1, ul);
Packit Service 82fcde
          else
Packit Service 82fcde
            aligned_heap_area = p2 + HEAP_MAX_SIZE;
Packit Service 82fcde
          __munmap (p2 + HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul);
Packit Service 82fcde
        }
Packit Service 82fcde
      else
Packit Service 82fcde
        {
Packit Service 82fcde
          /* Try to take the chance that an allocation of only HEAP_MAX_SIZE
Packit Service 82fcde
             is already aligned. */
Packit Service 82fcde
          p2 = (char *) MMAP (0, HEAP_MAX_SIZE, PROT_NONE, MAP_NORESERVE);
Packit Service 82fcde
          if (p2 == MAP_FAILED)
Packit Service 82fcde
            return 0;
Packit Service 82fcde
Packit Service 82fcde
          if ((unsigned long) p2 & (HEAP_MAX_SIZE - 1))
Packit Service 82fcde
            {
Packit Service 82fcde
              __munmap (p2, HEAP_MAX_SIZE);
Packit Service 82fcde
              return 0;
Packit Service 82fcde
            }
Packit Service 82fcde
        }
Packit Service 82fcde
    }
Packit Service 82fcde
  if (__mprotect (p2, size, PROT_READ | PROT_WRITE) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      __munmap (p2, HEAP_MAX_SIZE);
Packit Service 82fcde
      return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
  h = (heap_info *) p2;
Packit Service 82fcde
  h->size = size;
Packit Service 82fcde
  h->mprotect_size = size;
Packit Service 82fcde
  LIBC_PROBE (memory_heap_new, 2, h, h->size);
Packit Service 82fcde
  return h;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Grow a heap.  size is automatically rounded up to a
Packit Service 82fcde
   multiple of the page size. */
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
grow_heap (heap_info *h, long diff)
Packit Service 82fcde
{
Packit Service 82fcde
  size_t pagesize = GLRO (dl_pagesize);
Packit Service 82fcde
  long new_size;
Packit Service 82fcde
Packit Service 82fcde
  diff = ALIGN_UP (diff, pagesize);
Packit Service 82fcde
  new_size = (long) h->size + diff;
Packit Service 82fcde
  if ((unsigned long) new_size > (unsigned long) HEAP_MAX_SIZE)
Packit Service 82fcde
    return -1;
Packit Service 82fcde
Packit Service 82fcde
  if ((unsigned long) new_size > h->mprotect_size)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (__mprotect ((char *) h + h->mprotect_size,
Packit Service 82fcde
                      (unsigned long) new_size - h->mprotect_size,
Packit Service 82fcde
                      PROT_READ | PROT_WRITE) != 0)
Packit Service 82fcde
        return -2;
Packit Service 82fcde
Packit Service 82fcde
      h->mprotect_size = new_size;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  h->size = new_size;
Packit Service 82fcde
  LIBC_PROBE (memory_heap_more, 2, h, h->size);
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Shrink a heap.  */
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
shrink_heap (heap_info *h, long diff)
Packit Service 82fcde
{
Packit Service 82fcde
  long new_size;
Packit Service 82fcde
Packit Service 82fcde
  new_size = (long) h->size - diff;
Packit Service 82fcde
  if (new_size < (long) sizeof (*h))
Packit Service 82fcde
    return -1;
Packit Service 82fcde
Packit Service 82fcde
  /* Try to re-map the extra heap space freshly to save memory, and make it
Packit Service 82fcde
     inaccessible.  See malloc-sysdep.h to know when this is true.  */
Packit Service 82fcde
  if (__glibc_unlikely (check_may_shrink_heap ()))
Packit Service 82fcde
    {
Packit Service 82fcde
      if ((char *) MMAP ((char *) h + new_size, diff, PROT_NONE,
Packit Service 82fcde
                         MAP_FIXED) == (char *) MAP_FAILED)
Packit Service 82fcde
        return -2;
Packit Service 82fcde
Packit Service 82fcde
      h->mprotect_size = new_size;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    __madvise ((char *) h + new_size, diff, MADV_DONTNEED);
Packit Service 82fcde
  /*fprintf(stderr, "shrink %p %08lx\n", h, new_size);*/
Packit Service 82fcde
Packit Service 82fcde
  h->size = new_size;
Packit Service 82fcde
  LIBC_PROBE (memory_heap_less, 2, h, h->size);
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Delete a heap. */
Packit Service 82fcde
Packit Service 82fcde
#define delete_heap(heap) \
Packit Service 82fcde
  do {									      \
Packit Service 82fcde
      if ((char *) (heap) + HEAP_MAX_SIZE == aligned_heap_area)		      \
Packit Service 82fcde
        aligned_heap_area = NULL;					      \
Packit Service 82fcde
      __munmap ((char *) (heap), HEAP_MAX_SIZE);			      \
Packit Service 82fcde
    } while (0)
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
heap_trim (heap_info *heap, size_t pad)
Packit Service 82fcde
{
Packit Service 82fcde
  mstate ar_ptr = heap->ar_ptr;
Packit Service 82fcde
  unsigned long pagesz = GLRO (dl_pagesize);
Packit Service f14ab5
  mchunkptr top_chunk = top (ar_ptr), p;
Packit Service 82fcde
  heap_info *prev_heap;
Packit Service 82fcde
  long new_size, top_size, top_area, extra, prev_size, misalign;
Packit Service 82fcde
Packit Service 82fcde
  /* Can this heap go away completely? */
Packit Service 82fcde
  while (top_chunk == chunk_at_offset (heap, sizeof (*heap)))
Packit Service 82fcde
    {
Packit Service 82fcde
      prev_heap = heap->prev;
Packit Service 82fcde
      prev_size = prev_heap->size - (MINSIZE - 2 * SIZE_SZ);
Packit Service 82fcde
      p = chunk_at_offset (prev_heap, prev_size);
Packit Service 82fcde
      /* fencepost must be properly aligned.  */
Packit Service 82fcde
      misalign = ((long) p) & MALLOC_ALIGN_MASK;
Packit Service 82fcde
      p = chunk_at_offset (prev_heap, prev_size - misalign);
Packit Service 82fcde
      assert (chunksize_nomask (p) == (0 | PREV_INUSE)); /* must be fencepost */
Packit Service 82fcde
      p = prev_chunk (p);
Packit Service 82fcde
      new_size = chunksize (p) + (MINSIZE - 2 * SIZE_SZ) + misalign;
Packit Service 82fcde
      assert (new_size > 0 && new_size < (long) (2 * MINSIZE));
Packit Service 82fcde
      if (!prev_inuse (p))
Packit Service 82fcde
        new_size += prev_size (p);
Packit Service 82fcde
      assert (new_size > 0 && new_size < HEAP_MAX_SIZE);
Packit Service 82fcde
      if (new_size + (HEAP_MAX_SIZE - prev_heap->size) < pad + MINSIZE + pagesz)
Packit Service 82fcde
        break;
Packit Service 82fcde
      ar_ptr->system_mem -= heap->size;
Packit Service 82fcde
      LIBC_PROBE (memory_heap_free, 2, heap, heap->size);
Packit Service 82fcde
      delete_heap (heap);
Packit Service 82fcde
      heap = prev_heap;
Packit Service 82fcde
      if (!prev_inuse (p)) /* consolidate backward */
Packit Service 82fcde
        {
Packit Service 82fcde
          p = prev_chunk (p);
Packit Service f14ab5
          unlink_chunk (ar_ptr, p);
Packit Service 82fcde
        }
Packit Service 82fcde
      assert (((unsigned long) ((char *) p + new_size) & (pagesz - 1)) == 0);
Packit Service 82fcde
      assert (((char *) p + new_size) == ((char *) heap + heap->size));
Packit Service 82fcde
      top (ar_ptr) = top_chunk = p;
Packit Service 82fcde
      set_head (top_chunk, new_size | PREV_INUSE);
Packit Service 82fcde
      /*check_chunk(ar_ptr, top_chunk);*/
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Uses similar logic for per-thread arenas as the main arena with systrim
Packit Service 82fcde
     and _int_free by preserving the top pad and rounding down to the nearest
Packit Service 82fcde
     page.  */
Packit Service 82fcde
  top_size = chunksize (top_chunk);
Packit Service 82fcde
  if ((unsigned long)(top_size) <
Packit Service 82fcde
      (unsigned long)(mp_.trim_threshold))
Packit Service 82fcde
    return 0;
Packit Service 82fcde
Packit Service 82fcde
  top_area = top_size - MINSIZE - 1;
Packit Service 82fcde
  if (top_area < 0 || (size_t) top_area <= pad)
Packit Service 82fcde
    return 0;
Packit Service 82fcde
Packit Service 82fcde
  /* Release in pagesize units and round down to the nearest page.  */
Packit Service 82fcde
  extra = ALIGN_DOWN(top_area - pad, pagesz);
Packit Service 82fcde
  if (extra == 0)
Packit Service 82fcde
    return 0;
Packit Service 82fcde
Packit Service 82fcde
  /* Try to shrink. */
Packit Service 82fcde
  if (shrink_heap (heap, extra) != 0)
Packit Service 82fcde
    return 0;
Packit Service 82fcde
Packit Service 82fcde
  ar_ptr->system_mem -= extra;
Packit Service 82fcde
Packit Service 82fcde
  /* Success. Adjust top accordingly. */
Packit Service 82fcde
  set_head (top_chunk, (top_size - extra) | PREV_INUSE);
Packit Service 82fcde
  /*check_chunk(ar_ptr, top_chunk);*/
Packit Service 82fcde
  return 1;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Create a new arena with initial size "size".  */
Packit Service 82fcde
Packit Service 82fcde
/* If REPLACED_ARENA is not NULL, detach it from this thread.  Must be
Packit Service 82fcde
   called while free_list_lock is held.  */
Packit Service 82fcde
static void
Packit Service 82fcde
detach_arena (mstate replaced_arena)
Packit Service 82fcde
{
Packit Service 82fcde
  if (replaced_arena != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      assert (replaced_arena->attached_threads > 0);
Packit Service 82fcde
      /* The current implementation only detaches from main_arena in
Packit Service 82fcde
	 case of allocation failure.  This means that it is likely not
Packit Service 82fcde
	 beneficial to put the arena on free_list even if the
Packit Service 82fcde
	 reference count reaches zero.  */
Packit Service 82fcde
      --replaced_arena->attached_threads;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static mstate
Packit Service 82fcde
_int_new_arena (size_t size)
Packit Service 82fcde
{
Packit Service 82fcde
  mstate a;
Packit Service 82fcde
  heap_info *h;
Packit Service 82fcde
  char *ptr;
Packit Service 82fcde
  unsigned long misalign;
Packit Service 82fcde
Packit Service 82fcde
  h = new_heap (size + (sizeof (*h) + sizeof (*a) + MALLOC_ALIGNMENT),
Packit Service 82fcde
                mp_.top_pad);
Packit Service 82fcde
  if (!h)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Maybe size is too large to fit in a single heap.  So, just try
Packit Service 82fcde
         to create a minimally-sized arena and let _int_malloc() attempt
Packit Service 82fcde
         to deal with the large request via mmap_chunk().  */
Packit Service 82fcde
      h = new_heap (sizeof (*h) + sizeof (*a) + MALLOC_ALIGNMENT, mp_.top_pad);
Packit Service 82fcde
      if (!h)
Packit Service 82fcde
        return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
  a = h->ar_ptr = (mstate) (h + 1);
Packit Service 82fcde
  malloc_init_state (a);
Packit Service 82fcde
  a->attached_threads = 1;
Packit Service 82fcde
  /*a->next = NULL;*/
Packit Service 82fcde
  a->system_mem = a->max_system_mem = h->size;
Packit Service 82fcde
Packit Service 82fcde
  /* Set up the top chunk, with proper alignment. */
Packit Service 82fcde
  ptr = (char *) (a + 1);
Packit Service 82fcde
  misalign = (unsigned long) chunk2mem (ptr) & MALLOC_ALIGN_MASK;
Packit Service 82fcde
  if (misalign > 0)
Packit Service 82fcde
    ptr += MALLOC_ALIGNMENT - misalign;
Packit Service 82fcde
  top (a) = (mchunkptr) ptr;
Packit Service 82fcde
  set_head (top (a), (((char *) h + h->size) - ptr) | PREV_INUSE);
Packit Service 82fcde
Packit Service 82fcde
  LIBC_PROBE (memory_arena_new, 2, a, size);
Packit Service 82fcde
  mstate replaced_arena = thread_arena;
Packit Service 82fcde
  thread_arena = a;
Packit Service 82fcde
  __libc_lock_init (a->mutex);
Packit Service 82fcde
Packit Service 82fcde
  __libc_lock_lock (list_lock);
Packit Service 82fcde
Packit Service 82fcde
  /* Add the new arena to the global list.  */
Packit Service 82fcde
  a->next = main_arena.next;
Packit Service 82fcde
  /* FIXME: The barrier is an attempt to synchronize with read access
Packit Service 82fcde
     in reused_arena, which does not acquire list_lock while
Packit Service 82fcde
     traversing the list.  */
Packit Service 82fcde
  atomic_write_barrier ();
Packit Service 82fcde
  main_arena.next = a;
Packit Service 82fcde
Packit Service 82fcde
  __libc_lock_unlock (list_lock);
Packit Service 82fcde
Packit Service 82fcde
  __libc_lock_lock (free_list_lock);
Packit Service 82fcde
  detach_arena (replaced_arena);
Packit Service 82fcde
  __libc_lock_unlock (free_list_lock);
Packit Service 82fcde
Packit Service 82fcde
  /* Lock this arena.  NB: Another thread may have been attached to
Packit Service 82fcde
     this arena because the arena is now accessible from the
Packit Service 82fcde
     main_arena.next list and could have been picked by reused_arena.
Packit Service 82fcde
     This can only happen for the last arena created (before the arena
Packit Service 82fcde
     limit is reached).  At this point, some arena has to be attached
Packit Service 82fcde
     to two threads.  We could acquire the arena lock before list_lock
Packit Service 82fcde
     to make it less likely that reused_arena picks this new arena,
Packit Service 82fcde
     but this could result in a deadlock with
Packit Service 82fcde
     __malloc_fork_lock_parent.  */
Packit Service 82fcde
Packit Service 82fcde
  __libc_lock_lock (a->mutex);
Packit Service 82fcde
Packit Service 82fcde
  return a;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Remove an arena from free_list.  */
Packit Service 82fcde
static mstate
Packit Service 82fcde
get_free_list (void)
Packit Service 82fcde
{
Packit Service 82fcde
  mstate replaced_arena = thread_arena;
Packit Service 82fcde
  mstate result = free_list;
Packit Service 82fcde
  if (result != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      __libc_lock_lock (free_list_lock);
Packit Service 82fcde
      result = free_list;
Packit Service 82fcde
      if (result != NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  free_list = result->next_free;
Packit Service 82fcde
Packit Service 82fcde
	  /* The arena will be attached to this thread.  */
Packit Service 82fcde
	  assert (result->attached_threads == 0);
Packit Service 82fcde
	  result->attached_threads = 1;
Packit Service 82fcde
Packit Service 82fcde
	  detach_arena (replaced_arena);
Packit Service 82fcde
	}
Packit Service 82fcde
      __libc_lock_unlock (free_list_lock);
Packit Service 82fcde
Packit Service 82fcde
      if (result != NULL)
Packit Service 82fcde
        {
Packit Service 82fcde
          LIBC_PROBE (memory_arena_reuse_free_list, 1, result);
Packit Service 82fcde
          __libc_lock_lock (result->mutex);
Packit Service 82fcde
	  thread_arena = result;
Packit Service 82fcde
        }
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Remove the arena from the free list (if it is present).
Packit Service 82fcde
   free_list_lock must have been acquired by the caller.  */
Packit Service 82fcde
static void
Packit Service 82fcde
remove_from_free_list (mstate arena)
Packit Service 82fcde
{
Packit Service 82fcde
  mstate *previous = &free_list;
Packit Service 82fcde
  for (mstate p = free_list; p != NULL; p = p->next_free)
Packit Service 82fcde
    {
Packit Service 82fcde
      assert (p->attached_threads == 0);
Packit Service 82fcde
      if (p == arena)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* Remove the requested arena from the list.  */
Packit Service 82fcde
	  *previous = p->next_free;
Packit Service 82fcde
	  break;
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	previous = &p->next_free;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Lock and return an arena that can be reused for memory allocation.
Packit Service 82fcde
   Avoid AVOID_ARENA as we have already failed to allocate memory in
Packit Service 82fcde
   it and it is currently locked.  */
Packit Service 82fcde
static mstate
Packit Service 82fcde
reused_arena (mstate avoid_arena)
Packit Service 82fcde
{
Packit Service 82fcde
  mstate result;
Packit Service 82fcde
  /* FIXME: Access to next_to_use suffers from data races.  */
Packit Service 82fcde
  static mstate next_to_use;
Packit Service 82fcde
  if (next_to_use == NULL)
Packit Service 82fcde
    next_to_use = &main_arena;
Packit Service 82fcde
Packit Service 82fcde
  /* Iterate over all arenas (including those linked from
Packit Service 82fcde
     free_list).  */
Packit Service 82fcde
  result = next_to_use;
Packit Service 82fcde
  do
Packit Service 82fcde
    {
Packit Service 82fcde
      if (!__libc_lock_trylock (result->mutex))
Packit Service 82fcde
        goto out;
Packit Service 82fcde
Packit Service 82fcde
      /* FIXME: This is a data race, see _int_new_arena.  */
Packit Service 82fcde
      result = result->next;
Packit Service 82fcde
    }
Packit Service 82fcde
  while (result != next_to_use);
Packit Service 82fcde
Packit Service 82fcde
  /* Avoid AVOID_ARENA as we have already failed to allocate memory
Packit Service 82fcde
     in that arena and it is currently locked.   */
Packit Service 82fcde
  if (result == avoid_arena)
Packit Service 82fcde
    result = result->next;
Packit Service 82fcde
Packit Service 82fcde
  /* No arena available without contention.  Wait for the next in line.  */
Packit Service 82fcde
  LIBC_PROBE (memory_arena_reuse_wait, 3, &result->mutex, result, avoid_arena);
Packit Service 82fcde
  __libc_lock_lock (result->mutex);
Packit Service 82fcde
Packit Service 82fcde
out:
Packit Service 82fcde
  /* Attach the arena to the current thread.  */
Packit Service 82fcde
  {
Packit Service 82fcde
    /* Update the arena thread attachment counters.   */
Packit Service 82fcde
    mstate replaced_arena = thread_arena;
Packit Service 82fcde
    __libc_lock_lock (free_list_lock);
Packit Service 82fcde
    detach_arena (replaced_arena);
Packit Service 82fcde
Packit Service 82fcde
    /* We may have picked up an arena on the free list.  We need to
Packit Service 82fcde
       preserve the invariant that no arena on the free list has a
Packit Service 82fcde
       positive attached_threads counter (otherwise,
Packit Service 82fcde
       arena_thread_freeres cannot use the counter to determine if the
Packit Service 82fcde
       arena needs to be put on the free list).  We unconditionally
Packit Service 82fcde
       remove the selected arena from the free list.  The caller of
Packit Service 82fcde
       reused_arena checked the free list and observed it to be empty,
Packit Service 82fcde
       so the list is very short.  */
Packit Service 82fcde
    remove_from_free_list (result);
Packit Service 82fcde
Packit Service 82fcde
    ++result->attached_threads;
Packit Service 82fcde
Packit Service 82fcde
    __libc_lock_unlock (free_list_lock);
Packit Service 82fcde
  }
Packit Service 82fcde
Packit Service 82fcde
  LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena);
Packit Service 82fcde
  thread_arena = result;
Packit Service 82fcde
  next_to_use = result->next;
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static mstate
Packit Service 82fcde
arena_get2 (size_t size, mstate avoid_arena)
Packit Service 82fcde
{
Packit Service 82fcde
  mstate a;
Packit Service 82fcde
Packit Service 82fcde
  static size_t narenas_limit;
Packit Service 82fcde
Packit Service 82fcde
  a = get_free_list ();
Packit Service 82fcde
  if (a == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Nothing immediately available, so generate a new arena.  */
Packit Service 82fcde
      if (narenas_limit == 0)
Packit Service 82fcde
        {
Packit Service 82fcde
          if (mp_.arena_max != 0)
Packit Service 82fcde
            narenas_limit = mp_.arena_max;
Packit Service 82fcde
          else if (narenas > mp_.arena_test)
Packit Service 82fcde
            {
Packit Service 82fcde
              int n = __get_nprocs ();
Packit Service 82fcde
Packit Service 82fcde
              if (n >= 1)
Packit Service 82fcde
                narenas_limit = NARENAS_FROM_NCORES (n);
Packit Service 82fcde
              else
Packit Service 82fcde
                /* We have no information about the system.  Assume two
Packit Service 82fcde
                   cores.  */
Packit Service 82fcde
                narenas_limit = NARENAS_FROM_NCORES (2);
Packit Service 82fcde
            }
Packit Service 82fcde
        }
Packit Service 82fcde
    repeat:;
Packit Service 82fcde
      size_t n = narenas;
Packit Service 82fcde
      /* NB: the following depends on the fact that (size_t)0 - 1 is a
Packit Service 82fcde
         very large number and that the underflow is OK.  If arena_max
Packit Service 82fcde
         is set the value of arena_test is irrelevant.  If arena_test
Packit Service 82fcde
         is set but narenas is not yet larger or equal to arena_test
Packit Service 82fcde
         narenas_limit is 0.  There is no possibility for narenas to
Packit Service 82fcde
         be too big for the test to always fail since there is not
Packit Service 82fcde
         enough address space to create that many arenas.  */
Packit Service 82fcde
      if (__glibc_unlikely (n <= narenas_limit - 1))
Packit Service 82fcde
        {
Packit Service 82fcde
          if (catomic_compare_and_exchange_bool_acq (&narenas, n + 1, n))
Packit Service 82fcde
            goto repeat;
Packit Service 82fcde
          a = _int_new_arena (size);
Packit Service 82fcde
	  if (__glibc_unlikely (a == NULL))
Packit Service 82fcde
            catomic_decrement (&narenas);
Packit Service 82fcde
        }
Packit Service 82fcde
      else
Packit Service 82fcde
        a = reused_arena (avoid_arena);
Packit Service 82fcde
    }
Packit Service 82fcde
  return a;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* If we don't have the main arena, then maybe the failure is due to running
Packit Service 82fcde
   out of mmapped areas, so we can try allocating on the main arena.
Packit Service 82fcde
   Otherwise, it is likely that sbrk() has failed and there is still a chance
Packit Service 82fcde
   to mmap(), so try one of the other arenas.  */
Packit Service 82fcde
static mstate
Packit Service 82fcde
arena_get_retry (mstate ar_ptr, size_t bytes)
Packit Service 82fcde
{
Packit Service 82fcde
  LIBC_PROBE (memory_arena_retry, 2, bytes, ar_ptr);
Packit Service 82fcde
  if (ar_ptr != &main_arena)
Packit Service 82fcde
    {
Packit Service 82fcde
      __libc_lock_unlock (ar_ptr->mutex);
Packit Service 82fcde
      ar_ptr = &main_arena;
Packit Service 82fcde
      __libc_lock_lock (ar_ptr->mutex);
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      __libc_lock_unlock (ar_ptr->mutex);
Packit Service 82fcde
      ar_ptr = arena_get2 (bytes, ar_ptr);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return ar_ptr;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
__malloc_arena_thread_freeres (void)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Shut down the thread cache first.  This could deallocate data for
Packit Service 82fcde
     the thread arena, so do this before we put the arena on the free
Packit Service 82fcde
     list.  */
Packit Service 82fcde
  tcache_thread_shutdown ();
Packit Service 82fcde
Packit Service 82fcde
  mstate a = thread_arena;
Packit Service 82fcde
  thread_arena = NULL;
Packit Service 82fcde
Packit Service 82fcde
  if (a != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      __libc_lock_lock (free_list_lock);
Packit Service 82fcde
      /* If this was the last attached thread for this arena, put the
Packit Service 82fcde
	 arena on the free list.  */
Packit Service 82fcde
      assert (a->attached_threads > 0);
Packit Service 82fcde
      if (--a->attached_threads == 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  a->next_free = free_list;
Packit Service 82fcde
	  free_list = a;
Packit Service 82fcde
	}
Packit Service 82fcde
      __libc_lock_unlock (free_list_lock);
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/*
Packit Service 82fcde
 * Local variables:
Packit Service 82fcde
 * c-basic-offset: 2
Packit Service 82fcde
 * End:
Packit Service 82fcde
 */