...
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  // Ignored reports whether sig is currently ignored.
    90  func Ignored(sig os.Signal) bool {
    91  	sn := signum(sig)
    92  	return sn >= 0 && signalIgnored(sn)
    93  }
    94  
    95  // Notify causes package signal to relay incoming signals to c.
    96  // If no signals are provided, all incoming signals will be relayed to c.
    97  // Otherwise, just the provided signals will.
    98  //
    99  // Package signal will not block sending to c: the caller must ensure
   100  // that c has sufficient buffer space to keep up with the expected
   101  // signal rate. For a channel used for notification of just one signal value,
   102  // a buffer of size 1 is sufficient.
   103  //
   104  // It is allowed to call Notify multiple times with the same channel:
   105  // each call expands the set of signals sent to that channel.
   106  // The only way to remove signals from the set is to call Stop.
   107  //
   108  // It is allowed to call Notify multiple times with different channels
   109  // and the same signals: each channel receives copies of incoming
   110  // signals independently.
   111  func Notify(c chan<- os.Signal, sig ...os.Signal) {
   112  	if c == nil {
   113  		panic("os/signal: Notify using nil channel")
   114  	}
   115  
   116  	handlers.Lock()
   117  	defer handlers.Unlock()
   118  
   119  	h := handlers.m[c]
   120  	if h == nil {
   121  		if handlers.m == nil {
   122  			handlers.m = make(map[chan<- os.Signal]*handler)
   123  		}
   124  		h = new(handler)
   125  		handlers.m[c] = h
   126  	}
   127  
   128  	add := func(n int) {
   129  		if n < 0 {
   130  			return
   131  		}
   132  		if !h.want(n) {
   133  			h.set(n)
   134  			if handlers.ref[n] == 0 {
   135  				enableSignal(n)
   136  			}
   137  			handlers.ref[n]++
   138  		}
   139  	}
   140  
   141  	if len(sig) == 0 {
   142  		for n := 0; n < numSig; n++ {
   143  			add(n)
   144  		}
   145  	} else {
   146  		for _, s := range sig {
   147  			add(signum(s))
   148  		}
   149  	}
   150  }
   151  
   152  // Reset undoes the effect of any prior calls to Notify for the provided
   153  // signals.
   154  // If no signals are provided, all signal handlers will be reset.
   155  func Reset(sig ...os.Signal) {
   156  	cancel(sig, disableSignal)
   157  }
   158  
   159  // Stop causes package signal to stop relaying incoming signals to c.
   160  // It undoes the effect of all prior calls to Notify using c.
   161  // When Stop returns, it is guaranteed that c will receive no more signals.
   162  func Stop(c chan<- os.Signal) {
   163  	handlers.Lock()
   164  
   165  	h := handlers.m[c]
   166  	if h == nil {
   167  		handlers.Unlock()
   168  		return
   169  	}
   170  	delete(handlers.m, c)
   171  
   172  	for n := 0; n < numSig; n++ {
   173  		if h.want(n) {
   174  			handlers.ref[n]--
   175  			if handlers.ref[n] == 0 {
   176  				disableSignal(n)
   177  			}
   178  		}
   179  	}
   180  
   181  	// Signals will no longer be delivered to the channel.
   182  	// We want to avoid a race for a signal such as SIGINT:
   183  	// it should be either delivered to the channel,
   184  	// or the program should take the default action (that is, exit).
   185  	// To avoid the possibility that the signal is delivered,
   186  	// and the signal handler invoked, and then Stop deregisters
   187  	// the channel before the process function below has a chance
   188  	// to send it on the channel, put the channel on a list of
   189  	// channels being stopped and wait for signal delivery to
   190  	// quiesce before fully removing it.
   191  
   192  	handlers.stopping = append(handlers.stopping, stopping{c, h})
   193  
   194  	handlers.Unlock()
   195  
   196  	signalWaitUntilIdle()
   197  
   198  	handlers.Lock()
   199  
   200  	for i, s := range handlers.stopping {
   201  		if s.c == c {
   202  			handlers.stopping = append(handlers.stopping[:i], handlers.stopping[i+1:]...)
   203  			break
   204  		}
   205  	}
   206  
   207  	handlers.Unlock()
   208  }
   209  
   210  // Wait until there are no more signals waiting to be delivered.
   211  // Defined by the runtime package.
   212  func signalWaitUntilIdle()
   213  
   214  func process(sig os.Signal) {
   215  	n := signum(sig)
   216  	if n < 0 {
   217  		return
   218  	}
   219  
   220  	handlers.Lock()
   221  	defer handlers.Unlock()
   222  
   223  	for c, h := range handlers.m {
   224  		if h.want(n) {
   225  			// send but do not block for it
   226  			select {
   227  			case c <- sig:
   228  			default:
   229  			}
   230  		}
   231  	}
   232  
   233  	// Avoid the race mentioned in Stop.
   234  	for _, d := range handlers.stopping {
   235  		if d.h.want(n) {
   236  			select {
   237  			case d.c <- sig:
   238  			default:
   239  			}
   240  		}
   241  	}
   242  }
   243  

View as plain text