blob: e6e1a84063dd5adae2af705ff643d7bd2e323f26 [file] [log] [blame]
Dmitriy Vyukov651d0cf2014-08-24 11:50:37 +04001// 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.
Russ Cox81ed6842014-09-04 13:51:12 -04006//
7// Most synchronization primitives are not available from
8// the signal handler (it cannot block, allocate memory, or use locks)
9// so the handler communicates with a processing goroutine
10// via struct sig, below.
11//
Russ Coxf93e21a2014-09-05 14:38:29 -040012// sigsend is called by the signal handler to queue a new signal.
13// signal_recv is called by the Go program to receive a newly queued signal.
14// Synchronization between sigsend and signal_recv is based on the sig.state
15// variable. It can be in 3 states: sigIdle, sigReceiving and sigSending.
16// sigReceiving means that signal_recv is blocked on sig.Note and there are no
Russ Cox81ed6842014-09-04 13:51:12 -040017// new pending signals.
Russ Coxf93e21a2014-09-05 14:38:29 -040018// sigSending means that sig.mask *may* contain new pending signals,
19// signal_recv can't be blocked in this state.
20// sigIdle means that there are no new pending signals and signal_recv is not blocked.
Russ Cox81ed6842014-09-04 13:51:12 -040021// Transitions between states are done atomically with CAS.
Russ Coxf93e21a2014-09-05 14:38:29 -040022// When signal_recv is unblocked, it resets sig.Note and rechecks sig.mask.
23// If several sigsends and signal_recv execute concurrently, it can lead to
24// unnecessary rechecks of sig.mask, but it cannot lead to missed signals
Russ Cox81ed6842014-09-04 13:51:12 -040025// nor deadlocks.
Dmitriy Vyukov651d0cf2014-08-24 11:50:37 +040026
David du Colombierd5d4ab72015-01-22 23:38:29 +010027// +build !plan9
28
Dmitriy Vyukov651d0cf2014-08-24 11:50:37 +040029package runtime
30
Russ Cox81ed6842014-09-04 13:51:12 -040031import "unsafe"
32
33var sig struct {
34 note note
35 mask [(_NSIG + 31) / 32]uint32
36 wanted [(_NSIG + 31) / 32]uint32
37 recv [(_NSIG + 31) / 32]uint32
38 state uint32
39 inuse bool
40}
41
42const (
Russ Coxf93e21a2014-09-05 14:38:29 -040043 sigIdle = iota
44 sigReceiving
45 sigSending
Russ Cox81ed6842014-09-04 13:51:12 -040046)
47
48// Called from sighandler to send a signal back out of the signal handling thread.
Russ Coxf93e21a2014-09-05 14:38:29 -040049// Reports whether the signal was sent. If not, the caller typically crashes the program.
Russ Cox2d917c02014-11-11 17:05:55 -050050func sigsend(s uint32) bool {
Russ Cox81ed6842014-09-04 13:51:12 -040051 bit := uint32(1) << uint(s&31)
Todd Neala94e9062015-08-25 18:25:42 -050052 if !sig.inuse || s >= uint32(32*len(sig.wanted)) || sig.wanted[s/32]&bit == 0 {
Russ Cox81ed6842014-09-04 13:51:12 -040053 return false
54 }
55
Russ Coxf93e21a2014-09-05 14:38:29 -040056 // Add signal to outgoing queue.
Dmitriy Vyukov651d0cf2014-08-24 11:50:37 +040057 for {
Russ Cox81ed6842014-09-04 13:51:12 -040058 mask := sig.mask[s/32]
59 if mask&bit != 0 {
Russ Coxf93e21a2014-09-05 14:38:29 -040060 return true // signal already in queue
Dmitriy Vyukov651d0cf2014-08-24 11:50:37 +040061 }
Russ Cox81ed6842014-09-04 13:51:12 -040062 if cas(&sig.mask[s/32], mask, mask|bit) {
Russ Cox81ed6842014-09-04 13:51:12 -040063 break
64 }
65 }
Russ Coxf93e21a2014-09-05 14:38:29 -040066
67 // Notify receiver that queue has new bit.
68Send:
69 for {
70 switch atomicload(&sig.state) {
71 default:
Keith Randallb2a950b2014-12-27 20:58:00 -080072 throw("sigsend: inconsistent state")
Russ Coxf93e21a2014-09-05 14:38:29 -040073 case sigIdle:
74 if cas(&sig.state, sigIdle, sigSending) {
75 break Send
76 }
77 case sigSending:
78 // notification already pending
79 break Send
80 case sigReceiving:
81 if cas(&sig.state, sigReceiving, sigIdle) {
82 notewakeup(&sig.note)
83 break Send
84 }
85 }
86 }
87
Russ Cox81ed6842014-09-04 13:51:12 -040088 return true
89}
90
91// Called to receive the next queued signal.
92// Must only be called from a single goroutine at a time.
93func signal_recv() uint32 {
94 for {
Russ Coxf93e21a2014-09-05 14:38:29 -040095 // Serve any signals from local copy.
Russ Cox81ed6842014-09-04 13:51:12 -040096 for i := uint32(0); i < _NSIG; i++ {
97 if sig.recv[i/32]&(1<<(i&31)) != 0 {
98 sig.recv[i/32] &^= 1 << (i & 31)
99 return i
100 }
101 }
102
Russ Coxf93e21a2014-09-05 14:38:29 -0400103 // Wait for updates to be available from signal sender.
104 Receive:
Russ Cox81ed6842014-09-04 13:51:12 -0400105 for {
Russ Coxf93e21a2014-09-05 14:38:29 -0400106 switch atomicload(&sig.state) {
107 default:
Keith Randallb2a950b2014-12-27 20:58:00 -0800108 throw("signal_recv: inconsistent state")
Russ Coxf93e21a2014-09-05 14:38:29 -0400109 case sigIdle:
110 if cas(&sig.state, sigIdle, sigReceiving) {
Russ Cox81ed6842014-09-04 13:51:12 -0400111 notetsleepg(&sig.note, -1)
112 noteclear(&sig.note)
Russ Coxf93e21a2014-09-05 14:38:29 -0400113 break Receive
Russ Cox81ed6842014-09-04 13:51:12 -0400114 }
Russ Coxf93e21a2014-09-05 14:38:29 -0400115 case sigSending:
116 if cas(&sig.state, sigSending, sigIdle) {
117 break Receive
118 }
Russ Cox81ed6842014-09-04 13:51:12 -0400119 }
120 }
121
Russ Coxf93e21a2014-09-05 14:38:29 -0400122 // Incorporate updates from sender into local copy.
Russ Cox81ed6842014-09-04 13:51:12 -0400123 for i := range sig.mask {
Russ Coxf93e21a2014-09-05 14:38:29 -0400124 sig.recv[i] = xchg(&sig.mask[i], 0)
Russ Cox81ed6842014-09-04 13:51:12 -0400125 }
Dmitriy Vyukov651d0cf2014-08-24 11:50:37 +0400126 }
127}
128
Russ Cox81ed6842014-09-04 13:51:12 -0400129// Must only be called from a single goroutine at a time.
Dmitriy Vyukov651d0cf2014-08-24 11:50:37 +0400130func signal_enable(s uint32) {
Russ Cox81ed6842014-09-04 13:51:12 -0400131 if !sig.inuse {
132 // The first call to signal_enable is for us
133 // to use for initialization. It does not pass
134 // signal information in m.
135 sig.inuse = true // enable reception of signals; cannot disable
136 noteclear(&sig.note)
137 return
138 }
139
Todd Neala94e9062015-08-25 18:25:42 -0500140 if s >= uint32(len(sig.wanted)*32) {
Russ Cox81ed6842014-09-04 13:51:12 -0400141 return
142 }
143 sig.wanted[s/32] |= 1 << (s & 31)
Russ Cox656be312014-11-12 14:54:31 -0500144 sigenable(s)
Dmitriy Vyukov651d0cf2014-08-24 11:50:37 +0400145}
146
Russ Cox81ed6842014-09-04 13:51:12 -0400147// Must only be called from a single goroutine at a time.
Dmitriy Vyukov651d0cf2014-08-24 11:50:37 +0400148func signal_disable(s uint32) {
Todd Neala94e9062015-08-25 18:25:42 -0500149 if s >= uint32(len(sig.wanted)*32) {
Russ Cox81ed6842014-09-04 13:51:12 -0400150 return
151 }
152 sig.wanted[s/32] &^= 1 << (s & 31)
Russ Cox656be312014-11-12 14:54:31 -0500153 sigdisable(s)
Dmitriy Vyukov651d0cf2014-08-24 11:50:37 +0400154}
155
Michael MacInnis194ad162015-01-29 22:37:41 -0500156// Must only be called from a single goroutine at a time.
157func signal_ignore(s uint32) {
Todd Neala94e9062015-08-25 18:25:42 -0500158 if s >= uint32(len(sig.wanted)*32) {
Michael MacInnis194ad162015-01-29 22:37:41 -0500159 return
160 }
161 sig.wanted[s/32] &^= 1 << (s & 31)
162 sigignore(s)
163}
164
Russ Cox81ed6842014-09-04 13:51:12 -0400165// This runs on a foreign stack, without an m or a g. No stack split.
166//go:nosplit
Russ Cox75d77952015-07-22 15:31:54 -0400167//go:norace
Russ Cox81ed6842014-09-04 13:51:12 -0400168func badsignal(sig uintptr) {
Ian Lance Taylor872b1682015-07-21 22:34:48 -0700169 cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
170}
171
172func badsignalgo(sig uintptr) {
173 if !sigsend(uint32(sig)) {
174 // A foreign thread received the signal sig, and the
175 // Go code does not want to handle it.
176 raisebadsignal(int32(sig))
177 }
Russ Cox81ed6842014-09-04 13:51:12 -0400178}