// 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. // // Most synchronization primitives are not available from // the signal handler (it cannot block and cannot use locks) // so the handler communicates with a processing goroutine // via struct sig, below. // // Ownership for sig.Note passes back and forth between // the signal handler and the signal goroutine in rounds. // The initial state is that sig.note is cleared (setup by siginit). // At the beginning of each round, mask == 0. // The round goes through three stages: // // (In parallel) // 1a) One or more signals arrive and are handled // by sigsend using cas to set bits in sig.mask. // The handler that changes sig.mask from zero to non-zero // calls notewakeup(&sig). // 1b) Sigrecv calls notesleep(&sig) to wait for the wakeup. // // 2) Having received the wakeup, sigrecv knows that sigsend // will not send another wakeup, so it can noteclear(&sig) // to prepare for the next round. (Sigsend may still be adding // signals to sig.mask at this point, which is fine.) // // 3) Sigrecv uses cas to grab the current sig.mask and zero it, // triggering the next round. // // The signal handler takes ownership of the note by atomically // changing mask from a zero to non-zero value. It gives up // ownership by calling notewakeup. The signal goroutine takes // ownership by returning from notesleep (caused by the notewakeup) // and gives up ownership by clearing mask. package runtime #include "config.h" #include "runtime.h" #include "malloc.h" #include "defs.h" static struct { Note; uint32 mask; bool inuse; } sig; void siginit(void) { noteclear(&sig); } // Called from sighandler to send a signal back out of the signal handling thread. bool __go_sigsend(int32 s) { uint32 bit, mask; if(!sig.inuse) return false; bit = 1 << s; for(;;) { mask = sig.mask; if(mask & bit) break; // signal already in queue if(runtime_cas(&sig.mask, mask, mask|bit)) { // Added to queue. // Only send a wakeup for the first signal in each round. if(mask == 0) notewakeup(&sig); break; } } return true; } // Called to receive a bitmask of queued signals. func Sigrecv() (m uint32) { // runtime·entersyscall(); notesleep(&sig); // runtime·exitsyscall(); noteclear(&sig); for(;;) { m = sig.mask; if(runtime_cas(&sig.mask, m, 0)) break; } } func Signame(sig int32) (name String) { const char* s = NULL; char buf[100]; #if defined(HAVE_STRSIGNAL) s = strsignal(sig); #endif if (s == NULL) { snprintf(buf, sizeof buf, "signal %d", sig); s = buf; } int32 len = __builtin_strlen(s); unsigned char *data = runtime_mallocgc(len, RefNoPointers, 0, 0); __builtin_memcpy(data, s, len); name.__data = data; name.__length = len; } func Siginit() { sig.inuse = true; // enable reception of signals; cannot disable }