Skip to content

os/signal: deadlock combining signal handling with syscall.AllThreadsSyscall #43149

@AndrewGMorgan

Description

@AndrewGMorgan

What version of Go are you using (go version)?

HEAD (of 1.16 development branch)

Does this issue reproduce with the latest release?

No. It is a failure introduced with the new syscall.AllThreadsSyscall*() functions.

What operating system and processor architecture are you using (go env)?

All linux builds - with CGO_ENABLED=0

What did you do?

Following this bug: https://bugzilla.kernel.org/show_bug.cgi?id=210533 (which did not relate to the golang sources) I tried to test signal handling with the new (post 1.15) syscall.AllThreadsSyscall*() by adding the following test to the golang tree:

$ cat os/signal/signal_linux_test.go 
// +build linux

package signal

import (
        "os"
        "syscall"
        "testing"
        "time"
)

const prSetKeepCaps = 8

func TestAllThreadsSyscallSignals(t *testing.T) {
        if _, _, err := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, prSetKeepCaps, 0, 0); err == syscall.ENOTSUP {
                t.Skip("AllThreadsSyscall disabled with cgo")
        }

        sig := make(chan os.Signal, 1)
        Notify(sig, os.Interrupt)

        for i := 0; i <= 100; i++ {
                if _, _, errno := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, prSetKeepCaps, uintptr(i&1), 0); errno != 0 {
                        t.Fatalf("[%d] failed to set KEEP_CAPS=%d: %v", i, i&1, errno)
                }
        }

        select {
        case <-time.After(10 * time.Millisecond):
        case <-sig:
                t.Fatal("unexpected signal")
        }
        Stop(sig)
        close(sig)
}

Then in a build tree with this added test case I built and ran it as follows:

$ CGO_ENABLED=0 ../bin/go test -c os/signal
$ ./signal.test -test.v=1

What did you expect to see?

$ ./signal.test -test.v=1
=== RUN   TestAllThreadsSyscallSignals
--- PASS: TestAllThreadsSyscallSignals (0.02s)
=== RUN   TestSignal
    signal_test.go:116: sighup...
    signal_test.go:127: sigwinch...
    signal_test.go:134: sighup...
    signal_test.go:137: sighup...
--- PASS: TestSignal (0.00s)
=== RUN   TestStress
<...all good beyond here...>

What did you see instead?

$ ./signal.test -test.v=1
=== RUN   TestAllThreadsSyscallSignals
<...hangs here...>

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions