...

Source file src/os/signal/signal.go

     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