mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-22 19:00:07 +00:00
Allow a single-threaded program to cancel itself
There is nothing in the POSIX specification to disallow a single-threaded program from cancelling itself, so we forcibly enable multiple_threads to allow the next available cancellation point in the thread to run. Also added additional tests to cover various cancellation scenarios.
This commit is contained in:
parent
2949684c16
commit
439bf404b8
19
NEWS
19
NEWS
@ -17,15 +17,16 @@ Version 2.16
|
||||
10153, 10210, 10254, 10346, 10545, 10716, 11174, 11322, 11365, 11451,
|
||||
11494, 11521, 11837, 11959, 12047, 12340, 13058, 13525, 13526, 13527,
|
||||
13528, 13529, 13530, 13531, 13532, 13533, 13547, 13551, 13552, 13553,
|
||||
13555, 13559, 13563, 13566, 13583, 13592, 13618, 13637, 13656, 13658,
|
||||
13673, 13691, 13695, 13704, 13705, 13706, 13726, 13738, 13739, 13750,
|
||||
13758, 13760, 13761, 13775, 13786, 13787, 13792, 13806, 13824, 13840,
|
||||
13841, 13844, 13846, 13851, 13852, 13854, 13871, 13872, 13873, 13879,
|
||||
13883, 13884, 13885, 13886, 13892, 13895, 13908, 13910, 13911, 13912,
|
||||
13913, 13914, 13915, 13916, 13917, 13918, 13919, 13920, 13921, 13922,
|
||||
13923, 13924, 13926, 13927, 13928, 13938, 13941, 13942, 13954, 13955,
|
||||
13956, 13963, 13967, 13970, 13973, 13979, 13983, 14012, 14027, 14033,
|
||||
14034, 14040, 14049, 14053, 14055, 14064, 14080, 14083, 14103, 14104
|
||||
13555, 13559, 13563, 13566, 13583, 13592, 13613, 13618, 13637, 13656,
|
||||
13658, 13673, 13691, 13695, 13704, 13705, 13706, 13726, 13738, 13739,
|
||||
13750, 13758, 13760, 13761, 13775, 13786, 13787, 13792, 13806, 13824,
|
||||
13840, 13841, 13844, 13846, 13851, 13852, 13854, 13871, 13872, 13873,
|
||||
13879, 13883, 13884, 13885, 13886, 13892, 13895, 13908, 13910, 13911,
|
||||
13912, 13913, 13914, 13915, 13916, 13917, 13918, 13919, 13920, 13921,
|
||||
13922, 13923, 13924, 13926, 13927, 13928, 13938, 13941, 13942, 13954,
|
||||
13955, 13956, 13963, 13967, 13970, 13973, 13979, 13983, 14012, 14027,
|
||||
14033, 14034, 14040, 14049, 14053, 14055, 14064, 14080, 14083, 14103,
|
||||
14104
|
||||
|
||||
* ISO C11 support:
|
||||
|
||||
|
@ -1,3 +1,22 @@
|
||||
2012-05-15 Siddhesh Poyarekar <siddhesh@redhat.com>
|
||||
Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
[BZ #13613]
|
||||
* Makefile (tests): Add test cases.
|
||||
* descr.h (struct pthread): Add a comment describing multiple_threads.
|
||||
* pthreadP.h (__pthread_multiple_threads): Expand comment to include
|
||||
single-process case.
|
||||
* pthread_cancel.c (pthread_cancel): Enable multiple_threads
|
||||
before setting cancelstate of the thread.
|
||||
* sysdeps/unix/sysv/linux/libc_multiple_threads.c
|
||||
(__libc_multiple_threads): Add explanatory comment.
|
||||
* tst-cancel-self-cancelstate.c: New test case.
|
||||
* tst-cancel-self-canceltype.c: Likewise.
|
||||
* tst-cancel-self-cleanup.c: Supporting file for test cases.
|
||||
* tst-cancel-self-testcancel.c: New test case.
|
||||
* tst-cancel-self.c: Likewise.
|
||||
* vars.c: Expand comment to include single-process case.
|
||||
|
||||
2012-05-14 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
* sysdeps/x86_64/tls.h: Don't include <bits/wordsize.h>.
|
||||
|
@ -236,6 +236,8 @@ tests = tst-typesizes \
|
||||
tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \
|
||||
tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \
|
||||
tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel24 tst-cancel25 \
|
||||
tst-cancel-self tst-cancel-self-cancelstate \
|
||||
tst-cancel-self-canceltype tst-cancel-self-testcancel \
|
||||
tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \
|
||||
tst-flock1 tst-flock2 \
|
||||
tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
|
||||
|
15
nptl/descr.h
15
nptl/descr.h
@ -131,6 +131,21 @@ struct pthread
|
||||
#else
|
||||
struct
|
||||
{
|
||||
/* multiple_threads is enabled either when the process has spawned at
|
||||
least one thread or when a single-threaded process cancels itself.
|
||||
This enables additional code to introduce locking before doing some
|
||||
compare_and_exchange operations and also enable cancellation points.
|
||||
The concepts of multiple threads and cancellation points ideally
|
||||
should be separate, since it is not necessary for multiple threads to
|
||||
have been created for cancellation points to be enabled, as is the
|
||||
case is when single-threaded process cancels itself.
|
||||
|
||||
Since enabling multiple_threads enables additional code in
|
||||
cancellation points and compare_and_exchange operations, there is a
|
||||
potential for an unneeded performance hit when it is enabled in a
|
||||
single-threaded, self-canceling process. This is OK though, since a
|
||||
single-threaded process will enable async cancellation only when it
|
||||
looks to cancel itself and is hence going to end anyway. */
|
||||
int multiple_threads;
|
||||
int gscope_flag;
|
||||
# ifndef __ASSUME_PRIVATE_FUTEX
|
||||
|
@ -378,7 +378,9 @@ extern int *__libc_pthread_init (unsigned long int *ptr,
|
||||
const struct pthread_functions *functions)
|
||||
internal_function;
|
||||
|
||||
/* Variable set to a nonzero value if more than one thread runs or ran. */
|
||||
/* Variable set to a nonzero value either if more than one thread runs or ran,
|
||||
or if a single-threaded process is trying to cancel itself. See
|
||||
nptl/descr.h for more context on the single-threaded process case. */
|
||||
extern int __pthread_multiple_threads attribute_hidden;
|
||||
/* Pointer to the corresponding variable in libc. */
|
||||
extern int *__libc_multiple_threads_ptr attribute_hidden;
|
||||
|
@ -95,6 +95,14 @@ pthread_cancel (th)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* A single-threaded process should be able to kill itself, since there is
|
||||
nothing in the POSIX specification that says that it cannot. So we set
|
||||
multiple_threads to true so that cancellation points get executed. */
|
||||
THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
|
||||
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
|
||||
__pthread_multiple_threads = *__libc_multiple_threads_ptr = 1;
|
||||
#endif
|
||||
}
|
||||
/* Mark the thread as canceled. This has to be done
|
||||
atomically since other bits could be modified as well. */
|
||||
|
@ -20,6 +20,9 @@
|
||||
|
||||
#ifndef NOT_IN_libc
|
||||
# ifndef TLS_MULTIPLE_THREADS_IN_TCB
|
||||
/* Variable set to a nonzero value either if more than one thread runs or ran,
|
||||
or if a single-threaded process is trying to cancel itself. See
|
||||
nptl/descr.h for more context on the single-threaded process case. */
|
||||
int __libc_multiple_threads attribute_hidden;
|
||||
# endif
|
||||
#endif
|
||||
|
65
nptl/tst-cancel-self-cancelstate.c
Normal file
65
nptl/tst-cancel-self-cancelstate.c
Normal file
@ -0,0 +1,65 @@
|
||||
/* Copyright (C) 2012 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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "tst-cancel-self-cleanup.c"
|
||||
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int ret = 0;
|
||||
volatile int should_fail = 1;
|
||||
|
||||
pthread_cleanup_push (cleanup, &should_fail);
|
||||
|
||||
if ((ret = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL)) != 0)
|
||||
{
|
||||
printf ("setcancelstate(disable) failed: %s\n", strerror (ret));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if ((ret = pthread_cancel (pthread_self ())) != 0)
|
||||
{
|
||||
printf ("cancel failed: %s\n", strerror (ret));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
usleep (100);
|
||||
should_fail = 0;
|
||||
|
||||
if ((ret = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL)) != 0)
|
||||
{
|
||||
printf ("setcancelstate(enable) failed: %s\n", strerror (ret));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* The write syscall within this printf should give us our cancellation
|
||||
point. */
|
||||
printf ("Could not cancel self.\n");
|
||||
pthread_cleanup_pop (0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
53
nptl/tst-cancel-self-canceltype.c
Normal file
53
nptl/tst-cancel-self-canceltype.c
Normal file
@ -0,0 +1,53 @@
|
||||
/* Copyright (C) 2012 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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "tst-cancel-self-cleanup.c"
|
||||
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int ret = 0, should_fail = 0;
|
||||
|
||||
pthread_cleanup_push (cleanup, &should_fail);
|
||||
|
||||
if ((ret = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) != 0)
|
||||
{
|
||||
printf ("setcanceltype failed: %s\n", strerror (ret));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if ((ret = pthread_cancel (pthread_self ())) != 0)
|
||||
{
|
||||
printf ("cancel failed: %s\n", strerror (ret));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Wait to be canceled. Don't give any cancellation points to play with. */
|
||||
while (1);
|
||||
pthread_cleanup_pop (0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
23
nptl/tst-cancel-self-cleanup.c
Normal file
23
nptl/tst-cancel-self-cleanup.c
Normal file
@ -0,0 +1,23 @@
|
||||
/* Copyright (C) 2012 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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
static void
|
||||
cleanup (void *cleanup_should_fail)
|
||||
{
|
||||
printf ("Main thread got cancelled and is being cleaned up now\n");
|
||||
exit (*(int *)cleanup_should_fail);
|
||||
}
|
48
nptl/tst-cancel-self-testcancel.c
Normal file
48
nptl/tst-cancel-self-testcancel.c
Normal file
@ -0,0 +1,48 @@
|
||||
/* Copyright (C) 2012 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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "tst-cancel-self-cleanup.c"
|
||||
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int ret = 0, should_fail = 0;
|
||||
|
||||
pthread_cleanup_push (cleanup, &should_fail);
|
||||
if ((ret = pthread_cancel (pthread_self ())) != 0)
|
||||
{
|
||||
printf ("cancel failed: %s\n", strerror (ret));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
pthread_testcancel ();
|
||||
|
||||
printf ("Could not cancel self.\n");
|
||||
pthread_cleanup_pop (0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
48
nptl/tst-cancel-self.c
Normal file
48
nptl/tst-cancel-self.c
Normal file
@ -0,0 +1,48 @@
|
||||
/* Copyright (C) 2012 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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "tst-cancel-self-cleanup.c"
|
||||
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int ret = 0, should_fail = 0;
|
||||
|
||||
pthread_cleanup_push (cleanup, &should_fail);
|
||||
if ((ret = pthread_cancel (pthread_self ())) != 0)
|
||||
{
|
||||
printf ("cancel failed: %s\n", strerror (ret));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* The write syscall within this printf should give us our cancellation
|
||||
point. */
|
||||
printf ("Could not cancel self.\n");
|
||||
pthread_cleanup_pop (0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
@ -32,7 +32,9 @@ size_t __default_stacksize attribute_hidden
|
||||
int __is_smp attribute_hidden;
|
||||
|
||||
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
|
||||
/* Variable set to a nonzero value if more than one thread runs or ran. */
|
||||
/* Variable set to a nonzero value either if more than one thread runs or ran,
|
||||
or if a single-threaded process is trying to cancel itself. See
|
||||
nptl/descr.h for more context on the single-threaded process case. */
|
||||
int __pthread_multiple_threads attribute_hidden;
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user