mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			256 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			256 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
	
// Copyright 2009 The Go Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
// This file implements runtime support for signal handling.
 | 
						|
//
 | 
						|
// Most synchronization primitives are not available from
 | 
						|
// the signal handler (it cannot block, allocate memory, or use locks)
 | 
						|
// so the handler communicates with a processing goroutine
 | 
						|
// via struct sig, below.
 | 
						|
//
 | 
						|
// sigsend is called by the signal handler to queue a new signal.
 | 
						|
// signal_recv is called by the Go program to receive a newly queued signal.
 | 
						|
// Synchronization between sigsend and signal_recv is based on the sig.state
 | 
						|
// variable. It can be in 3 states: sigIdle, sigReceiving and sigSending.
 | 
						|
// sigReceiving means that signal_recv is blocked on sig.Note and there are no
 | 
						|
// new pending signals.
 | 
						|
// sigSending means that sig.mask *may* contain new pending signals,
 | 
						|
// signal_recv can't be blocked in this state.
 | 
						|
// sigIdle means that there are no new pending signals and signal_recv is not blocked.
 | 
						|
// Transitions between states are done atomically with CAS.
 | 
						|
// When signal_recv is unblocked, it resets sig.Note and rechecks sig.mask.
 | 
						|
// If several sigsends and signal_recv execute concurrently, it can lead to
 | 
						|
// unnecessary rechecks of sig.mask, but it cannot lead to missed signals
 | 
						|
// nor deadlocks.
 | 
						|
 | 
						|
// +build !plan9
 | 
						|
 | 
						|
package runtime
 | 
						|
 | 
						|
import (
 | 
						|
	"runtime/internal/atomic"
 | 
						|
	_ "unsafe" // for go:linkname
 | 
						|
)
 | 
						|
 | 
						|
// sig handles communication between the signal handler and os/signal.
 | 
						|
// Other than the inuse and recv fields, the fields are accessed atomically.
 | 
						|
//
 | 
						|
// The wanted and ignored fields are only written by one goroutine at
 | 
						|
// a time; access is controlled by the handlers Mutex in os/signal.
 | 
						|
// The fields are only read by that one goroutine and by the signal handler.
 | 
						|
// We access them atomically to minimize the race between setting them
 | 
						|
// in the goroutine calling os/signal and the signal handler,
 | 
						|
// which may be running in a different thread. That race is unavoidable,
 | 
						|
// as there is no connection between handling a signal and receiving one,
 | 
						|
// but atomic instructions should minimize it.
 | 
						|
var sig struct {
 | 
						|
	note       note
 | 
						|
	mask       [(_NSIG + 31) / 32]uint32
 | 
						|
	wanted     [(_NSIG + 31) / 32]uint32
 | 
						|
	ignored    [(_NSIG + 31) / 32]uint32
 | 
						|
	recv       [(_NSIG + 31) / 32]uint32
 | 
						|
	state      uint32
 | 
						|
	delivering uint32
 | 
						|
	inuse      bool
 | 
						|
}
 | 
						|
 | 
						|
const (
 | 
						|
	sigIdle = iota
 | 
						|
	sigReceiving
 | 
						|
	sigSending
 | 
						|
)
 | 
						|
 | 
						|
// sigsend delivers a signal from sighandler to the internal signal delivery queue.
 | 
						|
// It reports whether the signal was sent. If not, the caller typically crashes the program.
 | 
						|
// It runs from the signal handler, so it's limited in what it can do.
 | 
						|
