Blame malloc/tst-malloc-thread-exit.c

Packit Service 82fcde
/* Test malloc with concurrent thread termination.
Packit Service 82fcde
   Copyright (C) 2015-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
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
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the 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; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
/* This thread spawns a number of outer threads, equal to the arena
Packit Service 82fcde
   limit.  The outer threads run a loop which start and join two
Packit Service 82fcde
   different kinds of threads: the first kind allocates (attaching an
Packit Service 82fcde
   arena to the thread; malloc_first_thread) and waits, the second
Packit Service 82fcde
   kind waits and allocates (wait_first_threads).  Both kinds of
Packit Service 82fcde
   threads exit immediately after waiting.  The hope is that this will
Packit Service 82fcde
   exhibit races in thread termination and arena management,
Packit Service 82fcde
   particularly related to the arena free list.  */
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <malloc.h>
Packit Service 82fcde
#include <pthread.h>
Packit Service 82fcde
#include <stdbool.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
Packit Service 82fcde
#include <support/support.h>
Packit Service 82fcde
#include <support/xthread.h>
Packit Service 82fcde
#include <support/test-driver.h>
Packit Service 82fcde
Packit Service 82fcde
static bool termination_requested;
Packit Service 82fcde
static int inner_thread_count = 4;
Packit Service 82fcde
static size_t malloc_size = 32;
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
__attribute__ ((noinline, noclone))
Packit Service 82fcde
unoptimized_free (void *ptr)
Packit Service 82fcde
{
Packit Service 82fcde
  free (ptr);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void *
Packit Service 82fcde
malloc_first_thread (void * closure)
Packit Service 82fcde
{
Packit Service 82fcde
  pthread_barrier_t *barrier = closure;
Packit Service 82fcde
  void *ptr = xmalloc (malloc_size);
Packit Service 82fcde
  xpthread_barrier_wait (barrier);
Packit Service 82fcde
  unoptimized_free (ptr);
Packit Service 82fcde
  return NULL;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void *
Packit Service 82fcde
wait_first_thread (void * closure)
Packit Service 82fcde
{
Packit Service 82fcde
  pthread_barrier_t *barrier = closure;
Packit Service 82fcde
  xpthread_barrier_wait (barrier);
Packit Service 82fcde
  void *ptr = xmalloc (malloc_size);
Packit Service 82fcde
  unoptimized_free (ptr);
Packit Service 82fcde
  return NULL;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void *
Packit Service 82fcde
outer_thread (void *closure)
Packit Service 82fcde
{
Packit Service 82fcde
  pthread_t *threads = xcalloc (sizeof (*threads), inner_thread_count);
Packit Service 82fcde
  while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
Packit Service 82fcde
    {
Packit Service 82fcde
      pthread_barrier_t barrier;
Packit Service 82fcde
      xpthread_barrier_init (&barrier, NULL, inner_thread_count + 1);
Packit Service 82fcde
      for (int i = 0; i < inner_thread_count; ++i)
Packit Service 82fcde
        {
Packit Service 82fcde
          void *(*func) (void *);
Packit Service 82fcde
          if ((i  % 2) == 0)
Packit Service 82fcde
            func = malloc_first_thread;
Packit Service 82fcde
          else
Packit Service 82fcde
            func = wait_first_thread;
Packit Service 82fcde
          threads[i] = xpthread_create (NULL, func, &barrier);
Packit Service 82fcde
        }
Packit Service 82fcde
      xpthread_barrier_wait (&barrier);
Packit Service 82fcde
      for (int i = 0; i < inner_thread_count; ++i)
Packit Service 82fcde
        xpthread_join (threads[i]);
Packit Service 82fcde
      xpthread_barrier_destroy (&barrier);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  free (threads);
Packit Service 82fcde
Packit Service 82fcde
  return NULL;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
do_test (void)
Packit Service 82fcde
{
Packit Service 82fcde
  /* The number of threads should be smaller than the number of
Packit Service 82fcde
     arenas, so that there will be some free arenas to add to the
Packit Service 82fcde
     arena free list.  */
Packit Service 82fcde
  enum { outer_thread_count = 2 };
Packit Service 82fcde
  if (mallopt (M_ARENA_MAX, 8) == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("error: mallopt (M_ARENA_MAX) failed\n");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Leave some room for shutting down all threads gracefully.  */
Packit Service 82fcde
  int timeout = 3;
Packit Service 82fcde
  if (timeout > DEFAULT_TIMEOUT)
Packit Service 82fcde
    timeout = DEFAULT_TIMEOUT - 1;
Packit Service 82fcde
Packit Service 82fcde
  pthread_t *threads = xcalloc (sizeof (*threads), outer_thread_count);
Packit Service 82fcde
  for (long i = 0; i < outer_thread_count; ++i)
Packit Service 82fcde
    threads[i] = xpthread_create (NULL, outer_thread, NULL);
Packit Service 82fcde
Packit Service 82fcde
  struct timespec ts = {timeout, 0};
Packit Service 82fcde
  if (nanosleep (&ts, NULL))
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("error: error: nanosleep: %m\n");
Packit Service 82fcde
      abort ();
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  __atomic_store_n (&termination_requested, true, __ATOMIC_RELAXED);
Packit Service 82fcde
Packit Service 82fcde
  for (long i = 0; i < outer_thread_count; ++i)
Packit Service 82fcde
    xpthread_join (threads[i]);
Packit Service 82fcde
  free (threads);
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#include <support/test-driver.c>