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