You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by we...@apache.org on 2025/08/29 02:46:25 UTC

(spark) branch master updated: [SPARK-53394][CORE] UninterruptibleLock.isInterruptible should avoid duplicated interrupt

This is an automated email from the ASF dual-hosted git repository.

wenchen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new 78871d7de88b [SPARK-53394][CORE] UninterruptibleLock.isInterruptible should avoid duplicated interrupt
78871d7de88b is described below

commit 78871d7de88b30729f543f1a0fef0b845d04a37e
Author: Yi Wu <yi...@databricks.com>
AuthorDate: Fri Aug 29 10:46:09 2025 +0800

    [SPARK-53394][CORE] UninterruptibleLock.isInterruptible should avoid duplicated interrupt
    
    ### What changes were proposed in this pull request?
    
    This PR fixes `UninterruptibleLock.isInterruptible` to avoid duplicated interruption when the thread is already interrupted.
    
    ### Why are the changes needed?
    
    The "uninterruptible" semantic of `UninterruptibleThread`is broken (i.e., `UninterruptibleThread` is interruptible even if it's under `runUninterruptibly`) after the fix https://github.com/apache/spark/pull/50594. The probelm is that the state of
    `shouldInterruptThread` becomes unsafe when there are multiple interrupts concurrently.
    
    For example, thread A could interrupt UninterruptibleThread ut first before UninterruptibleThread enters `runUninterruptibly`. Right after that, another thread B starts to invoke ut.interrupt() and pass through `uninterruptibleLock.isInterruptible` (becasue at this point, `shouldInterruptThread = uninterruptible = false`). Before thread B invokes `super.interrupt()`, UninterruptibleThread ut enters `runUninterruptibly` and pass through `uninterruptibleLock.getAndSetUninterruptible` an [...]
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    Manually tested. The issue can be easily reproduced if we run `UninterruptibleThreadSuite.stress test` for 100 times in a row:
    ```
    [info]   true did not equal false (UninterruptibleThreadSuite.scala:208)
    [info]   org.scalatest.exceptions.TestFailedException:
    [info]   at org.scalatest.Assertions.newAssertionFailedException(Assertions.scala:472)
    [info]   at org.scalatest.Assertions.newAssertionFailedException$(Assertions.scala:471)
    [info]   at org.scalatest.Assertions$.newAssertionFailedException(Assertions.scala:1231)
    [info]   at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:1295)
    [info]   at org.apache.spark.util.UninterruptibleThreadSuite.$anonfun$new$7(UninterruptibleThreadSuite.scala:208)
    ...
    ```
    And the issue is gone after the fix.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    No
    
    Closes #52139 from Ngone51/fix-uninterruptiable.
    
    Authored-by: Yi Wu <yi...@databricks.com>
    Signed-off-by: Wenchen Fan <we...@databricks.com>
---
 .../main/scala/org/apache/spark/util/UninterruptibleThread.scala   | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/core/src/main/scala/org/apache/spark/util/UninterruptibleThread.scala b/core/src/main/scala/org/apache/spark/util/UninterruptibleThread.scala
index 8fba5ed944c6..3d504856f566 100644
--- a/core/src/main/scala/org/apache/spark/util/UninterruptibleThread.scala
+++ b/core/src/main/scala/org/apache/spark/util/UninterruptibleThread.scala
@@ -107,8 +107,11 @@ private[spark] class UninterruptibleThread(
       // super.interrupt() is called. In this case to prevent runUninterruptibly() from being
       // interrupted, we use awaitInterruptThread flag. We need to set it only if
       // runUninterruptibly() is not yet set uninterruptible to true (!shouldInterruptThread) and
-      // there is no other threads that called interrupt (awaitInterruptThread is already true)
-      if (!shouldInterruptThread && !awaitInterruptThread) {
+      // there is no other threads that called interrupt (awaitInterruptThread is already true or
+      // isInterrupted is true. (SPARK-53394) Otherwise, the state of shouldInterruptThread would
+      // become inconsistent between isInterruptible() and isInterruptPending(), leading to
+      // UninterruptibleThread be interruptible under runUninterruptibly.)
+      if (!shouldInterruptThread && !awaitInterruptThread && !isInterrupted) {
         awaitInterruptThread = true
         true
       } else {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org