diff options
Diffstat (limited to 'src/runtime/sigqueue_plan9.go')
-rw-r--r-- | src/runtime/sigqueue_plan9.go | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/src/runtime/sigqueue_plan9.go b/src/runtime/sigqueue_plan9.go new file mode 100644 index 0000000..d5fe8f8 --- /dev/null +++ b/src/runtime/sigqueue_plan9.go @@ -0,0 +1,156 @@ +// 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 +} + +// 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 +} |