2024-01-01 18:12:26 +00:00
|
|
|
/* Copyright (C) 2002-2024 Free Software Foundation, Inc.
|
2003-01-05 04:58: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
|
2012-02-09 23:18:22 +00:00
|
|
|
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/>. */
|
2003-01-05 04:58:18 +00:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2021-06-04 12:49:30 +00:00
|
|
|
#include <getopt.h>
|
2003-01-05 04:58:18 +00:00
|
|
|
#include <signal.h>
|
|
|
|
#include <stdlib.h>
|
2021-06-04 12:49:30 +00:00
|
|
|
#include <semaphore.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
|
|
#include <support/check.h>
|
|
|
|
#include <support/support.h>
|
|
|
|
#include <support/temp_file.h>
|
|
|
|
#include <support/xstdio.h>
|
|
|
|
#include <support/xunistd.h>
|
2016-12-09 07:18:27 +00:00
|
|
|
#include <support/xthread.h>
|
2003-01-05 04:58:18 +00:00
|
|
|
|
2021-06-04 12:49:30 +00:00
|
|
|
static const char *command;
|
|
|
|
static const char *pidfile;
|
|
|
|
static const char *semfile;
|
|
|
|
static char *pidfilename;
|
|
|
|
static char *semfilename;
|
|
|
|
|
|
|
|
static sem_t *sem;
|
2003-01-05 04:58:18 +00:00
|
|
|
|
nptl: Fix stray process left by tst-cancel7 blocking testing
Fix an issue with commit b74121ae4bc5 ("Update.") and prevent a stray
process from being left behind by tst-cancel7 (and also tst-cancelx7,
which is the same test built with '-fexceptions' additionally supplied
to the compiler), which then blocks remote testing until the process has
been killed by hand.
This test case creates a thread that runs an extra copy of the test via
system(3) and using the '--direct' option so that the test wrapper does
not interfere with this instance. This extra copy executes its business
and calls sigsuspend(2) and then never terminates by itself. Instead it
relies on being killed by the main test process directly via a thread
cancellation request or, should that fail, by issuing SIGKILL either at
the conclusion of 'do_test' or by the test driver via 'do_cleanup' where
the test timeout has been hit or the test driver interrupted.
However if the main test process has been instead killed by a signal,
such as due to incorrect execution, before it had a chance to kill the
extra copy of the test case, then the test wrapper will terminate
without running 'do_cleanup' and consequently the extra copy of the test
case will remain forever in its suspended state, and in the remote case
in particular it means that the remote test wrapper will wait forever
for the SSH command to complete.
This has been observed with the 'alpha-linux-gnu' target, where the main
test process triggers SIGSEGV and the test wrapper correctly records:
Didn't expect signal from child: got `Segmentation fault'
in nptl/tst-cancel7.out and terminates, but then the calling SSH command
continues waiting for the remaining process started in the same session
on the remote target to complete.
Address this problem by also registering 'do_cleanup' via atexit(3),
observing that 'support_delete_temp_files' is registered by the test
wrapper before the test initializing function 'do_prepare' is called and
that we call all the functions registered in the reverse of the order in
which they were registered, so it is safe to refer to 'pidfilename' in
'do_cleanup' invoked by exit(3) because by that time temporary files
have not yet been deleted.
A minor inconvenience is that if 'signal_handler' is invoked in the test
wrapper as a result of SIGALRM rather than SIGINT, then 'do_cleanup'
will be called twice, once as a cleanup handler and again by exit(3).
In reality it is harmless though, because issuing SIGKILL is guarded by
a record lock, so if the first call has succeeded in killing the extra
copy of the test case, then the subsequent call will do nothing.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2024-08-07 18:46:21 +00:00
|
|
|
static void do_cleanup (void);
|
|
|
|
|
2003-01-05 04:58:18 +00:00
|
|
|
static void *
|
|
|
|
tf (void *arg)
|
|
|
|
{
|
2021-06-04 12:49:30 +00:00
|
|
|
char *cmd = xasprintf ("%s --direct --sem %s --pidfile %s",
|
|
|
|
command, semfilename, pidfilename);
|
2023-06-14 08:52:07 +00:00
|
|
|
if (system (cmd))
|
|
|
|
FAIL_EXIT1("system call unexpectedly returned");
|
2003-01-05 04:58:18 +00:00
|
|
|
/* This call should never return. */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sl (void)
|
|
|
|
{
|
2021-06-04 12:49:30 +00:00
|
|
|
FILE *f = xfopen (pidfile, "w");
|
2003-01-05 04:58:18 +00:00
|
|
|
|
|
|
|
fprintf (f, "%lld\n", (long long) getpid ());
|
|
|
|
fflush (f);
|
|
|
|
|
|
|
|
struct flock fl =
|
|
|
|
{
|
|
|
|
.l_type = F_WRLCK,
|
|
|
|
.l_start = 0,
|
|
|
|
.l_whence = SEEK_SET,
|
|
|
|
.l_len = 1
|
|
|
|
};
|
|
|
|
if (fcntl (fileno (f), F_SETLK, &fl) != 0)
|
2021-06-04 12:49:30 +00:00
|
|
|
FAIL_EXIT1 ("fcntl (F_SETFL): %m");
|
2003-01-05 04:58:18 +00:00
|
|
|
|
2024-08-07 18:46:21 +00:00
|
|
|
if (sem_post (sem) != 0)
|
|
|
|
FAIL_EXIT1 ("sem_post: %m");
|
|
|
|
|
2003-01-05 04:58:18 +00:00
|
|
|
sigset_t ss;
|
|
|
|
sigfillset (&ss);
|
|
|
|
sigsuspend (&ss);
|
|
|
|
exit (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
do_prepare (int argc, char *argv[])
|
|
|
|
{
|
2021-06-04 12:49:30 +00:00
|
|
|
int semfd;
|
|
|
|
if (semfile == NULL)
|
|
|
|
semfd = create_temp_file ("tst-cancel7.", &semfilename);
|
|
|
|
else
|
|
|
|
semfd = open (semfile, O_RDWR);
|
|
|
|
TEST_VERIFY_EXIT (semfd != -1);
|
|
|
|
|
|
|
|
sem = xmmap (NULL, sizeof (sem_t), PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
|
|
semfd);
|
|
|
|
TEST_VERIFY_EXIT (sem != SEM_FAILED);
|
|
|
|
if (semfile == NULL)
|
|
|
|
{
|
|
|
|
xftruncate (semfd, sizeof (sem_t));
|
|
|
|
TEST_VERIFY_EXIT (sem_init (sem, 1, 0) != -1);
|
|
|
|
}
|
|
|
|
|
2003-01-05 04:58:18 +00:00
|
|
|
if (command == NULL)
|
|
|
|
command = argv[0];
|
|
|
|
|
|
|
|
if (pidfile)
|
|
|
|
sl ();
|
|
|
|
|
2021-06-04 12:49:30 +00:00
|
|
|
int fd = create_temp_file ("tst-cancel7-pid-", &pidfilename);
|
2003-01-05 04:58:18 +00:00
|
|
|
if (fd == -1)
|
2021-06-04 12:49:30 +00:00
|
|
|
FAIL_EXIT1 ("create_temp_file failed: %m");
|
2003-01-05 04:58:18 +00:00
|
|
|
|
2021-06-04 12:49:30 +00:00
|
|
|
xwrite (fd, " ", 1);
|
|
|
|
xclose (fd);
|
nptl: Fix stray process left by tst-cancel7 blocking testing
Fix an issue with commit b74121ae4bc5 ("Update.") and prevent a stray
process from being left behind by tst-cancel7 (and also tst-cancelx7,
which is the same test built with '-fexceptions' additionally supplied
to the compiler), which then blocks remote testing until the process has
been killed by hand.
This test case creates a thread that runs an extra copy of the test via
system(3) and using the '--direct' option so that the test wrapper does
not interfere with this instance. This extra copy executes its business
and calls sigsuspend(2) and then never terminates by itself. Instead it
relies on being killed by the main test process directly via a thread
cancellation request or, should that fail, by issuing SIGKILL either at
the conclusion of 'do_test' or by the test driver via 'do_cleanup' where
the test timeout has been hit or the test driver interrupted.
However if the main test process has been instead killed by a signal,
such as due to incorrect execution, before it had a chance to kill the
extra copy of the test case, then the test wrapper will terminate
without running 'do_cleanup' and consequently the extra copy of the test
case will remain forever in its suspended state, and in the remote case
in particular it means that the remote test wrapper will wait forever
for the SSH command to complete.
This has been observed with the 'alpha-linux-gnu' target, where the main
test process triggers SIGSEGV and the test wrapper correctly records:
Didn't expect signal from child: got `Segmentation fault'
in nptl/tst-cancel7.out and terminates, but then the calling SSH command
continues waiting for the remaining process started in the same session
on the remote target to complete.
Address this problem by also registering 'do_cleanup' via atexit(3),
observing that 'support_delete_temp_files' is registered by the test
wrapper before the test initializing function 'do_prepare' is called and
that we call all the functions registered in the reverse of the order in
which they were registered, so it is safe to refer to 'pidfilename' in
'do_cleanup' invoked by exit(3) because by that time temporary files
have not yet been deleted.
A minor inconvenience is that if 'signal_handler' is invoked in the test
wrapper as a result of SIGALRM rather than SIGINT, then 'do_cleanup'
will be called twice, once as a cleanup handler and again by exit(3).
In reality it is harmless though, because issuing SIGKILL is guarded by
a record lock, so if the first call has succeeded in killing the extra
copy of the test case, then the subsequent call will do nothing.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2024-08-07 18:46:21 +00:00
|
|
|
|
|
|
|
atexit (do_cleanup);
|
2003-01-05 04:58:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_test (void)
|
|
|
|
{
|
2021-06-04 12:49:30 +00:00
|
|
|
pthread_t th = xpthread_create (NULL, tf, NULL);
|
2003-01-05 04:58:18 +00:00
|
|
|
|
2024-08-07 18:46:21 +00:00
|
|
|
/* Wait to cancel until after the pid is written and file locked. */
|
2021-10-16 22:41:54 +00:00
|
|
|
if (sem_wait (sem) != 0)
|
|
|
|
FAIL_EXIT1 ("sem_wait: %m");
|
2003-01-05 04:58:18 +00:00
|
|
|
|
2016-12-09 07:18:27 +00:00
|
|
|
xpthread_cancel (th);
|
|
|
|
void *r = xpthread_join (th);
|
2003-01-05 04:58:18 +00:00
|
|
|
|
2021-06-04 12:49:30 +00:00
|
|
|
FILE *f = xfopen (pidfilename, "r+");
|
2003-01-05 04:58:18 +00:00
|
|
|
|
|
|
|
long long ll;
|
|
|
|
if (fscanf (f, "%lld\n", &ll) != 1)
|
2021-06-04 12:49:30 +00:00
|
|
|
FAIL_EXIT1 ("fscanf: %m");
|
2003-01-05 04:58:18 +00:00
|
|
|
|
|
|
|
struct flock fl =
|
|
|
|
{
|
|
|
|
.l_type = F_WRLCK,
|
|
|
|
.l_start = 0,
|
|
|
|
.l_whence = SEEK_SET,
|
|
|
|
.l_len = 1
|
|
|
|
};
|
|
|
|
if (fcntl (fileno (f), F_GETLK, &fl) != 0)
|
2021-06-04 12:49:30 +00:00
|
|
|
FAIL_EXIT1 ("fcntl: %m");
|
2003-01-05 04:58:18 +00:00
|
|
|
|
|
|
|
if (fl.l_type != F_UNLCK)
|
|
|
|
{
|
|
|
|
printf ("child %lld still running\n", (long long) fl.l_pid);
|
|
|
|
if (fl.l_pid == ll)
|
|
|
|
kill (fl.l_pid, SIGKILL);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-06-04 12:49:30 +00:00
|
|
|
xfclose (f);
|
2003-01-05 04:58:18 +00:00
|
|
|
|
|
|
|
return r != PTHREAD_CANCELED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
do_cleanup (void)
|
|
|
|
{
|
|
|
|
FILE *f = fopen (pidfilename, "r+");
|
|
|
|
long long ll;
|
|
|
|
|
|
|
|
if (f != NULL && fscanf (f, "%lld\n", &ll) == 1)
|
|
|
|
{
|
|
|
|
struct flock fl =
|
|
|
|
{
|
|
|
|
.l_type = F_WRLCK,
|
|
|
|
.l_start = 0,
|
|
|
|
.l_whence = SEEK_SET,
|
|
|
|
.l_len = 1
|
|
|
|
};
|
|
|
|
if (fcntl (fileno (f), F_GETLK, &fl) == 0 && fl.l_type != F_UNLCK
|
|
|
|
&& fl.l_pid == ll)
|
|
|
|
kill (fl.l_pid, SIGKILL);
|
|
|
|
|
|
|
|
fclose (f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define OPT_COMMAND 10000
|
|
|
|
#define OPT_PIDFILE 10001
|
2021-06-04 12:49:30 +00:00
|
|
|
#define OPT_SEMFILE 10002
|
2003-01-05 04:58:18 +00:00
|
|
|
#define CMDLINE_OPTIONS \
|
|
|
|
{ "command", required_argument, NULL, OPT_COMMAND }, \
|
2021-06-04 12:49:30 +00:00
|
|
|
{ "pidfile", required_argument, NULL, OPT_PIDFILE }, \
|
|
|
|
{ "sem", required_argument, NULL, OPT_SEMFILE },
|
2016-12-09 07:18:27 +00:00
|
|
|
static void
|
|
|
|
cmdline_process (int c)
|
|
|
|
{
|
|
|
|
switch (c)
|
|
|
|
{
|
2016-12-13 08:26:20 +00:00
|
|
|
case OPT_COMMAND:
|
2016-12-09 07:18:27 +00:00
|
|
|
command = optarg;
|
|
|
|
break;
|
|
|
|
case OPT_PIDFILE:
|
|
|
|
pidfile = optarg;
|
|
|
|
break;
|
2021-06-04 12:49:30 +00:00
|
|
|
case OPT_SEMFILE:
|
|
|
|
semfile = optarg;
|
|
|
|
break;
|
2016-12-09 07:18:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#define CMDLINE_PROCESS cmdline_process
|
|
|
|
#define CLEANUP_HANDLER do_cleanup
|
|
|
|
#define PREPARE do_prepare
|
|
|
|
#include <support/test-driver.c>
|