github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/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  #include "cgocall.h"
    32  #include "../../cmd/ld/textflag.h"
    33  
    34  static struct {
    35  	Note;
    36  	uint32 mask[(NSIG+31)/32];
    37  	uint32 wanted[(NSIG+31)/32];
    38  	uint32 state;
    39  	bool inuse;
    40  } sig;
    41  
    42  enum {
    43  	HASWAITER = 1,
    44  	HASSIGNAL = 2,
    45  };
    46  
    47  // Called from sighandler to send a signal back out of the signal handling thread.
    48  bool
    49  runtime·sigsend(int32 s)
    50  {
    51  	uint32 bit, mask, old, new;
    52  
    53  	if(!sig.inuse || s < 0 || s >= 32*nelem(sig.wanted) || !(sig.wanted[s/32]&(1U<<(s&31))))
    54  		return false;
    55  	bit = 1 << (s&31);
    56  	for(;;) {
    57  		mask = sig.mask[s/32];
    58  		if(mask & bit)
    59  			break;		// signal already in queue
    60  		if(runtime·cas(&sig.mask[s/32], mask, mask|bit)) {
    61  			// Added to queue.
    62  			// Only send a wakeup if the receiver needs a kick.
    63  			for(;;) {
    64  				old = runtime·atomicload(&sig.state);
    65  				if(old == HASSIGNAL)
    66  					break;
    67  				if(old == HASWAITER)
    68  					new = 0;
    69  				else  // if(old == 0)
    70  					new = HASSIGNAL;
    71  				if(runtime·cas(&sig.state, old, new)) {
    72  					if (old == HASWAITER)
    73  						runtime·notewakeup(&sig);
    74  					break;
    75  				}
    76  			}
    77  			break;
    78  		}
    79  	}
    80  	return true;
    81  }
    82  
    83  // Called to receive the next queued signal.
    84  // Must only be called from a single goroutine at a time.
    85  func signal_recv() (m uint32) {
    86  	static uint32 recv[nelem(sig.mask)];
    87  	uint32 i, old, new;
    88  	
    89  	for(;;) {
    90  		// Serve from local copy if there are bits left.
    91  		for(i=0; i<NSIG; i++) {
    92  			if(recv[i/32]&(1U<<(i&31))) {
    93  				recv[i/32] ^= 1U<<(i&31);
    94  				m = i;
    95  				goto done;
    96  			}
    97  		}
    98  
    99  		// Check and update sig.state.
   100  		for(;;) {
   101  			old = runtime·atomicload(&sig.state);
   102  			if(old == HASWAITER)
   103  				runtime·throw("inconsistent state in signal_recv");
   104  			if(old == HASSIGNAL)
   105  				new = 0;
   106  			else  // if(old == 0)
   107  				new = HASWAITER;
   108  			if(runtime·cas(&sig.state, old, new)) {
   109  				if (new == HASWAITER) {
   110  					runtime·notetsleepg(&sig, -1);
   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  }
   158  
   159  // This runs on a foreign stack, without an m or a g.  No stack split.
   160  #pragma textflag NOSPLIT
   161  void
   162  runtime·badsignal(uintptr sig)
   163  {
   164  	runtime·cgocallback((void (*)(void))runtime·sigsend, &sig, sizeof(sig));
   165  }