...
Run Format

Source file src/os/signal/signal_plan9_test.go

Documentation: os/signal

  // 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
  }
  

View as plain text