func sigsend(s uint32) bool {
 | 
						|
	bit := uint32(1) << uint(s&31)
 | 
						|
	if !sig.inuse || s >= uint32(32*len(sig.wanted)) {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	atomic.Xadd(&sig.delivering, 1)
 | 
						|
	// We are running in the signal handler; defer is not available.
 | 
						|
 | 
						|
	if w := atomic.Load(&sig.wanted[s/32]); w&bit == 0 {
 | 
						|
		atomic.Xadd(&sig.delivering, -1)
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	// Add signal to outgoing queue.
 | 
						|
	for {
 | 
						|
		mask := sig.mask[s/32]
 | 
						|
		if mask&bit != 0 {
 | 
						|
			atomic.Xadd(&sig.delivering, -1)
 | 
						|
			return true // signal already in queue
 | 
						|
		}
 | 
						|
		if atomic.Cas(&sig.mask[s/32], mask, mask|bit) {
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Notify receiver that queue has new bit.
 | 
						|
Send:
 | 
						|
	for {
 | 
						|
		switch atomic.Load(&sig.state) {
 | 
						|
		default:
 | 
						|
			throw("sigsend: inconsistent state")
 | 
						|
		case sigIdle:
 | 
						|
			if atomic.Cas(&sig.state, sigIdle, sigSending) {
 | 
						|
				break Send
 | 
						|
			}
 | 
						|
		case sigSending:
 | 
						|
			// notification already pending
 | 
						|
			break Send
 | 
						|
		case sigReceiving:
 | 
						|
			if atomic.Cas(&sig.state, sigReceiving, sigIdle) {
 | 
						|
				notewakeup(&sig.note)
 | 
						|
				break Send
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	atomic.Xadd(&sig.delivering, -1)
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
// Called to receive the next queued signal.
 | 
						|
// Must only be called from a single goroutine at a time.
 | 
						|
//go:linkname signal_recv os..z2fsignal.signal_recv
 | 
						|
func signal_recv() uint32 {
 | 
						|
	for {
 | 
						|
		// Serve any signals from local copy.
 | 
						|
		for i := uint32(0); i < _NSIG; i++ {
 | 
						|
			if sig.recv[i/32]&(1<<(i&31)) != 0 {
 | 
						|
				sig.recv[i/32] &^= 1 << (i & 31)
 | 
						|
				return i
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Wait for updates to be available from signal sender.
 | 
						|
	Receive:
 | 
						|
		for {
 | 
						|
			switch atomic.Load(&sig.state) {
 | 
						|
			default:
 | 
						|
				throw("signal_recv: inconsistent state")
 | 
						|
			case sigIdle:
 | 
						|
				if atomic.Cas(&sig.state, sigIdle, sigReceiving) {
 | 
						|
					notetsleepg(&sig.note, -1)
 | 
						|
					noteclear(&sig.note)
 | 
						|
					break Receive
 | 
						|
				}
 | 
						|
			case sigSending:
 | 
						|
				if atomic.Cas(&sig.state, sigSending, sigIdle) {
 | 
						|
					break Receive
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Incorporate updates from sender into local copy.
 | 
						|
		for i := range sig.mask {
 | 
						|
			sig.recv[i] = atomic.Xchg(&sig.mask[i], 0)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// signalWaitUntilIdle waits until the signal delivery mechanism is idle.
 | 
						|
// This is used to ensure that we do not drop a signal notification due
 | 
						|
// to a race between disabling a signal and receiving a signal.
 | 
						|
// This assumes that signal delivery has already been disabled for
 | 
						|
// the signal(s) in question, and here we are just waiting to make sure
 | 
						|
// that all the signals have been delivered to the user channels
 | 
						|
// by the os/signal package.
 | 
						|
//go:linkname signalWaitUntilIdle os..z2fsignal.signalWaitUntilIdle
 | 
						|
func signalWaitUntilIdle() {
 | 
						|
	// Although the signals we care about have been removed from
 | 
						|
	// sig.wanted, it is possible that another thread has received
 | 
						|
	// a signal, has read from sig.wanted, is now updating sig.mask,
 | 
						|
	// and has not yet woken up the processor thread. We need to wait
 | 
						|
	// until all current signal deliveries have completed.
 | 
						|
	for atomic.Load(&sig.delivering) != 0 {
 | 
						|
		Gosched()
 | 
						|
	}
 | 
						|
 | 
						|
	// Although WaitUntilIdle seems like the right name for this
 | 
						|
	// function, the state we are looking for is sigReceiving, not
 | 
						|
	// sigIdle.  The sigIdle state is really more like sigProcessing.
 | 
						|
	for atomic.Load(&sig.state) != sigReceiving {
 | 
						|
		Gosched()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Must only be called from a single goroutine at a time.
 | 
						|
//go:linkname signal_enable os..z2fsignal.signal_enable
 | 
						|
func signal_enable(s uint32) {
 | 
						|
	if !sig.inuse {
 | 
						|
		// The first call to signal_enable is for us
 | 
						|
		// to use for initialization. It does not pass
 | 
						|
		// signal information in m.
 | 
						|
		sig.inuse = true // enable reception of signals; cannot disable
 | 
						|
		noteclear(&sig.note)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if s >= uint32(len(sig.wanted)*32) {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	w := sig.wanted[s/32]
 | 
						|
	w |= 1 << (s & 31)
 | 
						|
	atomic.Store(&sig.wanted[s/32], w)
 | 
						|
 | 
						|
	i := sig.ignored[s/32]
 | 
						|
	i &^= 1 << (s & 31)
 | 
						|
	atomic.Store(&sig.ignored[s/32], i)
 | 
						|
 | 
						|
	sigenable(s)
 | 
						|
}
 | 
						|
 | 
						|
// Must only be called from a single goroutine at a time.
 | 
						|
//go:linkname signal_disable os..z2fsignal.signal_disable
 | 
						|
func signal_disable(s uint32) {
 | 
						|
	if s >= uint32(len(sig.wanted)*32) {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	sigdisable(s)
 | 
						|
 | 
						|
	w := sig.wanted[s/32]
 | 
						|
	w &^= 1 << (s & 31)
 | 
						|
	atomic.Store(&sig.wanted[s/32], w)
 | 
						|
}
 | 
						|
 | 
						|
// Must only be called from a single goroutine at a time.
 | 
						|
//go:linkname signal_ignore os..z2fsignal.signal_ignore
 | 
						|
func signal_ignore(s uint32) {
 | 
						|
	if s >= uint32(len(sig.wanted)*32) {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	sigignore(s)
 | 
						|
 | 
						|
	w := sig.wanted[s/32]
 | 
						|
	w &^= 1 << (s & 31)
 | 
						|
	atomic.Store(&sig.wanted[s/32], w)
 | 
						|
 | 
						|
	i := sig.ignored[s/32]
 | 
						|
	i |= 1 << (s & 31)
 | 
						|
	atomic.Store(&sig.ignored[s/32], i)
 | 
						|
}
 | 
						|
 | 
						|
// sigInitIgnored marks the signal as already ignored. This is called at
 | 
						|
// program start by initsig. In a shared library initsig is called by
 | 
						|
// libpreinit, so the runtime may not be initialized yet.
 | 
						|
//go:nosplit
 | 
						|
func sigInitIgnored(s uint32) {
 | 
						|
	i := sig.ignored[s/32]
 | 
						|
	i |= 1 << (s & 31)
 | 
						|
	atomic.Store(&sig.ignored[s/32], i)
 | 
						|
}
 | 
						|
 | 
						|
// Checked by signal handlers.
 | 
						|
//go:linkname signal_ignored os..z2fsignal.signal_ignored
 | 
						|
func signal_ignored(s uint32) bool {
 | 
						|
	i := atomic.Load(&sig.ignored[s/32])
 | 
						|
	return i&(1<<(s&31)) != 0
 | 
						|
}
 |