248 lines
8.1 KiB
Diff
248 lines
8.1 KiB
Diff
|
commit 946006d37cfc66c162877fc678405525a50f20df
|
||
|
Author: Miguel Martín <mmartinv@redhat.com>
|
||
|
Date: Tue Jul 16 17:14:57 2024 +0200
|
||
|
|
||
|
malloc: add multi-threaded tests for aligned_alloc/calloc/malloc
|
||
|
|
||
|
Improve aligned_alloc/calloc/malloc test coverage by adding
|
||
|
multi-threaded tests with random memory allocations and with/without
|
||
|
cross-thread memory deallocations.
|
||
|
|
||
|
Perform a number of memory allocation calls with random sizes limited
|
||
|
to 0xffff.
|
||
|
|
||
|
Use the existing DSO ('malloc/tst-aligned_alloc-lib.c') to randomize
|
||
|
allocator selection.
|
||
|
|
||
|
The multi-threaded allocation/deallocation is staged as described below:
|
||
|
|
||
|
- Stage 1: Half of the threads will be allocating memory and the
|
||
|
other half will be waiting for them to finish the allocation.
|
||
|
- Stage 2: Half of the threads will be allocating memory and the
|
||
|
other half will be deallocating memory.
|
||
|
- Stage 3: Half of the threads will be deallocating memory and the
|
||
|
second half waiting on them to finish.
|
||
|
|
||
|
Add 'malloc/tst-aligned-alloc-random-thread.c' where each thread will
|
||
|
deallocate only the memory that was previously allocated by itself.
|
||
|
|
||
|
Add 'malloc/tst-aligned-alloc-random-thread-cross.c' where each thread
|
||
|
will deallocate memory that was previously allocated by another thread.
|
||
|
|
||
|
The intention is to be able to utilize existing malloc testing to ensure
|
||
|
that similar allocation APIs are also exposed to the same rigors.
|
||
|
Reviewed-by: Arjun Shankar <arjun@redhat.com>
|
||
|
|
||
|
(cherry picked from commit b0fbcb7d0051a68baf26b2aed51a8a31c34d68e5)
|
||
|
|
||
|
diff --git a/malloc/Makefile b/malloc/Makefile
|
||
|
index 02aff1bd1dc664c3..98d507a6eb61f4fe 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 0000000000000000..360ecc56ee7c8c06
|
||
|
--- /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 <https://www.gnu.org/licenses/>. */
|
||
|
+#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 0000000000000000..e95f79250abec85e
|
||
|
--- /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 <https://www.gnu.org/licenses/>. */
|
||
|
+
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <string.h>
|
||
|
+#include <support/check.h>
|
||
|
+#include <support/support.h>
|
||
|
+#include <support/xthread.h>
|
||
|
+#include <support/test-driver.h>
|
||
|
+#include <sys/sysinfo.h>
|
||
|
+#include <unistd.h>
|
||
|
+
|
||
|
+#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 <support/test-driver.c>
|