blob: 504590a54e66a4d6daeeb8de9a4ba380a132cfbc [file] [log] [blame]
David Symondsb5866492009-12-15 18:21:29 -08001// 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 and cannot use locks)
9// so the handler communicates with a processing goroutine
10// via struct sig, below.
11//
12// Ownership for sig.Note passes back and forth between
13// the signal handler and the signal goroutine in rounds.
14// The initial state is that sig.note is cleared (setup by siginit).
15// At the beginning of each round, mask == 0.
16// The round goes through three stages:
17//
18// (In parallel)
19// 1a) One or more signals arrive and are handled
20// by sigsend using cas to set bits in sig.mask.
21// The handler that changes sig.mask from zero to non-zero
22// calls notewakeup(&sig).
23// 1b) Sigrecv calls notesleep(&sig) to wait for the wakeup.
24//
25// 2) Having received the wakeup, sigrecv knows that sigsend
26// will not send another wakeup, so it can noteclear(&sig)
27// to prepare for the next round. (Sigsend may still be adding
28// signals to sig.mask at this point, which is fine.)
29//
30// 3) Sigrecv uses cas to grab the current sig.mask and zero it,
31// triggering the next round.
32//
33// The signal handler takes ownership of the note by atomically
34// changing mask from a zero to non-zero value. It gives up
35// ownership by calling notewakeup. The signal goroutine takes
36// ownership by returning from notesleep (caused by the notewakeup)
37// and gives up ownership by clearing mask.
38
39package runtime
40#include "runtime.h"
41#include "defs.h"
42
43static struct {
44 Note;
45 uint32 mask;
Russ Cox08579c22009-12-16 20:20:50 -080046 bool inuse;
David Symondsb5866492009-12-15 18:21:29 -080047} sig;
48
49void
Russ Cox68b42552010-11-04 14:00:19 -040050runtime·siginit(void)
David Symondsb5866492009-12-15 18:21:29 -080051{
Russ Cox68b42552010-11-04 14:00:19 -040052 runtime·noteclear(&sig);
David Symondsb5866492009-12-15 18:21:29 -080053}
54
55// Called from sighandler to send a signal back out of the signal handling thread.
Russ Cox08579c22009-12-16 20:20:50 -080056bool
Russ Cox68b42552010-11-04 14:00:19 -040057runtime·sigsend(int32 s)
David Symondsb5866492009-12-15 18:21:29 -080058{
59 uint32 bit, mask;
60
Russ Cox08579c22009-12-16 20:20:50 -080061 if(!sig.inuse)
62 return false;
David Symondsb5866492009-12-15 18:21:29 -080063 bit = 1 << s;
64 for(;;) {
65 mask = sig.mask;
66 if(mask & bit)
Russ Cox08579c22009-12-16 20:20:50 -080067 break; // signal already in queue
Russ Cox68b42552010-11-04 14:00:19 -040068 if(runtime·cas(&sig.mask, mask, mask|bit)) {
David Symondsb5866492009-12-15 18:21:29 -080069 // Added to queue.
70 // Only send a wakeup for the first signal in each round.
71 if(mask == 0)
Russ Cox68b42552010-11-04 14:00:19 -040072 runtime·notewakeup(&sig);
Russ Cox08579c22009-12-16 20:20:50 -080073 break;
David Symondsb5866492009-12-15 18:21:29 -080074 }
75 }
Russ Cox08579c22009-12-16 20:20:50 -080076 return true;
David Symondsb5866492009-12-15 18:21:29 -080077}
78
79// Called to receive a bitmask of queued signals.
80func Sigrecv() (m uint32) {
Russ Cox68b42552010-11-04 14:00:19 -040081 runtime·entersyscall();
82 runtime·notesleep(&sig);
83 runtime·exitsyscall();
84 runtime·noteclear(&sig);
David Symondsb5866492009-12-15 18:21:29 -080085 for(;;) {
86 m = sig.mask;
Russ Cox68b42552010-11-04 14:00:19 -040087 if(runtime·cas(&sig.mask, m, 0))
David Symondsb5866492009-12-15 18:21:29 -080088 break;
89 }
90}
91
92func Signame(sig int32) (name String) {
Russ Cox68b42552010-11-04 14:00:19 -040093 name = runtime·signame(sig);
David Symondsb5866492009-12-15 18:21:29 -080094}
Russ Cox08579c22009-12-16 20:20:50 -080095
96func Siginit() {
Russ Cox68b42552010-11-04 14:00:19 -040097 runtime·initsig(SigQueue);
Russ Cox08579c22009-12-16 20:20:50 -080098 sig.inuse = true; // enable reception of signals; cannot disable
99}