From patchwork Wed May 20 17:48:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 39341 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6BE553887002; Wed, 20 May 2020 17:48:30 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6BE553887002 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1589996910; bh=l60QfOkQTTKEOmx8iv/KrvrTP1XKjXWowe+rAmvxweE=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=Rizj8CWfjYRZ5+4p8XBNE1hvzp7yIW4Yh6G12/NXW9yUMR4ucMQ1cgp7LxoDUirNc EQOCPboejUB7Lk94g+bvv2wZzVRYpGR90yLzYbHfW/YPKX3ADaSUOe4Ctg2UOXc3p1 vm1cCbOBUCLPZxtapGkEywjTNU+sOE/x2nizt6PI= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x742.google.com (mail-qk1-x742.google.com [IPv6:2607:f8b0:4864:20::742]) by sourceware.org (Postfix) with ESMTPS id C94FD386F41D for ; Wed, 20 May 2020 17:48:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org C94FD386F41D Received: by mail-qk1-x742.google.com with SMTP id m11so4477743qka.4 for ; Wed, 20 May 2020 10:48:26 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=l60QfOkQTTKEOmx8iv/KrvrTP1XKjXWowe+rAmvxweE=; b=aGzd8YTn2rhbr8Mw5JnbDRRf2rLyGZ5PmKXfsbDGYh2CQ9/Xq4bSXmwtS5XDBpGKwh SnHPrNZwl0UrVLv3YOyqSqOua2e0wjKbev7JFxDhTvIotEnsr/qsinFOMVzedIqDf2Ym QzkLyDI4JhLum18j4fVq1BpZAWco7xnrH8rIcTxqLuTY1tkcIFTsiautkXLf4PzwzA0s uAwWprIbGV4idvUy7T9l1BDEsBl7O7IDAEm7dLJk9hvgo7jMBLbEWskah+O87PCZOrdg qbaSghoPt6fLRlVMcqk2pShNB3V2CO2sg0LuHHDGG69K3qIPil4TwSNiVJuy+Y1I+a+W kFAg== X-Gm-Message-State: AOAM5328iUL/v1zDjPSG/hAw13pnbH4Q21adV6uyzIOdZu9Bj4Xesq3t U3BawQGhWE4lbjLyvj9jsFOGRbzk3kI= X-Google-Smtp-Source: ABdhPJx012MFmMh1ky4TTiDRT4WNLznEGIdgQto8irtWZmsY7vO9dLiWq1D9Zt7M+A0aI+Ix7gKBzA== X-Received: by 2002:a05:620a:10a5:: with SMTP id h5mr6217394qkk.388.1589996905755; Wed, 20 May 2020 10:48:25 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id g11sm2589014qkk.106.2020.05.20.10.48.23 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 May 2020 10:48:24 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v2 1/2] nptl: Move cancel state out of cancelhandling Date: Wed, 20 May 2020 14:48:18 -0300 Message-Id: <20200520174819.1138124-1-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-Spam-Status: No, score=-15.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" Changes from previous version: - Extended commit message. - Extended some comments. --- The thread cancellation state is not accessed concurrently internally neither the pthread interface allows changing the state of a different thread than its own. By removing the cancel state out of the internal thread cancel handling state there is no need to check if cancelled bit was set in CAS operation. The code is also simplified: the CANCELLATION_P is replaced with a internal pthread_testcancel call and the CANCELSTATE_BIT{MASK} is removed. The second part of this patchset also keeps the pthread_setcanceltype as cancellation entrypoint by calling pthread_testcancel if the new type is PTHREAD_CANCEL_ASYNCHRONOUS. With this behavior pthread_setcancelstate does not require to act on cancellation if cancel type is asynchronous (is already handled either by pthread_setcanceltype or by the signal handler). Checked on x86_64-linux-gnu. --- nptl/allocatestack.c | 1 + nptl/cancellation.c | 3 ++- nptl/cleanup_defer.c | 2 +- nptl/cleanup_defer_compat.c | 2 +- nptl/descr.h | 14 ++++++-------- nptl/pthreadP.h | 12 ------------ nptl/pthread_cancel.c | 3 ++- nptl/pthread_join_common.c | 5 ++++- nptl/pthread_setcancelstate.c | 36 +++-------------------------------- nptl/pthread_setcanceltype.c | 3 ++- nptl/pthread_testcancel.c | 11 ++++++++++- 11 files changed, 32 insertions(+), 60 deletions(-) diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index c94980c21c..d9174274c2 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -232,6 +232,7 @@ get_cached_stack (size_t *sizep, void **memp) /* Cancellation handling is back to the default. */ result->cancelhandling = 0; + result->cancelstate = PTHREAD_CANCEL_ENABLE; result->cleanup = NULL; /* No pending event. */ diff --git a/nptl/cancellation.c b/nptl/cancellation.c index 826071321e..7e8cbe9fe1 100644 --- a/nptl/cancellation.c +++ b/nptl/cancellation.c @@ -45,7 +45,8 @@ __pthread_enable_asynccancel (void) oldval); if (__glibc_likely (curval == oldval)) { - if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) + if (self->cancelstate == PTHREAD_CANCEL_ENABLE + && CANCEL_CANCELED_AND_ASYNCHRONOUS (newval)) { THREAD_SETMEM (self, result, PTHREAD_CANCELED); __do_cancel (); diff --git a/nptl/cleanup_defer.c b/nptl/cleanup_defer.c index 8ad9a90c50..33d4ea6eef 100644 --- a/nptl/cleanup_defer.c +++ b/nptl/cleanup_defer.c @@ -86,6 +86,6 @@ __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *buf) cancelhandling = curval; } - CANCELLATION_P (self); + __pthread_testcancel (); } } diff --git a/nptl/cleanup_defer_compat.c b/nptl/cleanup_defer_compat.c index 33e47888f2..a1ad291fcc 100644 --- a/nptl/cleanup_defer_compat.c +++ b/nptl/cleanup_defer_compat.c @@ -83,7 +83,7 @@ _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, cancelhandling = curval; } - CANCELLATION_P (self); + __pthread_testcancel (); } /* If necessary call the cleanup routine after we removed the diff --git a/nptl/descr.h b/nptl/descr.h index e1c7db5473..279df680d6 100644 --- a/nptl/descr.h +++ b/nptl/descr.h @@ -269,9 +269,6 @@ struct pthread /* Flags determining processing of cancellation. */ int cancelhandling; - /* Bit set if cancellation is disabled. */ -#define CANCELSTATE_BIT 0 -#define CANCELSTATE_BITMASK (0x01 << CANCELSTATE_BIT) /* Bit set if asynchronous cancellation mode is selected. */ #define CANCELTYPE_BIT 1 #define CANCELTYPE_BITMASK (0x01 << CANCELTYPE_BIT) @@ -293,11 +290,8 @@ struct pthread /* Mask for the rest. Helps the compiler to optimize. */ #define CANCEL_RESTMASK 0xffffff80 -#define CANCEL_ENABLED_AND_CANCELED(value) \ - (((value) & (CANCELSTATE_BITMASK | CANCELED_BITMASK | EXITING_BITMASK \ - | CANCEL_RESTMASK | TERMINATED_BITMASK)) == CANCELED_BITMASK) -#define CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS(value) \ - (((value) & (CANCELSTATE_BITMASK | CANCELTYPE_BITMASK | CANCELED_BITMASK \ +#define CANCEL_CANCELED_AND_ASYNCHRONOUS(value) \ + (((value) & (CANCELTYPE_BITMASK | CANCELED_BITMASK \ | EXITING_BITMASK | CANCEL_RESTMASK | TERMINATED_BITMASK)) \ == (CANCELTYPE_BITMASK | CANCELED_BITMASK)) @@ -398,6 +392,10 @@ struct pthread /* Indicates whether is a C11 thread created by thrd_creat. */ bool c11; + /* Thread cancel state (PTHREAD_CANCEL_ENABLE or + PTHREAD_CANCEL_DISABLE). */ + unsigned char cancelstate; + /* This member must be last. */ char end_padding[]; diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index c4e72f57a9..7fe7d7f064 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -258,18 +258,6 @@ extern int __pthread_debug attribute_hidden; #endif -/* Cancellation test. */ -#define CANCELLATION_P(self) \ - do { \ - int cancelhandling = THREAD_GETMEM (self, cancelhandling); \ - if (CANCEL_ENABLED_AND_CANCELED (cancelhandling)) \ - { \ - THREAD_SETMEM (self, result, PTHREAD_CANCELED); \ - __do_cancel (); \ - } \ - } while (0) - - extern void __pthread_unwind (__pthread_unwind_buf_t *__buf) __cleanup_fct_attribute __attribute ((__noreturn__)) #if !defined SHARED && !IS_IN (libpthread) diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c index 88c1ab8f6a..5b2789d620 100644 --- a/nptl/pthread_cancel.c +++ b/nptl/pthread_cancel.c @@ -55,7 +55,8 @@ __pthread_cancel (pthread_t th) /* If the cancellation is handled asynchronously just send a signal. We avoid this if possible since it's more expensive. */ - if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) + if (pd->cancelstate == PTHREAD_CANCEL_ENABLE + && CANCEL_CANCELED_AND_ASYNCHRONOUS (newval)) { /* Mark the cancellation as "in progress". */ if (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, diff --git a/nptl/pthread_join_common.c b/nptl/pthread_join_common.c index a96ceafde4..03e202136f 100644 --- a/nptl/pthread_join_common.c +++ b/nptl/pthread_join_common.c @@ -105,7 +105,10 @@ __pthread_clockjoin_ex (pthread_t threadid, void **thread_return, && (pd->cancelhandling & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK | TERMINATED_BITMASK)) == 0)) - && !CANCEL_ENABLED_AND_CANCELED (self->cancelhandling)) + && !(self->cancelstate == PTHREAD_CANCEL_ENABLE + && (pd->cancelhandling & (CANCELED_BITMASK | EXITING_BITMASK + | TERMINATED_BITMASK)) + == CANCELED_BITMASK)) /* This is a deadlock situation. The threads are waiting for each 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 diff --git a/nptl/pthread_setcancelstate.c b/nptl/pthread_setcancelstate.c index 4d7f413e19..aa1c8073a8 100644 --- a/nptl/pthread_setcancelstate.c +++ b/nptl/pthread_setcancelstate.c @@ -31,39 +31,9 @@ __pthread_setcancelstate (int state, int *oldstate) self = THREAD_SELF; - int oldval = THREAD_GETMEM (self, cancelhandling); - while (1) - { - int newval = (state == PTHREAD_CANCEL_DISABLE - ? oldval | CANCELSTATE_BITMASK - : oldval & ~CANCELSTATE_BITMASK); - - /* Store the old value. */ - if (oldstate != NULL) - *oldstate = ((oldval & CANCELSTATE_BITMASK) - ? PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE); - - /* Avoid doing unnecessary work. The atomic operation can - potentially be expensive if the memory has to be locked and - remote cache lines have to be invalidated. */ - if (oldval == newval) - break; - - /* Update the cancel handling word. This has to be done - atomically since other bits could be modified as well. */ - int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, - oldval); - if (__glibc_likely (curval == oldval)) - { - if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) - __do_cancel (); - - break; - } - - /* Prepare for the next round. */ - oldval = curval; - } + if (oldstate != NULL) + *oldstate = self->cancelstate; + self->cancelstate = state; return 0; } diff --git a/nptl/pthread_setcanceltype.c b/nptl/pthread_setcanceltype.c index fcaae8abc7..cc0507ae04 100644 --- a/nptl/pthread_setcanceltype.c +++ b/nptl/pthread_setcanceltype.c @@ -53,7 +53,8 @@ __pthread_setcanceltype (int type, int *oldtype) oldval); if (__glibc_likely (curval == oldval)) { - if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) + if (self->cancelstate == PTHREAD_CANCEL_ENABLE + && CANCEL_CANCELED_AND_ASYNCHRONOUS (newval)) { THREAD_SETMEM (self, result, PTHREAD_CANCELED); __do_cancel (); diff --git a/nptl/pthread_testcancel.c b/nptl/pthread_testcancel.c index 30408c2008..cd937bb3a3 100644 --- a/nptl/pthread_testcancel.c +++ b/nptl/pthread_testcancel.c @@ -23,7 +23,16 @@ void __pthread_testcancel (void) { - CANCELLATION_P (THREAD_SELF); + struct pthread *self = THREAD_SELF; + int cancelhandling = THREAD_GETMEM (self, cancelhandling); + if (self->cancelstate == PTHREAD_CANCEL_ENABLE + && (cancelhandling & CANCELED_BITMASK) + && !(cancelhandling & EXITING_BITMASK) + && !(cancelhandling & TERMINATED_BITMASK)) + { + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + __do_cancel (); + } } strong_alias (__pthread_testcancel, pthread_testcancel) hidden_def (__pthread_testcancel) From patchwork Wed May 20 17:48:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 39342 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 03014395C05E; Wed, 20 May 2020 17:48:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 03014395C05E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1589996911; bh=Mt5gTQD2gnEdCz/JB2j9TC51dJKVDEj2j34J1w7h030=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=jMwL/63b2FDGRTH31a4Gef0AbojL600vDKl827fe2jNdTK0C/fGSE8z9gIUnXd0Bw 8wxouIEIheuHtD3bLGAoc7ooPBN6r3KeEbrbCgqmIM+aBeICbmqa3pBUA842WSiHVt u6kLMv/3VZUKMzxDGakFQmaQHzUcu5+5PBa7g3qE= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qt1-x843.google.com (mail-qt1-x843.google.com [IPv6:2607:f8b0:4864:20::843]) by sourceware.org (Postfix) with ESMTPS id 2C0A23887002 for ; Wed, 20 May 2020 17:48:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 2C0A23887002 Received: by mail-qt1-x843.google.com with SMTP id x12so3234505qts.9 for ; Wed, 20 May 2020 10:48:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Mt5gTQD2gnEdCz/JB2j9TC51dJKVDEj2j34J1w7h030=; b=GdU3gTxlIGc6fuH0IoSfMk6CIgEMQpRHc/5f0suLL7cohC3fn6yvFSyLGS2ZyGOVKm DqSTh4F1ENDzTyPT9GypMop0CUSln5hcN44MC63/LDBrjyhkm6u8Wb4ByMqgs+avYsoc 8Y1QrnuHxJGP+WjUFAC7pG9W6kpEdeDC9UsalYo0GhYoCi+9qMFcoiovpqOl5B0HMLlT 7kIoSxtSqBGy744mUUpzO3wqOAqbJ0zWBfvLoRHI5URDt+3OsTgv0aY7QXIC8I1PQPwW NvrMTQfHODh4nH5jL5jI1MpmvGgHPyDpm/pqCD2qeQWicuDE8ddhHXJJIy+xsWPI/ABN EamA== X-Gm-Message-State: AOAM531QAqfNBSUiRgF6OID2pbvpYNFweLjGT3VioP01fWxzvNeUUMCq 2TaCAVqr47CLqBtGrAV8g2HghGhUFV4= X-Google-Smtp-Source: ABdhPJxM2oFICJ35PjxVqTUyHaVHy0SscUSURVDlghZObYjFt91JyG8u6t94CYICKbyEY7Zs9eUxeQ== X-Received: by 2002:ac8:18a3:: with SMTP id s32mr6542602qtj.102.1589996907145; Wed, 20 May 2020 10:48:27 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id g11sm2589014qkk.106.2020.05.20.10.48.26 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 May 2020 10:48:26 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v2 2/2] nptl: Move cancel type out of cancelhandling Date: Wed, 20 May 2020 14:48:19 -0300 Message-Id: <20200520174819.1138124-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200520174819.1138124-1-adhemerval.zanella@linaro.org> References: <20200520174819.1138124-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-15.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" Changes from previous version: - Extended some comments. --- The thread cancellation type is not accessed concurrently internally neither its pthread interface allows changing the state of a different thread than its own. By removing the cancel state out of the internal thread cancel handling state there is no need to check if cancelled bit was set in CAS operation. It allows simplifing the cancellation wrappers and the CANCEL_CANCELED_AND_ASYNCHRONOUS is removed. Checked on x86_64-linux-gnu. --- nptl/allocatestack.c | 1 + nptl/cancellation.c | 60 ++++++++++-------------------------- nptl/cleanup_defer.c | 46 +++------------------------ nptl/cleanup_defer_compat.c | 46 +++------------------------ nptl/descr.h | 14 +++------ nptl/nptl-init.c | 2 +- nptl/pthread_cancel.c | 5 ++- nptl/pthread_setcanceltype.c | 42 +++---------------------- nptl/pthread_testcancel.c | 2 +- 9 files changed, 43 insertions(+), 175 deletions(-) diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index d9174274c2..481487bbb4 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -233,6 +233,7 @@ get_cached_stack (size_t *sizep, void **memp) /* Cancellation handling is back to the default. */ result->cancelhandling = 0; result->cancelstate = PTHREAD_CANCEL_ENABLE; + result->canceltype = PTHREAD_CANCEL_DEFERRED; result->cleanup = NULL; /* No pending event. */ diff --git a/nptl/cancellation.c b/nptl/cancellation.c index 7e8cbe9fe1..90974c0b18 100644 --- a/nptl/cancellation.c +++ b/nptl/cancellation.c @@ -32,31 +32,19 @@ attribute_hidden __pthread_enable_asynccancel (void) { struct pthread *self = THREAD_SELF; - int oldval = THREAD_GETMEM (self, cancelhandling); - while (1) - { - int newval = oldval | CANCELTYPE_BITMASK; - - if (newval == oldval) - break; - - int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, - oldval); - if (__glibc_likely (curval == oldval)) - { - if (self->cancelstate == PTHREAD_CANCEL_ENABLE - && CANCEL_CANCELED_AND_ASYNCHRONOUS (newval)) - { - THREAD_SETMEM (self, result, PTHREAD_CANCELED); - __do_cancel (); - } + int oldval = THREAD_GETMEM (self, canceltype); + THREAD_SETMEM (self, canceltype, PTHREAD_CANCEL_ASYNCHRONOUS); - break; - } + int ch = THREAD_GETMEM (self, cancelhandling); - /* Prepare the next round. */ - oldval = curval; + if (self->cancelstate == PTHREAD_CANCEL_ENABLE + && (ch & CANCELED_BITMASK) + && !(ch & EXITING_BITMASK) + && !(ch & TERMINATED_BITMASK)) + { + THREAD_SETMEM (self, result, PTHREAD_CANCELED); + __do_cancel (); } return oldval; @@ -70,36 +58,22 @@ __pthread_disable_asynccancel (int oldtype) { /* If asynchronous cancellation was enabled before we do not have anything to do. */ - if (oldtype & CANCELTYPE_BITMASK) + if (oldtype == PTHREAD_CANCEL_ASYNCHRONOUS) return; struct pthread *self = THREAD_SELF; - int newval; - - int oldval = THREAD_GETMEM (self, cancelhandling); - - while (1) - { - newval = oldval & ~CANCELTYPE_BITMASK; - - int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, - oldval); - if (__glibc_likely (curval == oldval)) - break; - - /* Prepare the next round. */ - oldval = curval; - } + THREAD_SETMEM (self, canceltype, PTHREAD_CANCEL_DEFERRED); /* We cannot return when we are being canceled. Upon return the thread might be things which would have to be undone. The following loop should loop until the cancellation signal is delivered. */ - while (__builtin_expect ((newval & (CANCELING_BITMASK | CANCELED_BITMASK)) - == CANCELING_BITMASK, 0)) + int ch = THREAD_GETMEM (self, cancelhandling); + while (__glibc_unlikely ((ch & CANCELING_BITMASK) + && !(ch & CANCELED_BITMASK))) { - futex_wait_simple ((unsigned int *) &self->cancelhandling, newval, + futex_wait_simple ((unsigned int *) &self->cancelhandling, ch, FUTEX_PRIVATE); - newval = THREAD_GETMEM (self, cancelhandling); + ch = THREAD_GETMEM (self, cancelhandling); } } diff --git a/nptl/cleanup_defer.c b/nptl/cleanup_defer.c index 33d4ea6eef..3300b4df46 100644 --- a/nptl/cleanup_defer.c +++ b/nptl/cleanup_defer.c @@ -31,27 +31,9 @@ __pthread_register_cancel_defer (__pthread_unwind_buf_t *buf) ibuf->priv.data.prev = THREAD_GETMEM (self, cleanup_jmp_buf); ibuf->priv.data.cleanup = THREAD_GETMEM (self, cleanup); - int cancelhandling = THREAD_GETMEM (self, cancelhandling); - /* Disable asynchronous cancellation for now. */ - if (__glibc_unlikely (cancelhandling & CANCELTYPE_BITMASK)) - while (1) - { - int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, - cancelhandling - & ~CANCELTYPE_BITMASK, - cancelhandling); - if (__glibc_likely (curval == cancelhandling)) - /* Successfully replaced the value. */ - break; - - /* Prepare for the next round. */ - cancelhandling = curval; - } - - ibuf->priv.data.canceltype = (cancelhandling & CANCELTYPE_BITMASK - ? PTHREAD_CANCEL_ASYNCHRONOUS - : PTHREAD_CANCEL_DEFERRED); + ibuf->priv.data.canceltype = THREAD_GETMEM (self, canceltype); + THREAD_SETMEM (self, canceltype, PTHREAD_CANCEL_DEFERRED); /* Store the new cleanup handler info. */ THREAD_SETMEM (self, cleanup_jmp_buf, (struct pthread_unwind_buf *) buf); @@ -67,25 +49,7 @@ __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *buf) THREAD_SETMEM (self, cleanup_jmp_buf, ibuf->priv.data.prev); - int cancelhandling; - if (ibuf->priv.data.canceltype != PTHREAD_CANCEL_DEFERRED - && ((cancelhandling = THREAD_GETMEM (self, cancelhandling)) - & CANCELTYPE_BITMASK) == 0) - { - while (1) - { - int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, - cancelhandling - | CANCELTYPE_BITMASK, - cancelhandling); - if (__glibc_likely (curval == cancelhandling)) - /* Successfully replaced the value. */ - break; - - /* Prepare for the next round. */ - cancelhandling = curval; - } - - __pthread_testcancel (); - } + THREAD_SETMEM (self, canceltype, ibuf->priv.data.canceltype); + if (ibuf->priv.data.canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) + __pthread_testcancel (); } diff --git a/nptl/cleanup_defer_compat.c b/nptl/cleanup_defer_compat.c index a1ad291fcc..77655c1b0a 100644 --- a/nptl/cleanup_defer_compat.c +++ b/nptl/cleanup_defer_compat.c @@ -29,27 +29,9 @@ _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, buffer->__arg = arg; buffer->__prev = THREAD_GETMEM (self, cleanup); - int cancelhandling = THREAD_GETMEM (self, cancelhandling); - /* Disable asynchronous cancellation for now. */ - if (__glibc_unlikely (cancelhandling & CANCELTYPE_BITMASK)) - while (1) - { - int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, - cancelhandling - & ~CANCELTYPE_BITMASK, - cancelhandling); - if (__glibc_likely (curval == cancelhandling)) - /* Successfully replaced the value. */ - break; - - /* Prepare for the next round. */ - cancelhandling = curval; - } - - buffer->__canceltype = (cancelhandling & CANCELTYPE_BITMASK - ? PTHREAD_CANCEL_ASYNCHRONOUS - : PTHREAD_CANCEL_DEFERRED); + buffer->__canceltype = THREAD_GETMEM (self, canceltype); + THREAD_SETMEM (self, canceltype, PTHREAD_CANCEL_DEFERRED); THREAD_SETMEM (self, cleanup, buffer); } @@ -64,27 +46,9 @@ _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, THREAD_SETMEM (self, cleanup, buffer->__prev); - int cancelhandling; - if (__builtin_expect (buffer->__canceltype != PTHREAD_CANCEL_DEFERRED, 0) - && ((cancelhandling = THREAD_GETMEM (self, cancelhandling)) - & CANCELTYPE_BITMASK) == 0) - { - while (1) - { - int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, - cancelhandling - | CANCELTYPE_BITMASK, - cancelhandling); - if (__glibc_likely (curval == cancelhandling)) - /* Successfully replaced the value. */ - break; - - /* Prepare for the next round. */ - cancelhandling = curval; - } - - __pthread_testcancel (); - } + THREAD_SETMEM (self, canceltype, buffer->__canceltype); + if (buffer->__canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) + __pthread_testcancel (); /* If necessary call the cleanup routine after we removed the current cleanup block from the list. */ diff --git a/nptl/descr.h b/nptl/descr.h index 279df680d6..e7dc865c91 100644 --- a/nptl/descr.h +++ b/nptl/descr.h @@ -269,9 +269,6 @@ struct pthread /* Flags determining processing of cancellation. */ int cancelhandling; - /* Bit set if asynchronous cancellation mode is selected. */ -#define CANCELTYPE_BIT 1 -#define CANCELTYPE_BITMASK (0x01 << CANCELTYPE_BIT) /* Bit set if canceling has been initiated. */ #define CANCELING_BIT 2 #define CANCELING_BITMASK (0x01 << CANCELING_BIT) @@ -287,13 +284,6 @@ struct pthread /* Bit set if thread is supposed to change XID. */ #define SETXID_BIT 6 #define SETXID_BITMASK (0x01 << SETXID_BIT) - /* Mask for the rest. Helps the compiler to optimize. */ -#define CANCEL_RESTMASK 0xffffff80 - -#define CANCEL_CANCELED_AND_ASYNCHRONOUS(value) \ - (((value) & (CANCELTYPE_BITMASK | CANCELED_BITMASK \ - | EXITING_BITMASK | CANCEL_RESTMASK | TERMINATED_BITMASK)) \ - == (CANCELTYPE_BITMASK | CANCELED_BITMASK)) /* Flags. Including those copied from the thread attribute. */ int flags; @@ -396,6 +386,10 @@ struct pthread PTHREAD_CANCEL_DISABLE). */ unsigned char cancelstate; + /* Thread cancel type (PTHREAD_CANCEL_DEFERRED or + PTHREAD_CANCEL_ASYNCHRONOUS). */ + unsigned char canceltype; + /* This member must be last. */ char end_padding[]; diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c index 96b1444a01..89f58d2e5e 100644 --- a/nptl/nptl-init.c +++ b/nptl/nptl-init.c @@ -157,7 +157,7 @@ sigcancel_handler (int sig, siginfo_t *si, void *ctx) THREAD_SETMEM (self, result, PTHREAD_CANCELED); /* Make sure asynchronous cancellation is still enabled. */ - if ((newval & CANCELTYPE_BITMASK) != 0) + if (self->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) /* Run the registered destructors and terminate the thread. */ __do_cancel (); diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c index 5b2789d620..266fd77284 100644 --- a/nptl/pthread_cancel.c +++ b/nptl/pthread_cancel.c @@ -56,7 +56,10 @@ __pthread_cancel (pthread_t th) signal. We avoid this if possible since it's more expensive. */ if (pd->cancelstate == PTHREAD_CANCEL_ENABLE - && CANCEL_CANCELED_AND_ASYNCHRONOUS (newval)) + && pd->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS + && (newval & CANCELED_BITMASK) + && !(newval & EXITING_BITMASK) + && !(newval & TERMINATED_BITMASK)) { /* Mark the cancellation as "in progress". */ if (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, diff --git a/nptl/pthread_setcanceltype.c b/nptl/pthread_setcanceltype.c index cc0507ae04..d8cb54736d 100644 --- a/nptl/pthread_setcanceltype.c +++ b/nptl/pthread_setcanceltype.c @@ -29,43 +29,11 @@ __pthread_setcanceltype (int type, int *oldtype) volatile struct pthread *self = THREAD_SELF; - int oldval = THREAD_GETMEM (self, cancelhandling); - while (1) - { - int newval = (type == PTHREAD_CANCEL_ASYNCHRONOUS - ? oldval | CANCELTYPE_BITMASK - : oldval & ~CANCELTYPE_BITMASK); - - /* Store the old value. */ - if (oldtype != NULL) - *oldtype = ((oldval & CANCELTYPE_BITMASK) - ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED); - - /* Avoid doing unnecessary work. The atomic operation can - potentially be expensive if the memory has to be locked and - remote cache lines have to be invalidated. */ - if (oldval == newval) - break; - - /* Update the cancel handling word. This has to be done - atomically since other bits could be modified as well. */ - int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, - oldval); - if (__glibc_likely (curval == oldval)) - { - if (self->cancelstate == PTHREAD_CANCEL_ENABLE - && CANCEL_CANCELED_AND_ASYNCHRONOUS (newval)) - { - THREAD_SETMEM (self, result, PTHREAD_CANCELED); - __do_cancel (); - } - - break; - } - - /* Prepare for the next round. */ - oldval = curval; - } + if (oldtype != NULL) + *oldtype = self->canceltype; + self->canceltype = type; + if (type == PTHREAD_CANCEL_ASYNCHRONOUS) + __pthread_testcancel (); return 0; } diff --git a/nptl/pthread_testcancel.c b/nptl/pthread_testcancel.c index cd937bb3a3..cf518bb8a8 100644 --- a/nptl/pthread_testcancel.c +++ b/nptl/pthread_testcancel.c @@ -34,5 +34,5 @@ __pthread_testcancel (void) __do_cancel (); } } -strong_alias (__pthread_testcancel, pthread_testcancel) +weak_alias (__pthread_testcancel, pthread_testcancel) hidden_def (__pthread_testcancel)