// 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 "runtime.h" #include "defs_GOOS_GOARCH.h" static struct { Note; uint32 mask; bool inuse; } sig; void runtime·siginit(void) { runtime·noteclear(&sig); } // Called from sighandler to send a signal back out of the signal handling thread. bool runtime·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) runtime·notewakeup(&sig); break; } } return true; } // Called to receive a bitmask of queued signals. func Sigrecv() (m uint32) { runtime·entersyscall(); runtime·notesleep(&sig); runtime·exitsyscall(); runtime·noteclear(&sig); for(;;) { m = sig.mask; if(runtime·cas(&sig.mask, m, 0)) break; } } func Signame(sig int32) (name String) { name = runtime·signame(sig); } func Siginit() { runtime·initsig(SigQueue); sig.inuse = true; // enable reception of signals; cannot disable }