github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/sigqueue.goc (about)

     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, allocate memory, or use locks)
     9  // so the handler communicates with a processing goroutine
    10  // via struct sig, below.
    11  //
    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.
    26  
    27  package runtime
    28  #include "runtime.h"
    29  #include "defs_GOOS_GOARCH.h"
    30  #include "os_GOOS.h"
    31  
    32  static struct {
    33  	Note;
    34  	uint32 mask[(NSIG+31)/32];
    35  	uint32 wanted[(NSIG+31)/32];
    36  	uint32 state;
    37  	bool inuse;
    38  } sig;
    39  
    40  enum {
    41  	HASWAITER = 1,
    42  	HASSIGNAL = 2,
    43  };
    44  
    45  // Called from sighandler to send a signal back out of the signal handling thread.
    46  bool
    47  runtime·sigsend(int32 s)
    48  {
    49  	uint32 bit, mask, old, new;
    50  
    51  	if(!sig.inuse || s < 0 || s >= 32*nelem(sig.wanted) || !(sig.wanted[s/32]&(1U<<(s&31))))
    52  		return false;
    53  	bit = 1 << (s&31);
    54  	for(;;) {
    55  		mask = sig.mask[s/32];
    56  		if(mask & bit)
    57  			break;		// signal already in queue
    58  		if(runtime·cas(&sig.mask[s/32], mask, mask|bit)) {
    59  			// Added to queue.
    60  			// Only send a wakeup if the receiver needs a kick.
    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  			}
    75  			break;
    76  		}
    77  	}
    78  	return true;
    79  }
    80  
    81  // Called to receive the next queued signal.
    82  // Must only be called from a single goroutine at a time.
    83  func signal_recv() (m uint32) {
    84  	static uint32 recv[nelem(sig.mask)];
    85  	uint32 i, old, new;
    86  	
    87  	for(;;) {
    88  		// Serve from local copy if there are bits left.
    89  		for(i=0; i<NSIG; i++) {
    90  			if(recv[i/32]&(1U<<(i&31))) {
    91  				recv[i/32] ^= 1U<<(i&31);
    92  				m = i;
    93  				goto done;
    94  			}
    95  		}
    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  
   117  		// Get a new local copy.
   118  		for(i=0; i<nelem(sig.mask); i++) {
   119  			for(;;) {
   120  				m = sig.mask[i];
   121  				if(runtime·cas(&sig.mask[i], m, 0))
   122  					break;
   123  			}
   124  			recv[i] = m;
   125  		}
   126  	}
   127  
   128  done:;
   129  	// goc requires that we fall off the end of functions
   130  	// that return values instead of using our own return
   131  	// statements.
   132  }
   133  
   134  // Must only be called from a single goroutine at a time.
   135  func signal_enable(s uint32) {
   136  	if(!sig.inuse) {
   137  		// The first call to signal_enable is for us
   138  		// to use for initialization.  It does not pass
   139  		// signal information in m.
   140  		sig.inuse = true;	// enable reception of signals; cannot disable
   141  		runtime·noteclear(&sig);
   142  		return;
   143  	}
   144  	
   145  	if(s >= nelem(sig.wanted)*32)
   146  		return;
   147  	sig.wanted[s/32] |= 1U<<(s&31);
   148  	runtime·sigenable(s);
   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  }