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

BewareMyPower pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git


The following commit(s) were added to refs/heads/master by this push:
     new 1796b8a7 fix: remove default case in waitWithContext to prevent 
busy-spin deadlock (#1503)
1796b8a7 is described below

commit 1796b8a718bfd984ca5ceceb8a7b46226e866d8a
Author: Zixuan Liu <[email protected]>
AuthorDate: Mon Jun 1 14:19:22 2026 +0800

    fix: remove default case in waitWithContext to prevent busy-spin deadlock 
(#1503)
---
 pulsar/internal/channel_cond.go      |  3 +--
 pulsar/internal/channel_cond_test.go | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/pulsar/internal/channel_cond.go b/pulsar/internal/channel_cond.go
index 38301abe..94b303a1 100644
--- a/pulsar/internal/channel_cond.go
+++ b/pulsar/internal/channel_cond.go
@@ -47,6 +47,7 @@ func (c *chCond) wait() {
 }
 
 // waitWithContext Same as wait() call, but the end condition can also be 
controlled through the context.
+// It blocks until either a broadcast occurs or the context is done.
 func (c *chCond) waitWithContext(ctx context.Context) bool {
        n := c.notifyChan()
        c.L.Unlock()
@@ -56,8 +57,6 @@ func (c *chCond) waitWithContext(ctx context.Context) bool {
                return true
        case <-ctx.Done():
                return false
-       default:
-               return true
        }
 }
 
diff --git a/pulsar/internal/channel_cond_test.go 
b/pulsar/internal/channel_cond_test.go
index 93a04084..0a58f4fa 100644
--- a/pulsar/internal/channel_cond_test.go
+++ b/pulsar/internal/channel_cond_test.go
@@ -53,3 +53,38 @@ func TestChCondWithContext(_ *testing.T) {
        cancel()
        wg.Wait()
 }
+
+func TestChCondWithContextBlocks(t *testing.T) {
+       // Verify that waitWithContext actually blocks (does not return via a 
default case)
+       // until either a broadcast or context cancellation occurs.
+       cond := newCond(&sync.Mutex{})
+       started := make(chan struct{})
+       done := make(chan struct{})
+
+       go func() {
+               cond.L.Lock()
+               close(started)
+               cond.waitWithContext(context.Background())
+               cond.L.Unlock()
+               close(done)
+       }()
+
+       <-started
+       // Give the goroutine time to enter the select. If there were a default 
case,
+       // it would return immediately and close done before the broadcast 
below.
+       time.Sleep(20 * time.Millisecond)
+
+       select {
+       case <-done:
+               t.Fatal("waitWithContext returned before broadcast — default 
case must have fired")
+       default:
+       }
+
+       cond.broadcast()
+
+       select {
+       case <-done:
+       case <-time.After(time.Second):
+               t.Fatal("waitWithContext did not unblock after broadcast")
+       }
+}

Reply via email to