2017-09-28 17:05:18 +00:00
|
|
|
/* Bug 22111: Test that threads do not leak their per thread cache.
|
2020-01-01 00:14:33 +00:00
|
|
|
Copyright (C) 2015-2020 Free Software Foundation, Inc.
|
2017-09-28 17:05:18 +00:00
|
|
|
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
|
Prefer https to http for gnu.org and fsf.org URLs
Also, change sources.redhat.com to sourceware.org.
This patch was automatically generated by running the following shell
script, which uses GNU sed, and which avoids modifying files imported
from upstream:
sed -ri '
s,(http|ftp)(://(.*\.)?(gnu|fsf|sourceware)\.org($|[^.]|\.[^a-z])),https\2,g
s,(http|ftp)(://(.*\.)?)sources\.redhat\.com($|[^.]|\.[^a-z]),https\2sourceware.org\4,g
' \
$(find $(git ls-files) -prune -type f \
! -name '*.po' \
! -name 'ChangeLog*' \
! -path COPYING ! -path COPYING.LIB \
! -path manual/fdl-1.3.texi ! -path manual/lgpl-2.1.texi \
! -path manual/texinfo.tex ! -path scripts/config.guess \
! -path scripts/config.sub ! -path scripts/install-sh \
! -path scripts/mkinstalldirs ! -path scripts/move-if-change \
! -path INSTALL ! -path locale/programs/charmap-kw.h \
! -path po/libc.pot ! -path sysdeps/gnu/errlist.c \
! '(' -name configure \
-execdir test -f configure.ac -o -f configure.in ';' ')' \
! '(' -name preconfigure \
-execdir test -f preconfigure.ac ';' ')' \
-print)
and then by running 'make dist-prepare' to regenerate files built
from the altered files, and then executing the following to cleanup:
chmod a+x sysdeps/unix/sysv/linux/riscv/configure
# Omit irrelevant whitespace and comment-only changes,
# perhaps from a slightly-different Autoconf version.
git checkout -f \
sysdeps/csky/configure \
sysdeps/hppa/configure \
sysdeps/riscv/configure \
sysdeps/unix/sysv/linux/csky/configure
# Omit changes that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/powerpc/powerpc64/ppc-mcount.S: trailing lines
git checkout -f \
sysdeps/powerpc/powerpc64/ppc-mcount.S \
sysdeps/unix/sysv/linux/s390/s390-64/syscall.S
# Omit change that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S: last line does not end in newline
git checkout -f sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S
2019-09-07 05:40:42 +00:00
|
|
|
<https://www.gnu.org/licenses/>. */
|
2017-09-28 17:05:18 +00:00
|
|
|
|
|
|
|
/* The point of this test is to start and exit a large number of
|
|
|
|
threads, while at the same time looking to see if the used
|
|
|
|
memory grows with each round of threads run. If the memory
|
|
|
|
grows above some linear bound we declare the test failed and
|
|
|
|
that the malloc implementation is leaking memory with each
|
|
|
|
thread. This is a good indicator that the thread local cache
|
|
|
|
is leaking chunks. */
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include <support/check.h>
|
|
|
|
#include <support/support.h>
|
|
|
|
#include <support/xthread.h>
|
|
|
|
|
|
|
|
void *
|
|
|
|
worker (void *data)
|
|
|
|
{
|
|
|
|
void *ret;
|
|
|
|
/* Allocate an arbitrary amount of memory that is known to fit into
|
|
|
|
the thread local cache (tcache). If we have at least 64 bins
|
|
|
|
(default e.g. TCACHE_MAX_BINS) we should be able to allocate 32
|
|
|
|
bytes and force malloc to fill the tcache. We are assuming tcahce
|
|
|
|
init happens at the first small alloc, but it might in the future
|
|
|
|
be deferred to some other point. Therefore to future proof this
|
|
|
|
test we include a full alloc/free/alloc cycle for the thread. We
|
|
|
|
need a compiler barrier to avoid the removal of the useless
|
|
|
|
alloc/free. We send some memory back to main to have the memory
|
|
|
|
freed after the thread dies, as just another check that the chunks
|
|
|
|
that were previously in the tcache are still OK to free after
|
|
|
|
thread death. */
|
|
|
|
ret = xmalloc (32);
|
|
|
|
__asm__ volatile ("" ::: "memory");
|
|
|
|
free (ret);
|
|
|
|
return (void *) xmalloc (32);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_test (void)
|
|
|
|
{
|
|
|
|
pthread_t *thread;
|
|
|
|
struct mallinfo info_before, info_after;
|
|
|
|
void *retval;
|
|
|
|
|
|
|
|
/* This is an arbitrary choice. We choose a total of THREADS
|
|
|
|
threads created and joined. This gives us enough iterations to
|
|
|
|
show a leak. */
|
|
|
|
int threads = 100000;
|
|
|
|
|
|
|
|
/* Avoid there being 0 malloc'd data at this point by allocating the
|
|
|
|
pthread_t required to run the test. */
|
|
|
|
thread = (pthread_t *) xcalloc (1, sizeof (pthread_t));
|
|
|
|
|
|
|
|
info_before = mallinfo ();
|
|
|
|
|
|
|
|
assert (info_before.uordblks != 0);
|
|
|
|
|
|
|
|
printf ("INFO: %d (bytes) are in use before starting threads.\n",
|
|
|
|
info_before.uordblks);
|
|
|
|
|
|
|
|
for (int loop = 0; loop < threads; loop++)
|
|
|
|
{
|
|
|
|
*thread = xpthread_create (NULL, worker, NULL);
|
|
|
|
retval = xpthread_join (*thread);
|
|
|
|
free (retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
info_after = mallinfo ();
|
|
|
|
printf ("INFO: %d (bytes) are in use after all threads joined.\n",
|
|
|
|
info_after.uordblks);
|
|
|
|
|
|
|
|
/* We need to compare the memory in use before and the memory in use
|
|
|
|
after starting and joining THREADS threads. We almost always grow
|
|
|
|
memory slightly, but not much. Consider that if even 1-byte leaked
|
|
|
|
per thread we'd have THREADS bytes of additional memory, and in
|
|
|
|
general the in-use at the start of main is quite low. We will
|
|
|
|
always leak a full malloc chunk, and never just 1-byte, therefore
|
|
|
|
anything above "+ threads" from the start (constant offset) is a
|
|
|
|
leak. Obviously this assumes no thread-related malloc'd internal
|
|
|
|
libc data structures persist beyond the thread death, and any that
|
|
|
|
did would limit the number of times you could call pthread_create,
|
|
|
|
which is a QoI we'd want to detect and fix. */
|
|
|
|
if (info_after.uordblks > (info_before.uordblks + threads))
|
|
|
|
FAIL_EXIT1 ("Memory usage after threads is too high.\n");
|
|
|
|
|
|
|
|
/* Did not detect excessive memory usage. */
|
|
|
|
free (thread);
|
|
|
|
exit (0);
|
|
|
|
}
|
|
|
|
|
2018-01-04 21:58:40 +00:00
|
|
|
#define TIMEOUT 50
|
2017-09-28 17:05:18 +00:00
|
|
|
#include <support/test-driver.c>
|