github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/sigqueue_plan9.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 package runtime 8 9 import _ "unsafe" 10 11 const qsize = 64 12 13 var sig struct { 14 q noteQueue 15 inuse bool 16 17 lock mutex 18 note note 19 sleeping bool 20 } 21 22 type noteData struct { 23 s [_ERRMAX]byte 24 n int // n bytes of s are valid 25 } 26 27 type noteQueue struct { 28 lock mutex 29 data [qsize]noteData 30 ri int 31 wi int 32 full bool 33 } 34 35 // It is not allowed to allocate memory in the signal handler. 36 func (q *noteQueue) push(item *byte) bool { 37 lock(&q.lock) 38 if q.full { 39 unlock(&q.lock) 40 return false 41 } 42 s := gostringnocopy(item) 43 copy(q.data[q.wi].s[:], s) 44 q.data[q.wi].n = len(s) 45 q.wi++ 46 if q.wi == qsize { 47 q.wi = 0 48 } 49 if q.wi == q.ri { 50 q.full = true 51 } 52 unlock(&q.lock) 53 return true 54 } 55 56 func (q *noteQueue) pop() string { 57 lock(&q.lock) 58 q.full = false 59 if q.ri == q.wi { 60 unlock(&q.lock) 61 return "" 62 } 63 note := &q.data[q.ri] 64 item := string(note.s[:note.n]) 65 q.ri++ 66 if q.ri == qsize { 67 q.ri = 0 68 } 69 unlock(&q.lock) 70 return item 71 } 72 73 // Called from sighandler to send a signal back out of the signal handling thread. 74 // Reports whether the signal was sent. If not, the caller typically crashes the program. 75 func sendNote(s *byte) bool { 76 if !sig.inuse { 77 return false 78 } 79 80 // Add signal to outgoing queue. 81 if !sig.q.push(s) { 82 return false 83 } 84 85 lock(&sig.lock) 86 if sig.sleeping { 87 sig.sleeping = false 88 notewakeup(&sig.note) 89 } 90 unlock(&sig.lock) 91 92 return true 93 } 94 95 // Called to receive the next queued signal. 96 // Must only be called from a single goroutine at a time. 97 // 98 //go:linkname signal_recv os/signal.signal_recv 99 func signal_recv() string { 100 for { 101 note := sig.q.pop() 102 if note != "" { 103 return note 104 } 105 106 lock(&sig.lock) 107 sig.sleeping = true 108 noteclear(&sig.note) 109 unlock(&sig.lock) 110 notetsleepg(&sig.note, -1) 111 } 112 } 113 114 // signalWaitUntilIdle waits until the signal delivery mechanism is idle. 115 // This is used to ensure that we do not drop a signal notification due 116 // to a race between disabling a signal and receiving a signal. 117 // This assumes that signal delivery has already been disabled for 118 // the signal(s) in question, and here we are just waiting to make sure 119 // that all the signals have been delivered to the user channels 120 // by the os/signal package. 121 // 122 //go:linkname signalWaitUntilIdle os/signal.signalWaitUntilIdle 123 func signalWaitUntilIdle() { 124 for { 125 lock(&sig.lock) 126 sleeping := sig.sleeping 127 unlock(&sig.lock) 128 if sleeping { 129 return 130 } 131 Gosched() 132 } 133 } 134 135 // Must only be called from a single goroutine at a time. 136 // 137 //go:linkname signal_enable os/signal.signal_enable 138 func signal_enable(s uint32) { 139 if !sig.inuse { 140 // This is the first call to signal_enable. Initialize. 141 sig.inuse = true // enable reception of signals; cannot disable 142 noteclear(&sig.note) 143 } 144 } 145 146 // Must only be called from a single goroutine at a time. 147 // 148 //go:linkname signal_disable os/signal.signal_disable 149 func signal_disable(s uint32) { 150 } 151 152 // Must only be called from a single goroutine at a time. 153 // 154 //go:linkname signal_ignore os/signal.signal_ignore 155 func signal_ignore(s uint32) { 156 } 157 158 //go:linkname signal_ignored os/signal.signal_ignored 159 func signal_ignored(s uint32) bool { 160 return false 161 }