github.com/activestate/go@v0.0.0-20170614201249-0b81c023a722/src/os/signal/signal.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package signal
     6  
     7  import (
     8  	"os"
     9  	"sync"
    10  )
    11  
    12  var handlers struct {
    13  	sync.Mutex
    14  	m   map[chan<- os.Signal]*handler
    15  	ref [numSig]int64
    16  }
    17  
    18  type handler struct {
    19  	mask [(numSig + 31) / 32]uint32
    20  }
    21  
    22  func (h *handler) want(sig int) bool {
    23  	return (h.mask[sig/32]>>uint(sig&31))&1 != 0
    24  }
    25  
    26  func (h *handler) set(sig int) {
    27  	h.mask[sig/32] |= 1 << uint(sig&31)
    28  }
    29  
    30  func (h *handler) clear(sig int) {
    31  	h.mask[sig/32] &^= 1 << uint(sig&31)
    32  }
    33  
    34  // Stop relaying the signals, sigs, to any channels previously registered to
    35  // receive them and either reset the signal handlers to their original values
    36  // (action=disableSignal) or ignore the signals (action=ignoreSignal).
    37  func cancel(sigs []os.Signal, action func(int)) {
    38  	handlers.Lock()
    39  	defer handlers.Unlock()
    40  
    41  	remove := func(n int) {
    42  		var zerohandler handler
    43  
    44  		for c, h := range handlers.m {
    45  			if h.want(n) {
    46  				handlers.ref[n]--
    47  				h.clear(n)
    48  				if h.mask == zerohandler.mask {
    49  					delete(handlers.m, c)
    50  				}
    51  			}
    52  		}
    53  
    54  		action(n)
    55  	}
    56  
    57  	if len(sigs) == 0 {
    58  		for n := 0; n < numSig; n++ {
    59  			remove(n)
    60  		}
    61  	} else {
    62  		for _, s := range sigs {
    63  			remove(signum(s))
    64  		}
    65  	}
    66  }
    67  
    68  // Ignore causes the provided signals to be ignored. If they are received by
    69  // the program, nothing will happen. Ignore undoes the effect of any prior
    70  // calls to Notify for the provided signals.
    71  // If no signals are provided, all incoming signals will be ignored.
    72  func Ignore(sig ...os.Signal) {
    73  	cancel(sig, ignoreSignal)
    74  }
    75  
    76  // Notify causes package signal to relay incoming signals to c.
    77  // If no signals are provided, all incoming signals will be relayed to c.
    78  // Otherwise, just the provided signals will.
    79  //
    80  // Package signal will not block sending to c: the caller must ensure
    81  // that c has sufficient buffer space to keep up with the expected
    82  // signal rate. For a channel used for notification of just one signal value,
    83  // a buffer of size 1 is sufficient.
    84  //
    85  // It is allowed to call Notify multiple times with the same channel:
    86  // each call expands the set of signals sent to that channel.
    87  // The only way to remove signals from the set is to call Stop.
    88  //
    89  // It is allowed to call Notify multiple times with different channels
    90  // and the same signals: each channel receives copies of incoming
    91  // signals independently.
    92  func Notify(c chan<- os.Signal, sig ...os.Signal) {
    93  	if c == nil {
    94  		panic("os/signal: Notify using nil channel")
    95  	}
    96  
    97  	handlers.Lock()
    98  	defer handlers.Unlock()
    99  
   100  	h := handlers.m[c]
   101  	if h == nil {
   102  		if handlers.m == nil {
   103  			handlers.m = make(map[chan<- os.Signal]*handler)
   104  		}
   105  		h = new(handler)
   106  		handlers.m[c] = h
   107  	}
   108  
   109  	add := func(n int) {
   110  		if n < 0 {
   111  			return
   112  		}
   113  		if !h.want(n) {
   114  			h.set(n)
   115  			if handlers.ref[n] == 0 {
   116  				enableSignal(n)
   117  			}
   118  			handlers.ref[n]++
   119  		}
   120  	}
   121  
   122  	if len(sig) == 0 {
   123  		for n := 0; n < numSig; n++ {
   124  			add(n)
   125  		}
   126  	} else {
   127  		for _, s := range sig {
   128  			add(signum(s))
   129  		}
   130  	}
   131  }
   132  
   133  // Reset undoes the effect of any prior calls to Notify for the provided
   134  // signals.
   135  // If no signals are provided, all signal handlers will be reset.
   136  func Reset(sig ...os.Signal) {
   137  	cancel(sig, disableSignal)
   138  }
   139  
   140  // Stop causes package signal to stop relaying incoming signals to c.
   141  // It undoes the effect of all prior calls to Notify using c.
   142  // When Stop returns, it is guaranteed that c will receive no more signals.
   143  func Stop(c chan<- os.Signal) {
   144  	handlers.Lock()
   145  	defer handlers.Unlock()
   146  
   147  	h := handlers.m[c]
   148  	if h == nil {
   149  		return
   150  	}
   151  	delete(handlers.m, c)
   152  
   153  	for n := 0; n < numSig; n++ {
   154  		if h.want(n) {
   155  			handlers.ref[n]--
   156  			if handlers.ref[n] == 0 {
   157  				disableSignal(n)
   158  			}
   159  		}
   160  	}
   161  }
   162  
   163  func process(sig os.Signal) {
   164  	n := signum(sig)
   165  	if n < 0 {
   166  		return
   167  	}
   168  
   169  	handlers.Lock()
   170  	defer handlers.Unlock()
   171  
   172  	for c, h := range handlers.m {
   173  		if h.want(n) {
   174  			// send but do not block for it
   175  			select {
   176  			case c <- sig:
   177  			default:
   178  			}
   179  		}
   180  	}
   181  }