...
Run Format

Source file src/os/signal/signal.go

Documentation: os/signal

     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  	// Map a channel to the signals that should be sent to it.
    15  	m map[chan<- os.Signal]*handler
    16  	// Map a signal to the number of channels receiving it.
    17  	ref [numSig]int64
    18  	// Map channels to signals while the channel is being stopped.
    19  	// Not a map because entries live here only very briefly.
    20  	// We need a separate container because we need m to correspond to ref
    21  	// at all times, and we also need to keep track of the *handler
    22  	// value for a channel being stopped. See the Stop function.
    23  	stopping []stopping
    24  }
    25  
    26  type stopping struct {
    27  	c chan<- os.Signal
    28  	h *handler
    29  }
    30  
    31  type handler struct {
    32  	mask [(numSig + 31) / 32]uint32
    33  }
    34  
    35  func (h *handler) want(sig int) bool {
    36  	return (h.mask[sig/32]>>uint(sig&31))&1 != 0
    37  }
    38  
    39  func (h *handler) set(sig int) {
    40  	h.mask[sig/32] |= 1 << uint(sig&31)
    41  }
    42  
    43  func (h *handler) clear(sig int) {
    44  	h.mask[sig/32] &^= 1 << uint(sig&31)
    45  }
    46  
    47  // Stop relaying the signals, sigs, to any channels previously registered to
    48  // receive them and either reset the signal handlers to their original values
    49  // (action=disableSignal) or ignore the signals (action=ignoreSignal).
    50  func cancel(sigs []os.Signal, action func(int)) {
    51  	handlers.Lock()
    52  	defer handlers.Unlock()
    53  
    54  	remove := func(n int) {
    55  		var zerohandler handler
    56  
    57  		for c, h := range handlers.m {
    58  			if h.want(n) {
    59  				handlers.ref[n]--
    60  				h.clear(n)
    61  				if h.mask == zerohandler.mask {
    62  					delete(handlers.m, c)
    63  				}
    64  			}
    65  		}
    66  
    67  		action(n)
    68  	}
    69  
    70  	if len(sigs) == 0 {
    71  		for n := 0; n < numSig; n++ {
    72  			remove(n)
    73  		}
    74  	} else {
    75  		for _, s := range sigs {
    76  			remove(signum(s))
    77  		}
    78  	}
    79  }
    80  
    81  // Ignore causes the provided signals to be ignored. If they are received by
    82  // the program, nothing will happen. Ignore undoes the effect of any prior
    83  // calls to Notify for the provided signals.
    84  // If no signals are provided, all incoming signals will be ignored.
    85  func Ignore(sig ...os.Signal) {
    86  	cancel(sig, ignoreSignal)
    87  }
    88  
    89  // Notify causes package signal to relay incoming signals to c.
    90  // If no signals are provided, all incoming signals will be relayed to c.
    91  // Otherwise, just the provided signals will.
    92  //
    93  // Package signal will not block sending to c: the caller must ensure
    94  // that c has sufficient buffer space to keep up with the expected
    95  // signal rate. For a channel used for notification of just one signal value,
    96  // a buffer of size 1 is sufficient.
    97  //
    98  // It is allowed to call Notify multiple times with the same channel:
    99  // each call expands the set of signals sent to that channel.
   100  // The only way to remove signals from the set is to call Stop.
   101  //
   102  // It is allowed to call Notify multiple times with different channels
   103  // and the same signals: each channel receives copies of incoming
   104  // signals independently.
   105  func Notify(c chan<- os.Signal, sig ...os.Signal) {
   106  	if c == nil {
   107  		panic("os/signal: Notify using nil channel")
   108  	}
   109  
   110  	handlers.Lock()
   111  	defer handlers.Unlock()
   112  
   113  	h := handlers.m[c]
   114  	if h == nil {
   115  		if handlers.m == nil {
   116  			handlers.m = make(map[chan<- os.Signal]*handler)
   117  		}
   118  		h = new(handler)
   119  		handlers.m[c] = h
   120  	}
   121  
   122  	add := func(n int) {
   123  		if n < 0 {
   124  			return
   125  		}
   126  		if !h.want(n) {
   127  			h.set(n)
   128  			if handlers.ref[n] == 0 {
   129  				enableSignal(n)
   130  			}
   131  			handlers.ref[n]++
   132  		}
   133  	}
   134  
   135  	if len(sig) == 0 {
   136  		for n := 0; n < numSig; n++ {
   137  			add(n)
   138  		}
   139  	} else {
   140  		for _, s := range sig {
   141  			add(signum(s))
   142  		}
   143  	}
   144  }
   145  
   146  // Reset undoes the effect of any prior calls to Notify for the provided
   147  // signals.
   148  // If no signals are provided, all signal handlers will be reset.
   149  func Reset(sig ...os.Signal) {
   150  	cancel(sig, disableSignal)
   151  }
   152  
   153  // Stop causes package signal to stop relaying incoming signals to c.
   154  // It undoes the effect of all prior calls to Notify using c.
   155  // When Stop returns, it is guaranteed that c will receive no more signals.
   156  func Stop(c chan<- os.Signal) {
   157  	handlers.Lock()
   158  
   159  	h := handlers.m[c]
   160  	if h == nil {
   161  		handlers.Unlock()
   162  		return
   163  	}
   164  	delete(handlers.m, c)
   165  
   166  	for n := 0; n < numSig; n++ {
   167  		if h.want(n) {
   168  			handlers.ref[n]--
   169  			if handlers.ref[n] == 0 {
   170  				disableSignal(n)
   171  			}
   172  		}
   173  	}
   174  
   175  	// Signals will no longer be delivered to the channel.
   176  	// We want to avoid a race for a signal such as SIGINT:
   177  	// it should be either delivered to the channel,
   178  	// or the program should take the default action (that is, exit).
   179  	// To avoid the possibility that the signal is delivered,
   180  	// and the signal handler invoked, and then Stop deregisters
   181  	// the channel before the process function below has a chance
   182  	// to send it on the channel, put the channel on a list of
   183  	// channels being stopped and wait for signal delivery to
   184  	// quiesce before fully removing it.
   185  
   186  	handlers.stopping = append(handlers.stopping, stopping{c, h})
   187  
   188  	handlers.Unlock()
   189  
   190  	signalWaitUntilIdle()
   191  
   192  	handlers.Lock()
   193  
   194  	for i, s := range handlers.stopping {
   195  		if s.c == c {
   196  			handlers.stopping = append(handlers.stopping[:i], handlers.stopping[i+1:]...)
   197  			break
   198  		}
   199  	}
   200  
   201  	handlers.Unlock()
   202  }
   203  
   204  // Wait until there are no more signals waiting to be delivered.
   205  // Defined by the runtime package.
   206  func signalWaitUntilIdle()
   207  
   208  func process(sig os.Signal) {
   209  	n := signum(sig)
   210  	if n < 0 {
   211  		return
   212  	}
   213  
   214  	handlers.Lock()
   215  	defer handlers.Unlock()
   216  
   217  	for c, h := range handlers.m {
   218  		if h.want(n) {
   219  			// send but do not block for it
   220  			select {
   221  			case c <- sig:
   222  			default:
   223  			}
   224  		}
   225  	}
   226  
   227  	// Avoid the race mentioned in Stop.
   228  	for _, d := range handlers.stopping {
   229  		if d.h.want(n) {
   230  			select {
   231  			case d.c <- sig:
   232  			default:
   233  			}
   234  		}
   235  	}
   236  }
   237  

View as plain text