1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-30 22:43:12 +03:00
* descr.h: Define CANCELING_BIT and CANCELING_BITMASK.  Introduce
	after CANCELTYPE_BIT, move the other bits up.  Update CANCEL_RESTMASK.
	* init.c (sigcancel_handler): Also set CANCELING_BITMASK bit in newval.
	* pthread_cancel.c (pthread_cancel): Likewise.  Also set CANCELING_BIT
	if asynchronous canceling is enabled.
	* pthread_join.c (pthread_join): When recognizing circular joins,
	take into account the other thread might be already canceled.
	* Makefile (tests): Add tst-join5.
	* tst-join5.c: New file.
This commit is contained in:
Ulrich Drepper
2003-02-14 18:33:54 +00:00
parent 700bf7af9f
commit e320ef46a7
8 changed files with 179 additions and 18 deletions

View File

@ -1,5 +1,15 @@
2003-02-14 Ulrich Drepper <drepper@redhat.com> 2003-02-14 Ulrich Drepper <drepper@redhat.com>
* descr.h: Define CANCELING_BIT and CANCELING_BITMASK. Introduce
after CANCELTYPE_BIT, move the other bits up. Update CANCEL_RESTMASK.
* init.c (sigcancel_handler): Also set CANCELING_BITMASK bit in newval.
* pthread_cancel.c (pthread_cancel): Likewise. Also set CANCELING_BIT
if asynchronous canceling is enabled.
* pthread_join.c (pthread_join): When recognizing circular joins,
take into account the other thread might be already canceled.
* Makefile (tests): Add tst-join5.
* tst-join5.c: New file.
* Makefile (tests): Add tst-join4. * Makefile (tests): Add tst-join4.
* tst-join4.c: New file. * tst-join4.c: New file.

View File

