// 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 { // 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 } } // 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) { }