github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/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  // BUG(rsc): This package is not yet implemented on Plan 9.
     9  
    10  import (
    11  	"os"
    12  	"sync"
    13  )
    14  
    15  var handlers struct {
    16  	sync.Mutex
    17  	m   map[chan<- os.Signal]*handler
    18  	ref [numSig]int64
    19  }
    20  
    21  type handler struct {
    22  	mask [(numSig + 31) / 32]uint32
    23  }
    24  
    25  func (h *handler) want(sig int) bool {
    26  	return (h.mask[sig/32]>>uint(sig&31))&1 != 0
    27  }
    28  
    29  func (h *handler) set(sig int) {
    30  	h.mask[sig/32] |= 1 << uint(sig&31)
    31  }
    32  
    33  // Notify causes package signal to relay incoming signals to c.
    34  // If no signals are listed, all incoming signals will be relayed to c.
    35  // Otherwise, just the listed signals will.
    36  //
    37  // Package signal will not block sending to c: the caller must ensure
    38  // that c has sufficient buffer space to keep up with the expected
    39  // signal rate.  For a channel used for notification of just one signal value,
    40  // a buffer of size 1 is sufficient.
    41  //
    42  // It is allowed to call Notify multiple times with the same channel:
    43  // each call expands the set of signals sent to that channel.
    44  // The only way to remove signals from the set is to call Stop.
    45  //
    46  // It is allowed to call Notify multiple times with different channels
    47  // and the same signals: each channel receives copies of incoming
    48  // signals independently.
    49  func Notify(c chan<- os.Signal, sig ...os.Signal) {
    50  	if c == nil {
    51  		panic("os/signal: Notify using nil channel")
    52  	}
    53  
    54  	handlers.Lock()
    55  	defer handlers.Unlock()
    56  
    57  	h := handlers.m[c]
    58  	if h == nil {
    59  		if handlers.m == nil {
    60  			handlers.m = make(map[chan<- os.Signal]*handler)
    61  		}
    62  		h = new(handler)
    63  		handlers.m[c] = h
    64  	}
    65  
    66  	add := func(n int) {
    67  		if n < 0 {
    68  			return
    69  		}
    70  		if !h.want(n) {
    71  			h.set(n)
    72  			if handlers.ref[n] == 0 {
    73  				enableSignal(n)
    74  			}
    75  			handlers.ref[n]++
    76  		}
    77  	}
    78  
    79  	if len(sig) == 0 {
    80  		for n := 0; n < numSig; n++ {
    81  			add(n)
    82  		}
    83  	} else {
    84  		for _, s := range sig {
    85  			add(signum(s))
    86  		}
    87  	}
    88  }
    89  
    90  // Stop causes package signal to stop relaying incoming signals to c.
    91  // It undoes the effect of all prior calls to Notify using c.
    92  // When Stop returns, it is guaranteed that c will receive no more signals.
    93  func Stop(c chan<- os.Signal) {
    94  	handlers.Lock()
    95  	defer handlers.Unlock()
    96  
    97  	h := handlers.m[c]
    98  	if h == nil {
    99  		return
   100  	}
   101  	delete(handlers.m, c)
   102  
   103  	for n := 0; n < numSig; n++ {
   104  		if h.want(n) {
   105  			handlers.ref[n]--
   106  			if handlers.ref[n] == 0 {
   107  				disableSignal(n)
   108  			}
   109  		}
   110  	}
   111  }
   112  
   113  func process(sig os.Signal) {
   114  	n := signum(sig)
   115  	if n < 0 {
   116  		return
   117  	}
   118  
   119  	handlers.Lock()
   120  	defer handlers.Unlock()
   121  
   122  	for c, h := range handlers.m {
   123  		if h.want(n) {
   124  			// send but do not block for it
   125  			select {
   126  			case c <- sig:
   127  			default:
   128  			}
   129  		}
   130  	}
   131  }