blob: aebd2060e791ac721987da89532930ac6432d847 [file] [log] [blame]
// 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.
package runtime
import _ "unsafe"
const qsize = 64
var sig struct {
q noteQueue
inuse bool
lock mutex
note note
sleeping bool
}
type noteData struct {
s [_ERRMAX]byte
n int // n bytes of s are valid
}
type noteQueue struct {
lock mutex
data [qsize]noteData
ri int
wi int
full bool
}
// It is not allowed to allocate memory in the signal handler.
func (q *noteQueue) push(item *byte) bool {
lock(&q.lock)
if q.full {
unlock(&q.lock)
return false
}
s := gostringnocopy(item)
copy(q.data[q.wi].s[:], s)
q.data[q.wi].n = len(s)
q.wi++
if q.wi == qsize {
q.wi = 0
}
if q.wi == q.ri {
q.full = true
}
unlock(&q.lock)
return true
}
func (q *noteQueue) pop() string {
lock(&q.lock)
q.full = false
if q.ri == q.wi {
unlock(&q.lock)
return ""
}
note := &q.data[q.ri]
item := string(note.s[:note.n])
q.ri++
if q.ri == qsize {
q.ri = 0
}
unlock(&q.lock)
return item
}
// Called from sighandler to send a signal back out of the signal handling thread.
// Reports whether the signal was sent. If not, the caller typically crashes the program.
func sendNote(s *byte) bool {
if !sig.inuse {
return false
}
// Add signal to outgoing queue.
if !sig.q.push(s) {
return false
}
lock(&sig.lock)
if sig.sleeping {
sig.sleeping = false
notewakeup(&sig.note)
}
unlock(&sig.lock)
return true
}
// sigRecvPrepareForFixup is a no-op on plan9. (This would only be
// called while GC is disabled.)
//
//go:nosplit
func sigRecvPrepareForFixup() {
}
// Called to receive the next queued signal.
// Must only be called from a single goroutine at a time.
//go:linkname signal_recv os/signal.signal_recv
func signal_recv() string {
for {
note := sig.q.pop()
if note != "" {
return note
}
lock(&sig.lock)
sig.sleeping = true
noteclear(&sig.note)
unlock(&sig.lock)
notetsleepg(&sig.note, -1)
}
}
// 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/signal.signalWaitUntilIdle
func signalWaitUntilIdle() {
for {
lock(&sig.lock)
sleeping := sig.sleeping
unlock(&sig.lock)
if sleeping {
return
}
Gosched()
}
}
// Must only be called from a single goroutine at a time.
//go:linkname signal_enable os/signal.signal_enable
func signal_enable(s uint32) {
if !sig.inuse {
// This is the first call to signal_enable. Initialize.
sig.inuse = true // enable reception of signals; cannot disable
noteclear(&sig.note)
}
}
// Must only be called from a single goroutine at a time.
//go:linkname signal_disable os/signal.signal_disable
func signal_disable(s uint32) {
}
// Must only be called from a single goroutine at a time.
//go:linkname signal_ignore os/signal.signal_ignore
func signal_ignore(s uint32) {
}
//go:linkname signal_ignored os/signal.signal_ignored
func signal_ignored(s uint32) bool {
return false
}