/* Test for memalign chunk reuse.
   Copyright (C) 2022-2024 Free Software Foundation, Inc.
   This file is part of the GNU C Library.
   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.
   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.
   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   .  */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
typedef struct TestCase {
  size_t size;
  size_t alignment;
  void *ptr1;
  void *ptr2;
} TestCase;
static TestCase tcache_allocs[] = {
  { 24, 32, NULL, NULL },
  { 24, 64, NULL, NULL },
  { 128, 128, NULL, NULL },
  { 500, 128, NULL, NULL }
};
#define TN array_length (tcache_allocs)
static TestCase large_allocs[] = {
  { 23450, 64, NULL, NULL },
  { 23450, 64, NULL, NULL },
  { 23550, 64, NULL, NULL },
  { 23550, 64, NULL, NULL },
  { 23650, 64, NULL, NULL },
  { 23650, 64, NULL, NULL },
  { 33650, 64, NULL, NULL },
  { 33650, 64, NULL, NULL }
};
#define LN array_length (large_allocs)
void *p;
/* Sanity checks, ancillary to the actual test.  */
#define CHECK(p,a) \
  if (p == NULL || !PTR_IS_ALIGNED (p, a)) \
    FAIL_EXIT1 ("NULL or misaligned memory detected.\n");
static void *
mem_test (void *closure)
{
  int i;
  int j;
  int count;
  void *ptr[10];
  void *p;
  /* TCache test.  */
  for (i = 0; i < TN; ++ i)
    {
      size_t sz2;
      tcache_allocs[i].ptr1 = memalign (tcache_allocs[i].alignment, tcache_allocs[i].size);
      CHECK (tcache_allocs[i].ptr1, tcache_allocs[i].alignment);
      sz2 = malloc_usable_size (tcache_allocs[i].ptr1);
      free (tcache_allocs[i].ptr1);
      /* This should return the same chunk as was just free'd.  */
      tcache_allocs[i].ptr2 = memalign (tcache_allocs[i].alignment, sz2);
      CHECK (tcache_allocs[i].ptr2, tcache_allocs[i].alignment);
      free (tcache_allocs[i].ptr2);
      TEST_VERIFY (tcache_allocs[i].ptr1 == tcache_allocs[i].ptr2);
    }
  /* Test for non-head tcache hits.  */
  for (i = 0; i < array_length (ptr); ++ i)
    {
      if (i == 4)
	{
	  ptr[i] = memalign (64, 256);
	  CHECK (ptr[i], 64);
	}
      else
	{
	  ptr[i] = malloc (256);
	  CHECK (ptr[i], 4);
	}
    }
  for (i = 0; i < array_length (ptr); ++ i)
    free (ptr[i]);
  p = memalign (64, 256);
  CHECK (p, 64);
  count = 0;
  for (i = 0; i < 10; ++ i)
    if (ptr[i] == p)
      ++ count;
  free (p);
  TEST_VERIFY (count > 0);
  /* Large bins test.  */
  for (i = 0; i < LN; ++ i)
    {
      large_allocs[i].ptr1 = memalign (large_allocs[i].alignment, large_allocs[i].size);
      CHECK (large_allocs[i].ptr1, large_allocs[i].alignment);
      /* Keep chunks from combining by fragmenting the heap.  */
      p = malloc (512);
      CHECK (p, 4);
    }
  for (i = 0; i < LN; ++ i)
    free (large_allocs[i].ptr1);
  /* Force the unsorted bins to be scanned and moved to small/large
     bins.  */
  p = malloc (60000);
  for (i = 0; i < LN; ++ i)
    {
      large_allocs[i].ptr2 = memalign (large_allocs[i].alignment, large_allocs[i].size);
      CHECK (large_allocs[i].ptr2, large_allocs[i].alignment);
    }
  count = 0;
  for (i = 0; i < LN; ++ i)
    {
      int ok = 0;
      for (j = 0; j < LN; ++ j)
	if (large_allocs[i].ptr1 == large_allocs[j].ptr2)
	  ok = 1;
      if (ok == 1)
	count ++;
    }
  /* The allocation algorithm is complicated outside of the memalign
     logic, so just make sure it's working for most of the
     allocations.  This avoids possible boundary conditions with
     empty/full heaps.  */
  TEST_VERIFY (count > LN / 2);
  return 0;
}
static int
do_test (void)
{
  pthread_t p;
  p = xpthread_create (NULL, mem_test, NULL);
  xpthread_join (p);
  return 0;
}
#include