diff --git a/malloc/Makefile b/malloc/Makefile index 02aff1bd1d..98d507a6eb 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -28,6 +28,8 @@ tests := \ mallocbug \ tst-aligned-alloc \ tst-aligned-alloc-random \ + tst-aligned-alloc-random-thread \ + tst-aligned-alloc-random-thread-cross \ tst-alloc_buffer \ tst-calloc \ tst-free-errno \ @@ -151,6 +153,8 @@ ifeq ($(have-GLIBC_2.23)$(build-shared),yesyes) # the tests expect specific internal behavior that is changed due to linking to # libmcheck.a. tests-exclude-mcheck = \ + tst-aligned-alloc-random-thread \ + tst-aligned-alloc-random-thread-cross \ tst-compathooks-off \ tst-compathooks-on \ tst-malloc-backtrace \ @@ -415,7 +419,11 @@ $(objpfx)tst-mallocstate: $(objpfx)libc_malloc_debug.so $(objpfx)tst-mallocstate-malloc-check: $(objpfx)libc_malloc_debug.so $(objpfx)tst-aligned-alloc-random.out: $(objpfx)tst-aligned_alloc-lib.so +$(objpfx)tst-aligned-alloc-random-thread.out: $(objpfx)tst-aligned_alloc-lib.so +$(objpfx)tst-aligned-alloc-random-thread-cross.out: $(objpfx)tst-aligned_alloc-lib.so $(objpfx)tst-malloc-random.out: $(objpfx)tst-aligned_alloc-lib.so tst-aligned-alloc-random-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so +tst-aligned-alloc-random-thread-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so +tst-aligned-alloc-random-thread-cross-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so tst-malloc-random-ENV = LD_PRELOAD=$(objpfx)tst-aligned_alloc-lib.so diff --git a/malloc/tst-aligned-alloc-random-thread-cross.c b/malloc/tst-aligned-alloc-random-thread-cross.c new file mode 100644 index 0000000000..360ecc56ee --- /dev/null +++ b/malloc/tst-aligned-alloc-random-thread-cross.c @@ -0,0 +1,19 @@ +/* multi-threaded memory allocation and cross-thread deallocation test. + Copyright (C) 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; see the file COPYING.LIB. If + not, see . */ +#define CROSS_THREAD_DEALLOC +#include "tst-aligned-alloc-random-thread.c" diff --git a/malloc/tst-aligned-alloc-random-thread.c b/malloc/tst-aligned-alloc-random-thread.c new file mode 100644 index 0000000000..e95f79250a --- /dev/null +++ b/malloc/tst-aligned-alloc-random-thread.c @@ -0,0 +1,145 @@ +/* multi-threaded memory allocation/deallocation test. + Copyright (C) 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; see the file COPYING.LIB. If + not, see . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ITERATIONS +# define ITERATIONS 16 +#endif + +#ifndef NUM_THREADS +# define NUM_THREADS 8 +#endif + +#ifndef NUM_ALLOCATIONS +# define NUM_ALLOCATIONS 2048 +#endif + +static pthread_barrier_t barrier; + +__thread unsigned int seed; + +typedef struct +{ + int id; + pthread_t thread; +} thread; + +thread threads[NUM_THREADS]; + +void *allocations[NUM_THREADS][NUM_ALLOCATIONS]; + +void +run_thread_dealloc (int id) +{ + for (int i = 0; i < NUM_ALLOCATIONS; i++) + { + free (allocations[id][i]); + allocations[id][i] = NULL; + } +} + +void +run_thread_alloc (int id) +{ + size_t msb, size; + for (int i = 0; i < NUM_ALLOCATIONS; i++) + { + msb = 1 << rand_r (&seed) % 16; + size = msb + rand_r (&seed) % msb; + allocations[id][i] = malloc (size); + TEST_VERIFY_EXIT (allocations[id][i] != NULL); + } +} + +void * +run_allocations (void *arg) +{ + int id = *((int *) arg); + seed = time (NULL) + id; + + /* Stage 1: First half o the threads allocating memory and the second + * half waiting for them to finish + */ + if (id < NUM_THREADS / 2) + run_thread_alloc (id); + + xpthread_barrier_wait (&barrier); + + /* Stage 2: Half of the threads allocationg memory and the other + * half deallocating: + * - In the non cross-thread dealloc scenario the first half will be + * deallocating the memory allocated by themselves in stage 1 and the + * second half will be allocating memory. + * - In the cross-thread dealloc scenario the first half will continue + * to allocate memory and the second half will deallocate the memory + * allocated by the first half in stage 1. + */ + if (id < NUM_THREADS / 2) +#ifndef CROSS_THREAD_DEALLOC + run_thread_dealloc (id); +#else + run_thread_alloc (id + NUM_THREADS / 2); +#endif + else +#ifndef CROSS_THREAD_DEALLOC + run_thread_alloc (id); +#else + run_thread_dealloc (id - NUM_THREADS / 2); +#endif + + xpthread_barrier_wait (&barrier); + + // Stage 3: Second half of the threads deallocating and the first half + // waiting for them to finish. + if (id >= NUM_THREADS / 2) + run_thread_dealloc (id); + + return NULL; +} + +static int +do_test (void) +{ + xpthread_barrier_init (&barrier, NULL, NUM_THREADS); + + for (int i = 0; i < ITERATIONS; i++) + { + for (int t = 0; t < NUM_THREADS; t++) + { + threads[t].id = t; + threads[t].thread + = xpthread_create (NULL, run_allocations, &threads[t].id); + } + + for (int t = 0; t < NUM_THREADS; t++) + xpthread_join (threads[t].thread); + } + + return 0; +} + +#include