~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to src/pkg/runtime/sigqueue.goc

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
// This file implements runtime support for signal handling.
6
6
//
7
7
// Most synchronization primitives are not available from
8
 
// the signal handler (it cannot block and cannot use locks)
 
8
// the signal handler (it cannot block, allocate memory, or use locks)
9
9
// so the handler communicates with a processing goroutine
10
10
// via struct sig, below.
11
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 signal_enable).
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.
 
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.
38
26
 
39
27
package runtime
40
28
#include "runtime.h"
45
33
        Note;
46
34
        uint32 mask[(NSIG+31)/32];
47
35
        uint32 wanted[(NSIG+31)/32];
48
 
        uint32 kick;
 
36
        uint32 state;
49
37
        bool inuse;
50
38
} sig;
51
39
 
 
40
enum {
 
41
        HASWAITER = 1,
 
42
        HASSIGNAL = 2,
 
43
};
 
44
 
52
45
// Called from sighandler to send a signal back out of the signal handling thread.
53
46
bool
54
47
runtime·sigsend(int32 s)
55
48
{
56
 
        uint32 bit, mask;
 
49
        uint32 bit, mask, old, new;
57
50
 
58
51
        if(!sig.inuse || s < 0 || s >= 32*nelem(sig.wanted) || !(sig.wanted[s/32]&(1U<<(s&31))))
59
52
                return false;
65
58
                if(runtime·cas(&sig.mask[s/32], mask, mask|bit)) {
66
59
                        // Added to queue.
67
60
                        // Only send a wakeup if the receiver needs a kick.
68
 
                        if(runtime·cas(&sig.kick, 1, 0))
69
 
                                runtime·notewakeup(&sig);
 
61
                        for(;;) {
 
62
                                old = runtime·atomicload(&sig.state);
 
63
                                if(old == HASSIGNAL)
 
64
                                        break;
 
65
                                if(old == HASWAITER)
 
66
                                        new = 0;
 
67
                                else  // if(old == 0)
 
68
                                        new = HASSIGNAL;
 
69
                                if(runtime·cas(&sig.state, old, new)) {
 
70
                                        if (old == HASWAITER)
 
71
                                                runtime·notewakeup(&sig);
 
72
                                        break;
 
73
                                }
 
74
                        }
70
75
                        break;
71
76
                }
72
77
        }
77
82
// Must only be called from a single goroutine at a time.
78
83
func signal_recv() (m uint32) {
79
84
        static uint32 recv[nelem(sig.mask)];
80
 
        int32 i, more;
 
85
        uint32 i, old, new;
81
86
        
82
87
        for(;;) {
83
88
                // Serve from local copy if there are bits left.
89
94
                        }
90
95
                }
91
96
 
 
97
                // Check and update sig.state.
 
98
                for(;;) {
 
99
                        old = runtime·atomicload(&sig.state);
 
100
                        if(old == HASWAITER)
 
101
                                runtime·throw("inconsistent state in signal_recv");
 
102
                        if(old == HASSIGNAL)
 
103
                                new = 0;
 
104
                        else  // if(old == 0)
 
105
                                new = HASWAITER;
 
106
                        if(runtime·cas(&sig.state, old, new)) {
 
107
                                if (new == HASWAITER) {
 
108
                                        runtime·entersyscallblock();
 
109
                                        runtime·notesleep(&sig);
 
110
                                        runtime·exitsyscall();
 
111
                                        runtime·noteclear(&sig);
 
112
                                }
 
113
                                break;
 
114
                        }
 
115
                }
 
116
 
92
117
                // Get a new local copy.
93
 
                // Ask for a kick if more signals come in
94
 
                // during or after our check (before the sleep).
95
 
                if(sig.kick == 0) {
96
 
                        runtime·noteclear(&sig);
97
 
                        runtime·cas(&sig.kick, 0, 1);
98
 
                }
99
 
 
100
 
                more = 0;
101
118
                for(i=0; i<nelem(sig.mask); i++) {
102
119
                        for(;;) {
103
120
                                m = sig.mask[i];
105
122
                                        break;
106
123
                        }
107
124
                        recv[i] = m;
108
 
                        if(m != 0)
109
 
                                more = 1;
110
125
                }
111
 
                if(more)
112
 
                        continue;
113
 
 
114
 
                // Sleep waiting for more.
115
 
                runtime·entersyscall();
116
 
                runtime·notesleep(&sig);
117
 
                runtime·exitsyscall();
118
126
        }
119
127
 
120
128
done:;
125
133
 
126
134
// Must only be called from a single goroutine at a time.
127
135
func signal_enable(s uint32) {
128
 
        int32 i;
129
 
 
130
136
        if(!sig.inuse) {
131
137
                // The first call to signal_enable is for us
132
138
                // to use for initialization.  It does not pass
136
142
                return;
137
143
        }
138
144
        
139
 
        if(~s == 0) {
140
 
                // Special case: want everything.
141
 
                for(i=0; i<nelem(sig.wanted); i++)
142
 
                        sig.wanted[i] = ~(uint32)0;
143
 
                runtime·sigenable(s);
144
 
                return;
145
 
        }
146
 
 
147
145
        if(s >= nelem(sig.wanted)*32)
148
146
                return;
149
147
        sig.wanted[s/32] |= 1U<<(s&31);
150
148
        runtime·sigenable(s);
151
149
}
 
150
 
 
151
// Must only be called from a single goroutine at a time.
 
152
func 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
}