mirror of
https://sourceware.org/git/glibc.git
synced 2025-01-08 18:30:18 +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,
|
10153, 10210, 10254, 10346, 10545, 10716, 11174, 11322, 11365, 11451,
|
||||||
11494, 11521, 11837, 11959, 12047, 12340, 13058, 13525, 13526, 13527,
|
11494, 11521, 11837, 11959, 12047, 12340, 13058, 13525, 13526, 13527,
|
||||||
13528, 13529, 13530, 13531, 13532, 13533, 13547, 13551, 13552, 13553,
|
13528, 13529, 13530, 13531, 13532, 13533, 13547, 13551, 13552, 13553,
|
||||||
13555, 13559, 13563, 13566, 13583, 13592, 13618, 13637, 13656, 13658,
|
13555, 13559, 13563, 13566, 13583, 13592, 13613, 13618, 13637, 13656,
|
||||||
13673, 13691, 13695, 13704, 13705, 13706, 13726, 13738, 13739, 13750,
|
13658, 13673, 13691, 13695, 13704, 13705, 13706, 13726, 13738, 13739,
|
||||||
13758, 13760, 13761, 13775, 13786, 13787, 13792, 13806, 13824, 13840,
|
13750, 13758, 13760, 13761, 13775, 13786, 13787, 13792, 13806, 13824,
|
||||||
13841, 13844, 13846, 13851, 13852, 13854, 13871, 13872, 13873, 13879,
|
13840, 13841, 13844, 13846, 13851, 13852, 13854, 13871, 13872, 13873,
|
||||||
13883, 13884, 13885, 13886, 13892, 13895, 13908, 13910, 13911, 13912,
|
13879, 13883, 13884, 13885, 13886, 13892, 13895, 13908, 13910, 13911,
|
||||||
13913, 13914, 13915, 13916, 13917, 13918, 13919, 13920, 13921, 13922,
|
13912, 13913, 13914, 13915, 13916, 13917, 13918, 13919, 13920, 13921,
|
||||||
13923, 13924, 13926, 13927, 13928, 13938, 13941, 13942, 13954, 13955,
|
13922, 13923, 13924, 13926, 13927, 13928, 13938, 13941, 13942, 13954,
|
||||||
13956, 13963, 13967, 13970, 13973, 13979, 13983, 14012, 14027, 14033,
|
13955, 13956, 13963, 13967, 13970, 13973, 13979, 13983, 14012, 14027,
|
||||||
14034, 14040, 14049, 14053, 14055, 14064, 14080, 14083, 14103, 14104
|
14033, 14034, 14040, 14049, 14053, 14055, 14064, 14080, 14083, 14103,
|
||||||
|
14104
|
||||||
|
|
||||||
* ISO C11 support:
|
* 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>
|
2012-05-14 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
* sysdeps/x86_64/tls.h: Don't include <bits/wordsize.h>.
|
* 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-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \
|
||||||
tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \
|
tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \
|
||||||
tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel24 tst-cancel25 \
|
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-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \
|
||||||
tst-flock1 tst-flock2 \
|
tst-flock1 tst-flock2 \
|
||||||
tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
|
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
|
#else
|
||||||
struct
|
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 multiple_threads;
|
||||||
int gscope_flag;
|
int gscope_flag;
|
||||||
# ifndef __ASSUME_PRIVATE_FUTEX
|
# ifndef __ASSUME_PRIVATE_FUTEX
|
||||||
|
@ -378,7 +378,9 @@ extern int *__libc_pthread_init (unsigned long int *ptr,
|
|||||||
const struct pthread_functions *functions)
|
const struct pthread_functions *functions)
|
||||||
internal_function;
|
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;
|
extern int __pthread_multiple_threads attribute_hidden;
|
||||||
/* Pointer to the corresponding variable in libc. */
|
/* Pointer to the corresponding variable in libc. */
|
||||||
extern int *__libc_multiple_threads_ptr attribute_hidden;
|
extern int *__libc_multiple_threads_ptr attribute_hidden;
|
||||||
|
@ -95,6 +95,14 @@ pthread_cancel (th)
|
|||||||
|
|
||||||
break;
|
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
|
/* Mark the thread as canceled. This has to be done
|
||||||
atomically since other bits could be modified as well. */
|
atomically since other bits could be modified as well. */
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
|
|
||||||
#ifndef NOT_IN_libc
|
#ifndef NOT_IN_libc
|
||||||
# ifndef TLS_MULTIPLE_THREADS_IN_TCB
|
# 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;
|
int __libc_multiple_threads attribute_hidden;
|
||||||
# endif
|
# endif
|
||||||
#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;
|
int __is_smp attribute_hidden;
|
||||||
|
|
||||||
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
|
#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;
|
int __pthread_multiple_threads attribute_hidden;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user