github.com/AESNooper/go/src@v0.0.0-20220218095104-b56a4ab1bbbb/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 4 states: sigIdle, sigReceiving, sigSending and sigFixup.
    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  // sigFixup is a transient state that can only exist as a short
    22  // transition from sigReceiving and then on to sigIdle: it is
    23  // used to ensure the AllThreadsSyscall()'s mDoFixup() operation
    24  // occurs on the sleeping m, waiting to receive a signal.
    25  // Transitions between states are done atomically with CAS.
    26  // When signal_recv is unblocked, it resets sig.Note and rechecks sig.mask.
    27  // If several sigsends and signal_recv execute concurrently, it can lead to
    28  // unnecessary rechecks of sig.mask, but it cannot lead to missed signals
    29  // nor deadlocks.
    30  
    31  //go:build !plan9
    32  
    33  package runtime
    34  
    35  import (
    36  	"runtime/internal/atomic"
    37  	_ "unsafe" // for go:linkname
    38  )
    39  
    40  // sig handles communication between the signal handler and os/signal.
    41  // Other than the inuse and recv fields, the fields are accessed atomically.
    42  //
    43  // The wanted and ignored fields are only written by one goroutine at
    44  // a time; access is controlled by the handlers Mutex in os/signal.
    45  // The fields are only read by that one goroutine and by the signal handler.
    46  // We access them atomically to minimize the race between setting them
    47  // in the goroutine calling os/signal and the signal handler,
    48  // which may be running in a different thread. That race is unavoidable,
    49  // as there is no connection between handling a signal and receiving one,
    50  // but atomic instructions should minimize it.
    51  var sig struct {
    52  	note       note
    53  	mask       [(_NSIG + 31) / 32]uint32
    54  	wanted     [(_NSIG + 31) / 32]uint32
    55  	ignored    [(_NSIG + 31) / 32]uint32
    56  	recv       [(_NSIG + 31) / 32]uint32
    57  	state      uint32
    58  	delivering uint32
    59  	inuse      bool
    60  }
    61  
    62  const (
    63  	sigIdle = iota
    64  	sigReceiving
    65  	sigSending
    66  	sigFixup
    67  )
    68  
    69  // sigsend delivers a signal from sighandler to the internal signal delivery queue.
    70  // It reports whether the signal was sent. If not, the caller typically crashes the program.
    71  // It runs from the signal handler, so it's limited in what it can do.
    72  func sigsend(s uint32) bool {
    73  	bit := uint32(1) << uint(s&31)
    74  	if s >= uint32(32*len(sig.wanted)) {
    75  		return false
    76  	}
    77  
    78  	atomic.Xadd(&sig.delivering, 1)
    79  	// We are running in the signal handler; defer is not available.
    80  
    81  	if w := atomic.Load(&sig.wanted[s/32]); w&bit == 0 {
    82  		atomic.Xadd(&sig.delivering, -1)
    83  		return false
    84  	}
    85  
    86  	// Add signal to outgoing queue.
    87  	for {
    88  		mask := sig.mask[s/32]
    89  		if mask&bit != 0 {
    90  			atomic.Xadd(&sig.delivering, -1)
    91  			return true // signal already in queue
    92  		}
    93  		if atomic.Cas(&sig.mask[s/32], mask, mask|bit) {
    94  			break
    95  		}
    96  	}
    97  
    98  	// Notify receiver that queue has new bit.
    99  Send:
   100  	for {
   101  		switch atomic.Load(&sig.state) {
   102  		default:
   103  			throw("sigsend: inconsistent state")
   104  		case sigIdle:
   105  			if atomic.Cas(&sig.state, sigIdle, sigSending) {
   106  				break Send
   107  			}
   108  		case sigSending:
   109  			// notification already pending
   110  			break Send
   111  		case sigReceiving:
   112  			if atomic.Cas(&sig.state, sigReceiving, sigIdle) {
   113  				if GOOS == "darwin" || GOOS == "ios" {
   114  					sigNoteWakeup(&sig.note)
   115  					break Send
   116  				}
   117  				notewakeup(&sig.note)
   118  				break Send
   119  			}
   120  		case sigFixup:
   121  			// nothing to do - we need to wait for sigIdle.
   122  			mDoFixupAndOSYield()
   123  		}
   124  	}
   125  
   126  	atomic.Xadd(&sig.delivering, -1)
   127  	return true
   128  }
   129  
   130  // sigRecvPrepareForFixup is used to temporarily wake up the
   131  // signal_recv() running thread while it is blocked waiting for the
   132  // arrival of a signal. If it causes the thread to wake up, the
   133  // sig.state travels through this sequence: sigReceiving -> sigFixup
   134  // -> sigIdle -> sigReceiving and resumes. (This is only called while
   135  // GC is disabled.)
   136  //go:nosplit
   137  func sigRecvPrepareForFixup() {
   138  	if atomic.Cas(&sig.state, sigReceiving, sigFixup) {
   139  		notewakeup(&sig.note)
   140  	}
   141  }
   142  
   143  // Called to receive the next queued signal.
   144  // Must only be called from a single goroutine at a time.
   145  //go:linkname signal_recv os/signal.signal_recv
   146  func signal_recv() uint32 {
   147  	for {
   148  		// Serve any signals from local copy.
   149  		for i := uint32(0); i < _NSIG; i++ {
   150  			if sig.recv[i/32]&(1<<(i&31)) != 0 {
   151  				sig.recv[i/32] &^= 1 << (i & 31)
   152  				return i
   153  			}
   154  		}
   155  
   156  		// Wait for updates to be available from signal sender.
   157  	Receive:
   158  		for {
   159  			switch atomic.Load(&sig.state) {
   160  			default:
   161  				throw("signal_recv: inconsistent state")
   162  			case sigIdle:
   163  				if atomic.Cas(&sig.state, sigIdle, sigReceiving) {
   164  					if GOOS == "darwin" || GOOS == "ios" {
   165  						sigNoteSleep(&sig.note)
   166  						break Receive
   167  					}
   168  					notetsleepg(&sig.note, -1)
   169  					noteclear(&sig.note)
   170  					if !atomic.Cas(&sig.state, sigFixup, sigIdle) {
   171  						break Receive
   172  					}
   173  					// Getting here, the code will
   174  					// loop around again to sleep
   175  					// in state sigReceiving. This
   176  					// path is taken when
   177  					// sigRecvPrepareForFixup()
   178  					// has been called by another
   179  					// thread.
   180  				}
   181  			case sigSending:
   182  				if atomic.Cas(&sig.state, sigSending, sigIdle) {
   183  					break Receive
   184  				}
   185  			}
   186  		}
   187  
   188  		// Incorporate updates from sender into local copy.
   189  		for i := range sig.mask {
   190  			sig.recv[i] = atomic.Xchg(&sig.mask[i], 0)
   191  		}
   192  	}
   193  }
   194  
   195  // signalWaitUntilIdle waits until the signal delivery mechanism is idle.
   196  // This is used to ensure that we do not drop a signal notification due
   197  // to a race between disabling a signal and receiving a signal.
   198  // This assumes that signal delivery has already been disabled for
   199  // the signal(s) in question, and here we are just waiting to make sure
   200  // that all the signals have been delivered to the user channels
   201  // by the os/signal package.
   202  //go:linkname signalWaitUntilIdle os/signal.signalWaitUntilIdle
   203  func signalWaitUntilIdle() {
   204  	// Although the signals we care about have been removed from
   205  	// sig.wanted, it is possible that another thread has received
   206  	// a signal, has read from sig.wanted, is now updating sig.mask,
   207  	// and has not yet woken up the processor thread. We need to wait
   208  	// until all current signal deliveries have completed.
   209  	for atomic.Load(&sig.delivering) != 0 {
   210  		Gosched()
   211  	}
   212  
   213  	// Although WaitUntilIdle seems like the right name for this
   214  	// function, the state we are looking for is sigReceiving, not
   215  	// sigIdle.  The sigIdle state is really more like sigProcessing.
   216  	for atomic.Load(&sig.state) != sigReceiving {
   217  		Gosched()
   218  	}
   219  }
   220  
   221  // Must only be called from a single goroutine at a time.
   222  //go:linkname signal_enable os/signal.signal_enable
   223  func signal_enable(s uint32) {
   224  	if !sig.inuse {
   225  		// This is the first call to signal_enable. Initialize.
   226  		sig.inuse = true // enable reception of signals; cannot disable
   227  		if GOOS == "darwin" || GOOS == "ios" {
   228  			sigNoteSetup(&sig.note)
   229  		} else {
   230  			noteclear(&sig.note)
   231  		}
   232  	}
   233  
   234  	if s >= uint32(len(sig.wanted)*32) {
   235  		return
   236  	}
   237  
   238  	w := sig.wanted[s/32]
   239  	w |= 1 << (s & 31)
   240  	atomic.Store(&sig.wanted[s/32], w)
   241  
   242  	i := sig.ignored[s/32]
   243  	i &^= 1 << (s & 31)
   244  	atomic.Store(&sig.ignored[s/32], i)
   245  
   246  	sigenable(s)
   247  }
   248  
   249  // Must only be called from a single goroutine at a time.
   250  //go:linkname signal_disable os/signal.signal_disable
   251  func signal_disable(s uint32) {
   252  	if s >= uint32(len(sig.wanted)*32) {
   253  		return
   254  	}
   255  	sigdisable(s)
   256  
   257  	w := sig.wanted[s/32]
   258  	w &^= 1 << (s & 31)
   259  	atomic.Store(&sig.wanted[s/32], w)
   260  }
   261  
   262  // Must only be called from a single goroutine at a time.
   263  //go:linkname signal_ignore os/signal.signal_ignore
   264  func signal_ignore(s uint32) {
   265  	if s >= uint32(len(sig.wanted)*32) {
   266  		return
   267  	}
   268  	sigignore(s)
   269  
   270  	w := sig.wanted[s/32]
   271  	w &^= 1 << (s & 31)
   272  	atomic.Store(&sig.wanted[s/32], w)
   273  
   274  	i := sig.ignored[s/32]
   275  	i |= 1 << (s & 31)
   276  	atomic.Store(&sig.ignored[s/32], i)
   277  }
   278  
   279  // sigInitIgnored marks the signal as already ignored. This is called at
   280  // program start by initsig. In a shared library initsig is called by
   281  // libpreinit, so the runtime may not be initialized yet.
   282  //go:nosplit
   283  func sigInitIgnored(s uint32) {
   284  	i := sig.ignored[s/32]
   285  	i |= 1 << (s & 31)
   286  	atomic.Store(&sig.ignored[s/32], i)
   287  }
   288  
   289  // Checked by signal handlers.
   290  //go:linkname signal_ignored os/signal.signal_ignored
   291  func signal_ignored(s uint32) bool {
   292  	i := atomic.Load(&sig.ignored[s/32])
   293  	return i&(1<<(s&31)) != 0
   294  }