182 lines
3.8 KiB
Go
182 lines
3.8 KiB
Go
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package signal
|
||
|
|
||
|
import (
|
||
|
"os"
|
||
|
"runtime"
|
||
|
"syscall"
|
||
|
"testing"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
|
||
|
select {
|
||
|
case s := <-c:
|
||
|
if s != sig {
|
||
|
t.Fatalf("signal was %v, want %v", s, sig)
|
||
|
}
|
||
|
case <-time.After(1 * time.Second):
|
||
|
t.Fatalf("timeout waiting for %v", sig)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Test that basic signal handling works.
|
||
|
func TestSignal(t *testing.T) {
|
||
|
// Ask for hangup
|
||
|
c := make(chan os.Signal, 1)
|
||
|
Notify(c, syscall.Note("hangup"))
|
||
|
defer Stop(c)
|
||
|
|
||
|
// Send this process a hangup
|
||
|
t.Logf("hangup...")
|
||
|
postNote(syscall.Getpid(), "hangup")
|
||
|
waitSig(t, c, syscall.Note("hangup"))
|
||
|
|
||
|
// Ask for everything we can get.
|
||
|
c1 := make(chan os.Signal, 1)
|
||
|
Notify(c1)
|
||
|
|
||
|
// Send this process an alarm
|
||
|
t.Logf("alarm...")
|
||
|
postNote(syscall.Getpid(), "alarm")
|
||
|
waitSig(t, c1, syscall.Note("alarm"))
|
||
|
|
||
|
// Send two more hangups, to make sure that
|
||
|
// they get delivered on c1 and that not reading
|
||
|
// from c does not block everything.
|
||
|
t.Logf("hangup...")
|
||
|
postNote(syscall.Getpid(), "hangup")
|
||
|
waitSig(t, c1, syscall.Note("hangup"))
|
||
|
t.Logf("hangup...")
|
||
|
postNote(syscall.Getpid(), "hangup")
|
||
|
waitSig(t, c1, syscall.Note("hangup"))
|
||
|
|
||
|
// The first SIGHUP should be waiting for us on c.
|
||
|
waitSig(t, c, syscall.Note("hangup"))
|
||
|
}
|
||
|
|
||
|
func TestStress(t *testing.T) {
|
||
|
dur := 3 * time.Second
|
||
|
if testing.Short() {
|
||
|
dur = 100 * time.Millisecond
|
||
|
}
|
||
|
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
|
||
|
done := make(chan bool)
|
||
|
finished := make(chan bool)
|
||
|
go func() {
|
||
|
sig := make(chan os.Signal, 1)
|
||
|
Notify(sig, syscall.Note("alarm"))
|
||
|
defer Stop(sig)
|
||
|
Loop:
|
||
|
for {
|
||
|
select {
|
||
|
case <-sig:
|
||
|
case <-done:
|
||
|
break Loop
|
||
|
}
|
||
|
}
|
||
|
finished <- true
|
||
|
}()
|
||
|
go func() {
|
||
|
Loop:
|
||
|
for {
|
||
|
select {
|
||
|
case <-done:
|
||
|
break Loop
|
||
|
default:
|
||
|
postNote(syscall.Getpid(), "alarm")
|
||
|
runtime.Gosched()
|
||
|
}
|
||
|
}
|
||
|
finished <- true
|
||
|
}()
|
||
|
time.Sleep(dur)
|
||
|
close(done)
|
||
|
<-finished
|
||
|
<-finished
|
||
|
// When run with 'go test -cpu=1,2,4' alarm from this test can slip
|
||
|
// into subsequent TestSignal() causing failure.
|
||
|
// Sleep for a while to reduce the possibility of the failure.
|
||
|
time.Sleep(10 * time.Millisecond)
|
||
|
}
|
||
|
|
||
|
// Test that Stop cancels the channel's registrations.
|
||
|
func TestStop(t *testing.T) {
|
||
|
if testing.Short() {
|
||
|
t.Skip("skipping in short mode")
|
||
|
}
|
||
|
sigs := []string{
|
||
|
"alarm",
|
||
|
"hangup",
|
||
|
}
|
||
|
|
||
|
for _, sig := range sigs {
|
||
|
// Send the signal.
|
||
|
// If it's alarm, we should not see it.
|
||
|
// If it's hangup, maybe we'll die. Let the flag tell us what to do.
|
||
|
if sig != "hangup" {
|
||
|
postNote(syscall.Getpid(), sig)
|
||
|
}
|
||
|
time.Sleep(100 * time.Millisecond)
|
||
|
|
||
|
// Ask for signal
|
||
|
c := make(chan os.Signal, 1)
|
||
|
Notify(c, syscall.Note(sig))
|
||
|
defer Stop(c)
|
||
|
|
||
|
// Send this process that signal
|
||
|
postNote(syscall.Getpid(), sig)
|
||
|
waitSig(t, c, syscall.Note(sig))
|
||
|
|
||
|
Stop(c)
|
||
|
select {
|
||
|
case s := <-c:
|
||
|
t.Fatalf("unexpected signal %v", s)
|
||
|
case <-time.After(100 * time.Millisecond):
|
||
|
// nothing to read - good
|
||
|
}
|
||
|
|
||
|
// Send the signal.
|
||
|
// If it's alarm, we should not see it.
|
||
|
// If it's hangup, maybe we'll die. Let the flag tell us what to do.
|
||
|
if sig != "hangup" {
|
||
|
postNote(syscall.Getpid(), sig)
|
||
|
}
|
||
|
|
||
|
select {
|
||
|
case s := <-c:
|
||
|
t.Fatalf("unexpected signal %v", s)
|
||
|
case <-time.After(100 * time.Millisecond):
|
||
|
// nothing to read - good
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func itoa(val int) string {
|
||
|
if val < 0 {
|
||
|
return "-" + itoa(-val)
|
||
|
}
|
||
|
var buf [32]byte // big enough for int64
|
||
|
i := len(buf) - 1
|
||
|
for val >= 10 {
|
||
|
buf[i] = byte(val%10 + '0')
|
||
|
i--
|
||
|
val /= 10
|
||
|
}
|
||
|
buf[i] = byte(val + '0')
|
||
|
return string(buf[i:])
|
||
|
}
|
||
|
|
||
|
func postNote(pid int, note string) error {
|
||
|
f, err := os.OpenFile("/proc/"+itoa(pid)+"/note", os.O_WRONLY, 0)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer f.Close()
|
||
|
_, err = f.Write([]byte(note))
|
||
|
return err
|
||
|
}
|