mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			243 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
| // 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)
 | |
| }
 | |
| 
 | |
| // Ignored reports whether sig is currently ignored.
 | |
| func Ignored(sig os.Signal) bool {
 | |
| 	sn := signum(sig)
 | |
| 	return sn >= 0 && signalIgnored(sn)
 | |
| }
 | |
| 
 | |
| // 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:
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |