]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: make TestSpuriousWakeupsNeverHangSemasleep more robust
authorMichael Anthony Knyszek <mknyszek@google.com>
Tue, 11 Feb 2025 17:56:21 +0000 (17:56 +0000)
committerGopher Robot <gobot@golang.org>
Wed, 12 Feb 2025 16:23:26 +0000 (08:23 -0800)
This change modifies this test (which involves an arbitrary timeout) to
be a little less flaky by double-checking that our subprocess program
completed even if the ticker fires and we've exceeded our timeout. The
logic behind this change is that the testing goroutine might get delayed
for any number of reasons, but the subprocess could still complete in
time. Still, the goroutine will wake up to handle the ticker and see its
over time, even though the event it was waiting for did actually happen.

I can't reproduce #71548 locally, so I suspect because this test calls
t.Parallel other load can delay the testing goroutine enough for this to
happen (especially with GODEBUG=gccheckmark=1, which pauses
everything to perform a full mark and sweep, and runtime tests love to
call runtime.GC).

For #71548.

Change-Id: I83e86a0115f65950886b57b5af0b4a517ef5f90f
Reviewed-on: https://go-review.googlesource.com/c/go/+/648576
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Commit-Queue: Michael Knyszek <mknyszek@google.com>

src/runtime/semasleep_test.go

index 711d5df7352565d2a01c5bee45e33044e436363d..c891bc7e0c467187fc2f69d6ea903b8fa9527968 100644 (file)
@@ -91,10 +91,31 @@ func TestSpuriousWakeupsNeverHangSemasleep(t *testing.T) {
        // pthread_cond_timedwait_relative_np.
        ticker := time.NewTicker(200 * time.Millisecond)
        defer ticker.Stop()
+
+       checkDoneErr := func(err error) {
+               if err != nil {
+                       t.Fatalf("The program returned but unfortunately with an error: %v", err)
+               }
+               if time.Since(beforeStart) < 1*time.Second {
+                       // The program was supposed to sleep for a full (monotonic) second;
+                       // it should not return before that has elapsed.
+                       t.Fatalf("The program stopped too quickly.")
+               }
+       }
        for {
                select {
                case now := <-ticker.C:
                        if now.Sub(ready) > timeout {
+                               // If we got paused for a long time, for example if GODEBUG=gcstoptheworld=2,
+                               // it could be that the subprocess did actually finish and not deadlock, we
+                               // just got stuck as runnable or our wakeup was delayed. Double-check that
+                               // we don't have anything from doneCh before declaring failure.
+                               select {
+                               case err := <-doneCh:
+                                       checkDoneErr(err)
+                                       return
+                               default:
+                               }
                                t.Error("Program failed to return on time and has to be killed, issue #27520 still exists")
                                // Send SIGQUIT to get a goroutine dump.
                                // Stop sending SIGIO so that the program can clean up and actually terminate.
@@ -107,14 +128,7 @@ func TestSpuriousWakeupsNeverHangSemasleep(t *testing.T) {
                        cmd.Process.Signal(syscall.SIGIO)
 
                case err := <-doneCh:
-                       if err != nil {
-                               t.Fatalf("The program returned but unfortunately with an error: %v", err)
-                       }
-                       if time.Since(beforeStart) < 1*time.Second {
-                               // The program was supposed to sleep for a full (monotonic) second;
-                               // it should not return before that has elapsed.
-                               t.Fatalf("The program stopped too quickly.")
-                       }
+                       checkDoneErr(err)
                        return
                }
        }