David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 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 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 | |
| 39 | package runtime |
| 40 | #include "runtime.h" |
| 41 | #include "defs.h" |
| 42 | |
| 43 | static struct { |
| 44 | Note; |
| 45 | uint32 mask; |
Russ Cox | 08579c2 | 2009-12-16 20:20:50 -0800 | [diff] [blame] | 46 | bool inuse; |
David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 47 | } sig; |
| 48 | |
| 49 | void |
Russ Cox | 68b4255 | 2010-11-04 14:00:19 -0400 | [diff] [blame] | 50 | runtime·siginit(void) |
David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 51 | { |
Russ Cox | 68b4255 | 2010-11-04 14:00:19 -0400 | [diff] [blame] | 52 | runtime·noteclear(&sig); |
David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 53 | } |
| 54 | |
| 55 | // Called from sighandler to send a signal back out of the signal handling thread. |
Russ Cox | 08579c2 | 2009-12-16 20:20:50 -0800 | [diff] [blame] | 56 | bool |
Russ Cox | 68b4255 | 2010-11-04 14:00:19 -0400 | [diff] [blame] | 57 | runtime·sigsend(int32 s) |
David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 58 | { |
| 59 | uint32 bit, mask; |
| 60 | |
Russ Cox | 08579c2 | 2009-12-16 20:20:50 -0800 | [diff] [blame] | 61 | if(!sig.inuse) |
| 62 | return false; |
David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 63 | bit = 1 << s; |
| 64 | for(;;) { |
| 65 | mask = sig.mask; |
| 66 | if(mask & bit) |
Russ Cox | 08579c2 | 2009-12-16 20:20:50 -0800 | [diff] [blame] | 67 | break; // signal already in queue |
Russ Cox | 68b4255 | 2010-11-04 14:00:19 -0400 | [diff] [blame] | 68 | if(runtime·cas(&sig.mask, mask, mask|bit)) { |
David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 69 | // Added to queue. |
| 70 | // Only send a wakeup for the first signal in each round. |
| 71 | if(mask == 0) |
Russ Cox | 68b4255 | 2010-11-04 14:00:19 -0400 | [diff] [blame] | 72 | runtime·notewakeup(&sig); |
Russ Cox | 08579c2 | 2009-12-16 20:20:50 -0800 | [diff] [blame] | 73 | break; |
David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 74 | } |
| 75 | } |
Russ Cox | 08579c2 | 2009-12-16 20:20:50 -0800 | [diff] [blame] | 76 | return true; |
David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 77 | } |
| 78 | |
| 79 | // Called to receive a bitmask of queued signals. |
| 80 | func Sigrecv() (m uint32) { |
Russ Cox | 68b4255 | 2010-11-04 14:00:19 -0400 | [diff] [blame] | 81 | runtime·entersyscall(); |
| 82 | runtime·notesleep(&sig); |
| 83 | runtime·exitsyscall(); |
| 84 | runtime·noteclear(&sig); |
David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 85 | for(;;) { |
| 86 | m = sig.mask; |
Russ Cox | 68b4255 | 2010-11-04 14:00:19 -0400 | [diff] [blame] | 87 | if(runtime·cas(&sig.mask, m, 0)) |
David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 88 | break; |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | func Signame(sig int32) (name String) { |
Russ Cox | 68b4255 | 2010-11-04 14:00:19 -0400 | [diff] [blame] | 93 | name = runtime·signame(sig); |
David Symonds | b586649 | 2009-12-15 18:21:29 -0800 | [diff] [blame] | 94 | } |
Russ Cox | 08579c2 | 2009-12-16 20:20:50 -0800 | [diff] [blame] | 95 | |
| 96 | func Siginit() { |
Russ Cox | 68b4255 | 2010-11-04 14:00:19 -0400 | [diff] [blame] | 97 | runtime·initsig(SigQueue); |
Russ Cox | 08579c2 | 2009-12-16 20:20:50 -0800 | [diff] [blame] | 98 | sig.inuse = true; // enable reception of signals; cannot disable |
| 99 | } |