...
Run Format

Source file src/os/signal/signal.go

Documentation: os/signal

  // Copyright 2012 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"
  	"sync"
  )
  
  var handlers struct {
  	sync.Mutex
  	// Map a channel to the signals that should be sent to it.
  	m map[chan<- os.Signal]*handler
  	// Map a signal to the number of channels receiving it.
  	ref [numSig]int64
  	// Map channels to signals while the channel is being stopped.
  	// Not a map because entries live here only very briefly.
  	// We need a separate container because we need m to correspond to ref
  	// at all times, and we also need to keep track of the *handler
  	// value for a channel being stopped. See the Stop function.
  	stopping []stopping
  }
  
  type stopping struct {
  	c chan<- os.Signal
  	h *handler
  }
  
  type handler struct {
  	mask [(numSig + 31) / 32]uint32
  }
  
  func (h *handler) want(sig int) bool {
  	return (h.mask[sig/32]>>uint(sig&31))&1 != 0
  }
  
  func (h *handler) set(sig int) {
  	h.mask[sig/32] |= 1 << uint(sig&31)
  }
  
  func (h *handler) clear(sig int) {
  	h.mask[sig/32] &^= 1 << uint(sig&31)
  }
  
  // Stop relaying the signals, sigs, to any channels previously registered to
  // receive them and either reset the signal handlers to their original values
  // (action=disableSignal) or ignore the signals (action=ignoreSignal).
  func cancel(sigs []os.Signal, action func(int)) {
  	handlers.Lock()
  	defer handlers.Unlock()
  
  	remove := func(n int) {
  		var zerohandler handler
  
  		for c, h := range handlers.m {
  			if h.want(n) {
  				handlers.ref[n]--
  				h.clear(n)
  				if h.mask == zerohandler.mask {
  					delete(handlers.m, c)
  				}
  			}
  		}
  
  		action(n)
  	}
  
  	if len(sigs) == 0 {
  		for n := 0; n < numSig; n++ {
  			remove(n)
  		}
  	} else {
  		for _, s := range sigs {
  			remove(signum(s))
  		}
  	}
  }
  
  // Ignore causes the provided signals to be ignored. If they are received by
  // the program, nothing will happen. Ignore undoes the effect of any prior
  // calls to Notify for the provided signals.
  // If no signals are provided, all incoming signals will be ignored.
  func Ignore(sig ...os.Signal) {
  	cancel(sig, ignoreSignal)
  }
  
  // Notify causes package signal to relay incoming signals to c.
  // If no signals are provided, all incoming signals will be relayed to c.
  // Otherwise, just the provided signals will.
  //
  // Package signal will not block sending to c: the caller must ensure
  // that c has sufficient buffer space to keep up with the expected
  // signal rate. For a channel used for notification of just one signal value,
  // a buffer of size 1 is sufficient.
  //
  // It is allowed to call Notify multiple times with the same channel:
  // each call expands the set of signals sent to that channel.
  // The only way to remove signals from the set is to call Stop.
  //
  // It is allowed to call Notify multiple times with different channels
  // and the same signals: each channel receives copies of incoming
  // signals independently.
  func Notify(c chan<- os.Signal, sig ...os.Signal) {
  	if c == nil {
  		panic("os/signal: Notify using nil channel")
  	}
  
  	handlers.Lock()
  	defer handlers.Unlock()
  
  	h := handlers.m[c]
  	if h == nil {
  		if handlers.m == nil {
  			handlers.m = make(map[chan<- os.Signal]*handler)
  		}
  		h = new(handler)
  		handlers.m[c] = h
  	}
  
  	add := func(n int) {
  		if n < 0 {
  			return
  		}
  		if !h.want(n) {
  			h.set(n)
  			if handlers.ref[n] == 0 {
  				enableSignal(n)
  			}
  			handlers.ref[n]++
  		}
  	}
  
  	if len(sig) == 0 {
  		for n := 0; n < numSig; n++ {
  			add(n)
  		}
  	} else {
  		for _, s := range sig {
  			add(signum(s))
  		}
  	}
  }
  
  // Reset undoes the effect of any prior calls to Notify for the provided
  // signals.
  // If no signals are provided, all signal handlers will be reset.
  func Reset(sig ...os.Signal) {
  	cancel(sig, disableSignal)
  }
  
  // Stop causes package signal to stop relaying incoming signals to c.
  // It undoes the effect of all prior calls to Notify using c.
  // When Stop returns, it is guaranteed that c will receive no more signals.
  func Stop(c chan<- os.Signal) {
  	handlers.Lock()
  
  	h := handlers.m[c]
  	if h == nil {
  		handlers.Unlock()
  		return
  	}
  	delete(handlers.m, c)
  
  	for n := 0; n < numSig; n++ {
  		if h.want(n) {
  			handlers.ref[n]--
  			if handlers.ref[n] == 0 {
  				disableSignal(n)
  			}
  		}
  	}
  
  	// Signals will no longer be delivered to the channel.
  	// We want to avoid a race for a signal such as SIGINT:
  	// it should be either delivered to the channel,
  	// or the program should take the default action (that is, exit).
  	// To avoid the possibility that the signal is delivered,
  	// and the signal handler invoked, and then Stop deregisters
  	// the channel before the process function below has a chance
  	// to send it on the channel, put the channel on a list of
  	// channels being stopped and wait for signal delivery to
  	// quiesce before fully removing it.
  
  	handlers.stopping = append(handlers.stopping, stopping{c, h})
  
  	handlers.Unlock()
  
  	signalWaitUntilIdle()
  
  	handlers.Lock()
  
  	for i, s := range handlers.stopping {
  		if s.c == c {
  			handlers.stopping = append(handlers.stopping[:i], handlers.stopping[i+1:]...)
  			break
  		}
  	}
  
  	handlers.Unlock()
  }
  
  // Wait until there are no more signals waiting to be delivered.
  // Defined by the runtime package.
  func signalWaitUntilIdle()
  
  func process(sig os.Signal) {
  	n := signum(sig)
  	if n < 0 {
  		return
  	}
  
  	handlers.Lock()
  	defer handlers.Unlock()
  
  	for c, h := range handlers.m {
  		if h.want(n) {
  			// send but do not block for it
  			select {
  			case c <- sig:
  			default:
  			}
  		}
  	}
  
  	// Avoid the race mentioned in Stop.
  	for _, d := range handlers.stopping {
  		if d.h.want(n) {
  			select {
  			case d.c <- sig:
  			default:
  			}
  		}
  	}
  }
  

View as plain text