github.com/flyinox/gosm@v0.0.0-20171117061539-16768cb62077/src/runtime/sigqueue.go (about)

     1  // Copyright 2009 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  // This file implements runtime support for signal handling.
     6  //
     7  // Most synchronization primitives are not available from
     8  // the signal handler (it cannot block, allocate memory, or use locks)
     9  // so the handler communicates with a processing goroutine
    10  // via struct sig, below.
    11  //
    12  // sigsend is called by the signal handler to queue a new signal.
    13  // signal_recv is called by the Go program to receive a newly queued signal.
    14  // Synchronization between sigsend and signal_recv is based on the sig.state
    15  // variable. It can be in 3 states: sigIdle, sigReceiving and sigSending.
    16  // sigReceiving means that signal_recv is blocked on sig.Note and there are no
    17  // new pending signals.
    18  // sigSending means that sig.mask *may* contain new pending signals,
    19  // signal_recv can't be blocked in this state.
    20  // sigIdle means that there are no new pending signals and signal_recv is not blocked.
    21  // Transitions between states are done atomically with CAS.
    22  // When signal_recv is unblocked, it resets sig.Note and rechecks sig.mask.
    23  // If several sigsends and signal_recv execute concurrently, it can lead to
    24  // unnecessary rechecks of sig.mask, but it cannot lead to missed signals
    25  // nor deadlocks.
    26  
    27  // +build !plan9
    28  
    29  package runtime
    30  
    31  import (
    32  	"runtime/internal/atomic"
    33  	_ "unsafe" // for go:linkname
    34  )
    35  
    36  // sig handles communication between the signal handler and os/signal.
    37  // Other than the inuse and recv fields, the fields are accessed atomically.
    38  //
    39  // The wanted and ignored fields are only written by one goroutine at
    40  // a time; access is controlled by the handlers Mutex in os/signal.
    41  // The fields are only read by that one goroutine and by the signal handler.
    42  // We access them atomically to minimize the race between setting them
    43  // in the goroutine calling os/signal and the signal handler,
    44  // which may be running in a different thread. That race is unavoidable,
    45  // as there is no connection between handling a signal and receiving one,
    46  // but atomic instructions should minimize it.
    47  var sig struct {
    48  	note    note
    49  	mask    [(_NSIG + 31) / 32]uint32
    50  	wanted  [(_NSIG + 31) / 32]uint32
    51  	ignored [(_NSIG + 31) / 32]uint32
    52  	recv    [(_NSIG + 31) / 32]uint32
    53  	state   uint32
    54  	inuse   bool
    55  }
    56  
    57  const (
    58  	sigIdle = iota
    59  	sigReceiving
    60  	sigSending
    61  )
    62  
    63  // Called from sighandler to send a signal back out of the signal handling thread.
    64  // Reports whether the signal was sent. If not, the caller typically crashes the program.
    65  func sigsend(s uint32) bool {
    66  	bit := uint32(1) << uint(s&31)
    67  	if !sig.inuse || s >= uint32(32*len(sig.wanted)) {
    68  		return false
    69  	}
    70  
    71  	if w := atomic.Load(&sig.wanted[s/32]); w&bit == 0 {
    72  		return false
    73  	}
    74  
    75  	// Add signal to outgoing queue.
    76  	for {
    77  		mask := sig.mask[s/32]
    78  		if mask&bit != 0 {
    79  			return true // signal already in queue
    80  		}
    81  		if atomic.Cas(&sig.mask[s/32], mask, mask|bit) {
    82  			break
    83  		}
    84  	}
    85  
    86  	// Notify receiver that queue has new bit.
    87  Send:
    88  	for {
    89  		switch atomic.Load(&sig.state) {
    90  		default:
    91  			throw("sigsend: inconsistent state")
    92  		case sigIdle:
    93  			if atomic.Cas(&sig.state, sigIdle, sigSending) {
    94  				break Send
    95  			}
    96  		case sigSending:
    97  			// notification already pending
    98  			break Send
    99  		case sigReceiving:
   100  			if atomic.Cas(&sig.state, sigReceiving, sigIdle) {
   101  				notewakeup(&sig.note)
   102  				break Send
   103  			}
   104  		}
   105  	}
   106  
   107  	return true
   108  }
   109  
   110  // Called to receive the next queued signal.
   111  // Must only be called from a single goroutine at a time.
   112  //go:linkname signal_recv os/signal.signal_recv
   113  func signal_recv() uint32 {
   114  	for {
   115  		// Serve any signals from local copy.
   116  		for i := uint32(0); i < _NSIG; i++ {
   117  			if sig.recv[i/32]&(1<<(i&31)) != 0 {
   118  				sig.recv[i/32] &^= 1 << (i & 31)
   119  				return i
   120  			}
   121  		}
   122  
   123  		// Wait for updates to be available from signal sender.
   124  	Receive:
   125  		for {
   126  			switch atomic.Load(&sig.state) {
   127  			default:
   128  				throw("signal_recv: inconsistent state")
   129  			case sigIdle:
   130  				if atomic.Cas(&sig.state, sigIdle, sigReceiving) {
   131  					notetsleepg(&sig.note, -1)
   132  					noteclear(&sig.note)
   133  					break Receive
   134  				}
   135  			case sigSending:
   136  				if atomic.Cas(&sig.state, sigSending, sigIdle) {
   137  					break Receive
   138  				}
   139  			}
   140  		}
   141  
   142  		// Incorporate updates from sender into local copy.
   143  		for i := range sig.mask {
   144  			sig.recv[i] = atomic.Xchg(&sig.mask[i], 0)
   145  		}
   146  	}
   147  }
   148  
   149  // signalWaitUntilIdle waits until the signal delivery mechanism is idle.
   150  // This is used to ensure that we do not drop a signal notification due
   151  // to a race between disabling a signal and receiving a signal.
   152  // This assumes that signal delivery has already been disabled for
   153  // the signal(s) in question, and here we are just waiting to make sure
   154  // that all the signals have been delivered to the user channels
   155  // by the os/signal package.
   156  //go:linkname signalWaitUntilIdle os/signal.signalWaitUntilIdle
   157  func signalWaitUntilIdle() {
   158  	// Although WaitUntilIdle seems like the right name for this
   159  	// function, the state we are looking for is sigReceiving, not
   160  	// sigIdle.  The sigIdle state is really more like sigProcessing.
   161  	for atomic.Load(&sig.state) != sigReceiving {
   162  		Gosched()
   163  	}
   164  }
   165  
   166  // Must only be called from a single goroutine at a time.
   167  //go:linkname signal_enable os/signal.signal_enable
   168  func signal_enable(s uint32) {
   169  	if !sig.inuse {
   170  		// The first call to signal_enable is for us
   171  		// to use for initialization. It does not pass
   172  		// signal information in m.
   173  		sig.inuse = true // enable reception of signals; cannot disable
   174  		noteclear(&sig.note)
   175  		return
   176  	}
   177  
   178  	if s >= uint32(len(sig.wanted)*32) {
   179  		return
   180  	}
   181  
   182  	w := sig.wanted[s/32]
   183  	w |= 1 << (s & 31)
   184  	atomic.Store(&sig.wanted[s/32], w)
   185  
   186  	i := sig.ignored[s/32]
   187  	i &^= 1 << (s & 31)
   188  	atomic.Store(&sig.ignored[s/32], i)
   189  
   190  	sigenable(s)
   191  }
   192  
   193  // Must only be called from a single goroutine at a time.
   194  //go:linkname signal_disable os/signal.signal_disable
   195  func signal_disable(s uint32) {
   196  	if s >= uint32(len(sig.wanted)*32) {
   197  		return
   198  	}
   199  	sigdisable(s)
   200  
   201  	w := sig.wanted[s/32]
   202  	w &^= 1 << (s & 31)
   203  	atomic.Store(&sig.wanted[s/32], w)
   204  }
   205  
   206  // Must only be called from a single goroutine at a time.
   207  //go:linkname signal_ignore os/signal.signal_ignore
   208  func signal_ignore(s uint32) {
   209  	if s >= uint32(len(sig.wanted)*32) {
   210  		return
   211  	}
   212  	sigignore(s)
   213  
   214  	w := sig.wanted[s/32]
   215  	w &^= 1 << (s & 31)
   216  	atomic.Store(&sig.wanted[s/32], w)
   217  
   218  	i := sig.ignored[s/32]
   219  	i |= 1 << (s & 31)
   220  	atomic.Store(&sig.ignored[s/32], i)
   221  }
   222  
   223  // Checked by signal handlers.
   224  func signal_ignored(s uint32) bool {
   225  	i := atomic.Load(&sig.ignored[s/32])
   226  	return i&(1<<(s&31)) != 0
   227  }