mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-28 23:34:53 +03:00 
			
		
		
		
	I used these shell commands: ../glibc/scripts/update-copyrights $PWD/../gnulib/build-aux/update-copyright (cd ../glibc && git commit -am"[this commit message]") and then ignored the output, which consisted lines saying "FOO: warning: copyright statement not found" for each of 7061 files FOO. I then removed trailing white space from math/tgmath.h, support/tst-support-open-dev-null-range.c, and sysdeps/x86_64/multiarch/strlen-vec.S, to work around the following obscure pre-commit check failure diagnostics from Savannah. I don't know why I run into these diagnostics whereas others evidently do not. remote: *** 912-#endif remote: *** 913: remote: *** 914- remote: *** error: lines with trailing whitespace found ... remote: *** error: sysdeps/unix/sysv/linux/statx_cp.c: trailing lines
		
			
				
	
	
		
			138 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Test malloc with concurrent thread termination.
 | |
|    Copyright (C) 2015-2022 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
 | |
|    <https://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| /* This thread spawns a number of outer threads, equal to the arena
 | |
|    limit.  The outer threads run a loop which start and join two
 | |
|    different kinds of threads: the first kind allocates (attaching an
 | |
|    arena to the thread; malloc_first_thread) and waits, the second
 | |
|    kind waits and allocates (wait_first_threads).  Both kinds of
 | |
|    threads exit immediately after waiting.  The hope is that this will
 | |
|    exhibit races in thread termination and arena management,
 | |
|    particularly related to the arena free list.  */
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <malloc.h>
 | |
| #include <pthread.h>
 | |
| #include <stdbool.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #include <support/support.h>
 | |
| #include <support/xthread.h>
 | |
| #include <support/test-driver.h>
 | |
| 
 | |
| static bool termination_requested;
 | |
| static int inner_thread_count = 4;
 | |
| static size_t malloc_size = 32;
 | |
| 
 | |
| static void
 | |
| __attribute__ ((noinline, noclone))
 | |
| unoptimized_free (void *ptr)
 | |
| {
 | |
|   free (ptr);
 | |
| }
 | |
| 
 | |
| static void *
 | |
| malloc_first_thread (void * closure)
 | |
| {
 | |
|   pthread_barrier_t *barrier = closure;
 | |
|   void *ptr = xmalloc (malloc_size);
 | |
|   xpthread_barrier_wait (barrier);
 | |
|   unoptimized_free (ptr);
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static void *
 | |
| wait_first_thread (void * closure)
 | |
| {
 | |
|   pthread_barrier_t *barrier = closure;
 | |
|   xpthread_barrier_wait (barrier);
 | |
|   void *ptr = xmalloc (malloc_size);
 | |
|   unoptimized_free (ptr);
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static void *
 | |
| outer_thread (void *closure)
 | |
| {
 | |
|   pthread_t *threads = xcalloc (sizeof (*threads), inner_thread_count);
 | |
|   while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
 | |
|     {
 | |
|       pthread_barrier_t barrier;
 | |
|       xpthread_barrier_init (&barrier, NULL, inner_thread_count + 1);
 | |
|       for (int i = 0; i < inner_thread_count; ++i)
 | |
|         {
 | |
|           void *(*func) (void *);
 | |
|           if ((i  % 2) == 0)
 | |
|             func = malloc_first_thread;
 | |
|           else
 | |
|             func = wait_first_thread;
 | |
|           threads[i] = xpthread_create (NULL, func, &barrier);
 | |
|         }
 | |
|       xpthread_barrier_wait (&barrier);
 | |
|       for (int i = 0; i < inner_thread_count; ++i)
 | |
|         xpthread_join (threads[i]);
 | |
|       xpthread_barrier_destroy (&barrier);
 | |
|     }
 | |
| 
 | |
|   free (threads);
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static int
 | |
| do_test (void)
 | |
| {
 | |
|   /* The number of threads should be smaller than the number of
 | |
|      arenas, so that there will be some free arenas to add to the
 | |
|      arena free list.  */
 | |
|   enum { outer_thread_count = 2 };
 | |
|   if (mallopt (M_ARENA_MAX, 8) == 0)
 | |
|     {
 | |
|       printf ("error: mallopt (M_ARENA_MAX) failed\n");
 | |
|       return 1;
 | |
|     }
 | |
| 
 | |
|   /* Leave some room for shutting down all threads gracefully.  */
 | |
|   int timeout = 3;
 | |
|   if (timeout > DEFAULT_TIMEOUT)
 | |
|     timeout = DEFAULT_TIMEOUT - 1;
 | |
| 
 | |
|   pthread_t *threads = xcalloc (sizeof (*threads), outer_thread_count);
 | |
|   for (long i = 0; i < outer_thread_count; ++i)
 | |
|     threads[i] = xpthread_create (NULL, outer_thread, NULL);
 | |
| 
 | |
|   struct timespec ts = {timeout, 0};
 | |
|   if (nanosleep (&ts, NULL))
 | |
|     {
 | |
|       printf ("error: error: nanosleep: %m\n");
 | |
|       abort ();
 | |
|     }
 | |
| 
 | |
|   __atomic_store_n (&termination_requested, true, __ATOMIC_RELAXED);
 | |
| 
 | |
|   for (long i = 0; i < outer_thread_count; ++i)
 | |
|     xpthread_join (threads[i]);
 | |
|   free (threads);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #include <support/test-driver.c>
 |