mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			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
 | |
| }
 |