|  | // 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 ( | 
|  | "internal/itoa" | 
|  | "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 postNote(pid int, note string) error { | 
|  | f, err := os.OpenFile("/proc/"+itoa.Itoa(pid)+"/note", os.O_WRONLY, 0) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | defer f.Close() | 
|  | _, err = f.Write([]byte(note)) | 
|  | return err | 
|  | } |