@ -137,7 +137,7 @@ tests = tst-attr1 tst-attr2 \
tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 \ tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 \
tst-barrier1 tst-barrier2 tst-barrier3 \ tst-barrier1 tst-barrier2 tst-barrier3 \
tst-basic1 tst-basic2 \ tst-basic1 tst-basic2 \
tst-join1 tst-join2 tst-join3 tst-join4 \ tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 \
tst-tsd1 tst-tsd2 \ tst-tsd1 tst-tsd2 \
tst-fork1 tst-fork2 tst-fork3 \ tst-fork1 tst-fork2 tst-fork3 \
tst-atfork1 \ tst-atfork1 \

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2002 Free Software Foundation, Inc. /* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@ -127,17 +127,20 @@ struct pthread
/* Bit set if asynchronous cancellation mode is selected. */ /* Bit set if asynchronous cancellation mode is selected. */
#define CANCELTYPE_BIT 1 #define CANCELTYPE_BIT 1
#define CANCELTYPE_BITMASK 0x02 #define CANCELTYPE_BITMASK 0x02
/* Bit set if canceling has been initiated. */
#define CANCELING_BIT 2
#define CANCELING_BITMASK 0x04
/* Bit set if canceled. */ /* Bit set if canceled. */
#define CANCELED_BIT 2 #define CANCELED_BIT 3
#define CANCELED_BITMASK 0x04 #define CANCELED_BITMASK 0x08
/* Bit set if thread is exiting. */ /* Bit set if thread is exiting. */
#define EXITING_BIT 3 #define EXITING_BIT 4
#define EXITING_BITMASK 0x08 #define EXITING_BITMASK 0x10
/* Bit set if thread terminated and TCB is freed. */ /* Bit set if thread terminated and TCB is freed. */
#define TERMINATED_BIT 4 #define TERMINATED_BIT 5
#define TERMINATED_BITMASK 0x10 #define TERMINATED_BITMASK 0x20
/* Mask for the rest. Helps the compiler to optimize. */ /* Mask for the rest. Helps the compiler to optimize. */
#define CANCEL_RESTMASK 0xffffffe0 #define CANCEL_RESTMASK 0xffffffc0
#define CANCEL_ENABLED_AND_CANCELED(value) \ #define CANCEL_ENABLED_AND_CANCELED(value) \
(((value) & (CANCELSTATE_BITMASK | CANCELED_BITMASK | EXITING_BITMASK \ (((value) & (CANCELSTATE_BITMASK | CANCELED_BITMASK | EXITING_BITMASK \

View File

@ -130,7 +130,7 @@ sigcancel_handler (int sig __attribute ((unused)))
is already set but if the signal is directly send (internally or is already set but if the signal is directly send (internally or
from another process) is has to be done here. */ from another process) is has to be done here. */
int oldval = THREAD_GETMEM (self, cancelhandling); int oldval = THREAD_GETMEM (self, cancelhandling);
int newval = oldval | CANCELED_BITMASK; int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
if (oldval == newval || (oldval & EXITING_BITMASK) != 0) if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
/* Already canceled or exiting. */ /* Already canceled or exiting. */

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2002 Free Software Foundation, Inc. /* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@ -31,7 +31,7 @@ pthread_cancel (th)
while (1) while (1)
{ {
int oldval = pd->cancelhandling; int oldval = pd->cancelhandling;
int newval = oldval | CANCELED_BITMASK; int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
/* Avoid doing unnecessary work. The atomic operation can /* Avoid doing unnecessary work. The atomic operation can
potentially be expensive if the bug has to be locked and potentially be expensive if the bug has to be locked and
@ -44,6 +44,9 @@ pthread_cancel (th)
expensive. */ expensive. */
if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
{ {
/* Mark the cancellation as "in progress". */
atomic_bit_set (&pd->cancelhandling, CANCELING_BIT);
/* The cancellation handler will take care of marking the /* The cancellation handler will take care of marking the
thread as canceled. */ thread as canceled. */
__pthread_kill (th, SIGCANCEL); __pthread_kill (th, SIGCANCEL);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2002 Free Software Foundation, Inc. /* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@ -50,7 +50,11 @@ pthread_join (threadid, thread_return)
return EINVAL; return EINVAL;
self = THREAD_SELF; self = THREAD_SELF;
if (pd == self || self->joinid == pd) if (pd == self
|| (self->joinid == pd
&& (pd->cancelhandling
& (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK
| TERMINATED_BITMASK)) == 0))
/* This is a deadlock situation. The threads are waiting for each /* This is a deadlock situation. The threads are waiting for each
other to finish. Note that this is a "may" error. To be 100% other to finish. Note that this is a "may" error. To be 100%
sure we catch this error we would have to lock the data sure we catch this error we would have to lock the data

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2002 Free Software Foundation, Inc. /* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@ -42,15 +42,15 @@
mq_send() mq_timedreceive() mq_timedsend() mq_send() mq_timedreceive() mq_timedsend()
msgrcv() msgsnd() msync() msgrcv() msgsnd() msync()
open() pause() open() pause()
pread() pthread_cond_timedwait() pread()
pthread_cond_wait() pthread_join() pthread_testcancel() pthread_join() pthread_testcancel()
putmsg() putpmsg() pwrite() putmsg() putpmsg() pwrite()
recv() recv()
recvfrom() recvmsg() recvfrom() recvmsg()
sem_timedwait() sem_wait() send() sem_timedwait() sem_wait() send()
sendmsg() sendto() sigpause() sendmsg() sendto() sigpause()
sigsuspend() sigtimedwait() sigwait() sigsuspend() sigtimedwait() sigwait()
sigwaitinfo() system() sigwaitinfo()
tcdrain() tcdrain()
Since STREAMS are not supported in the standard Linux kernel there Since STREAMS are not supported in the standard Linux kernel there

141
nptl/tst-join5.c Normal file
View File

@ -0,0 +1,141 @@
/* Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
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, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
static void *
tf1 (void *arg)
{
pthread_join (arg, NULL);
puts ("1st join returned");
return (void *) 1l;
}
static void *
tf2 (void *arg)
{
pthread_join (arg, NULL);
puts ("2nd join returned");
return (void *) 1l;
}
static int
do_test (void)
{
pthread_t th;
int err = pthread_join (pthread_self (), NULL);
if (err == 0)
{
puts ("1st circular join succeeded");
exit (1);
}
if (err != EDEADLK)
{
printf ("1st circular join %d, not EDEADLK\n", err);
exit (1);
}
if (pthread_create (&th, NULL, tf1, (void *) pthread_self ()) != 0)
{
puts ("1st create failed");
exit (1);
}
if (pthread_cancel (th) != 0)
{
puts ("cannot cancel 1st thread");
exit (1);
}
void *r;
err = pthread_join (th, &r);
if (err != 0)
{
printf ("cannot join 1st thread: %d\n", err);
exit (1);
}
if (r != PTHREAD_CANCELED)
{
puts ("1st thread not canceled");
exit (1);
}
err = pthread_join (pthread_self (), NULL);
if (err == 0)
{
puts ("2nd circular join succeeded");
exit (1);
}
if (err != EDEADLK)
{
printf ("2nd circular join %d, not EDEADLK\n", err);
exit (1);
}
if (pthread_create (&th, NULL, tf2, (void *) pthread_self ()) != 0)
{
puts ("2nd create failed");
exit (1);
}
if (pthread_cancel (th) != 0)
{
puts ("cannot cancel 2nd thread");
exit (1);
}
if (pthread_join (th, &r) != 0)
{
puts ("cannot join 2nd thread");
exit (1);
}
if (r != PTHREAD_CANCELED)
{
puts ("2nd thread not canceled");
exit (1);
}
err = pthread_join (pthread_self (), NULL);
if (err == 0)
{
puts ("2nd circular join succeeded");
exit (1);
}
if (err != EDEADLK)
{
printf ("2nd circular join %d, not EDEADLK\n", err);
exit (1);
}
exit (0);
}
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"