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// 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// 12// 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: 0, HASWAITER and HASSIGNAL. 16// HASWAITER means that signal_recv() is blocked on sig.Note and there are no 17// new pending signals. 18// HASSIGNAL means that sig.mask *may* contain new pending signals, 19// signal_recv() can't be blocked in this state. 20// 0 means that there are no new pending signals and signal_recv() is not blocked. 21// Transitions between states are done atomically with CAS. 22// When signal_recv() is unblocked, it resets sig.Note and rechecks sig.mask. 23// If several sigsend()'s and signal_recv() execute concurrently, it can lead to 24// unnecessary rechecks of sig.mask, but must not lead to missed signals 25// nor deadlocks. 26 27package signal 28#include "config.h" 29#include "runtime.h" 30#include "arch.h" 31#include "malloc.h" 32#include "defs.h" 33 34static struct { 35 Note; 36 uint32 mask[(NSIG+31)/32]; 37 uint32 wanted[(NSIG+31)/32]; 38 uint32 state; 39 bool inuse; 40} sig; 41 42enum { 43 HASWAITER = 1, 44 HASSIGNAL = 2, 45}; 46 47// Called from sighandler to send a signal back out of the signal handling thread. 48bool 49__go_sigsend(int32 s) 50{ 51 uint32 bit, mask, old, new; 52 53 if(!sig.inuse || s < 0 || (size_t)s >= 32*nelem(sig.wanted) || !(sig.wanted[s/32]&(1U<<(s&31)))) 54 return false; 55 bit = 1 << (s&31); 56 for(;;) { 57 mask = sig.mask[s/32]; 58 if(mask & bit) 59 break; // signal already in queue 60 if(runtime_cas(&sig.mask[s/32], mask, mask|bit)) { 61 // Added to queue. 62 // Only send a wakeup if the receiver needs a kick. 63 for(;;) { 64 old = runtime_atomicload(&sig.state); 65 if(old == HASSIGNAL) 66 break; 67 if(old == HASWAITER) 68 new = 0; 69 else // if(old == 0) 70 new = HASSIGNAL; 71 if(runtime_cas(&sig.state, old, new)) { 72 if (old == HASWAITER) 73 runtime_notewakeup(&sig); 74 break; 75 } 76 } 77 break; 78 } 79 } 80 return true; 81} 82 83// Called to receive the next queued signal. 84// Must only be called from a single goroutine at a time. 85func signal_recv() (m uint32) { 86 static uint32 recv[nelem(sig.mask)]; 87 uint32 i, old, new; 88 89 for(;;) { 90 // Serve from local copy if there are bits left. 91 for(i=0; i<NSIG; i++) { 92 if(recv[i/32]&(1U<<(i&31))) { 93 recv[i/32] ^= 1U<<(i&31); 94 m = i; 95 goto done; 96 } 97 } 98 99 // Check and update sig.state. 100 for(;;) { 101 old = runtime_atomicload(&sig.state); 102 if(old == HASWAITER) 103 runtime_throw("inconsistent state in signal_recv"); 104 if(old == HASSIGNAL) 105 new = 0; 106 else // if(old == 0) 107 new = HASWAITER; 108 if(runtime_cas(&sig.state, old, new)) { 109 if (new == HASWAITER) { 110 runtime_notetsleepg(&sig, -1); 111 runtime_noteclear(&sig); 112 } 113 break; 114 } 115 } 116 117 // Get a new local copy. 118 for(i=0; (size_t)i<nelem(sig.mask); i++) { 119 for(;;) { 120 m = sig.mask[i]; 121 if(runtime_cas(&sig.mask[i], m, 0)) 122 break; 123 } 124 recv[i] = m; 125 } 126 } 127 128done:; 129 // goc requires that we fall off the end of functions 130 // that return values instead of using our own return 131 // statements. 132} 133 134// Must only be called from a single goroutine at a time. 135func signal_enable(s uint32) { 136 if(!sig.inuse) { 137 // The first call to signal_enable is for us 138 // to use for initialization. It does not pass 139 // signal information in m. 140 sig.inuse = true; // enable reception of signals; cannot disable 141 runtime_noteclear(&sig); 142 return; 143 } 144 145 if(s >= nelem(sig.wanted)*32) 146 return; 147 sig.wanted[s/32] |= 1U<<(s&31); 148 runtime_sigenable(s); 149} 150 151// Must only be called from a single goroutine at a time. 152func signal_disable(s uint32) { 153 if(s >= nelem(sig.wanted)*32) 154 return; 155 sig.wanted[s/32] &= ~(1U<<(s&31)); 156 runtime_sigdisable(s); 157} 158 159// Must only be called from a single goroutine at a time. 160func signal_ignore(s uint32) { 161 if (s >= nelem(sig.wanted)*32) 162 return; 163 sig.wanted[s/32] &= ~(1U<<(s&31)); 164 runtime_sigignore(s); 165} 166 167// This runs on a foreign stack, without an m or a g. No stack split. 168void 169runtime_badsignal(int sig) 170{ 171 __go_sigsend(sig); 172} 173