github.com/akaros/go-akaros@v0.0.0-20181004170632-85005d477eab/src/runtime/parlib/signal.go (about)

     1  // Copyright 2013 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  // +build akaros
     6  
     7  package parlib
     8  
     9  /*
    10  #include <stdlib.h>
    11  #include <stdint.h>
    12  #include <stdio.h>
    13  #include <futex.h>
    14  #include <limits.h>
    15  #include <signal.h>
    16  #include <pthread.h>
    17  
    18  uint64_t __sigmap = 0;
    19  int __sigpending = 0;
    20  uint64_t wtf = 0;
    21  
    22  // must match the one in gcc_akaros.h
    23  typedef void (*__sigaction_t) (int, siginfo_t *, void *);
    24  
    25  // TODO(wheatman) There might be a bug here in that if we are not
    26  // in vcore context we can never call an updated signal handler.
    27  // I can't trigger it, but it looks posible
    28  void sig_hand(int signr, void *info, void *ctxt) {
    29          if (in_vcore_context()) {
    30            __sigmap |= ((uint64_t)(1)) << (signr-1);
    31            __sigpending = 1;
    32            futex(&__sigpending, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
    33          } else {
    34            ((__sigaction_t)wtf)(signr, info, ctxt);
    35  
    36          }
    37  
    38  }
    39  
    40  void pthread_wake(int signr) {
    41          pthread_kill(pthread_self(), signr);
    42          pthread_yield();
    43  }
    44  */
    45  import "C"
    46  import (
    47  	"unsafe"
    48  )
    49  
    50  var (
    51  	__SIG_ERR = -1
    52  	__SIG_IGN = 1
    53  	__SIG_DFL = 0
    54  	SIG_ERR   = *((*C.__sigaction_t)(unsafe.Pointer(&__SIG_ERR)))
    55  	SIG_IGN   = *((*C.__sigaction_t)(unsafe.Pointer(&__SIG_IGN)))
    56  	SIG_DFL   = *((*C.__sigaction_t)(unsafe.Pointer(&__SIG_DFL)))
    57  )
    58  
    59  const (
    60  	NSIG = C._NSIG
    61  )
    62  
    63  type SignalHandler func(sig int)
    64  
    65  var sighandlers [NSIG - 1]SignalHandler
    66  var sigact = SigactionT{Sigact: (C.__sigaction_t)(C.sig_hand), Flags: C.SA_SIGINFO}
    67  
    68  // Implemented in runtime/sys_{GOOS}_{GOARCH}.s
    69  func defaultSighandler(sig int)
    70  
    71  const ptrSize = 4 << (^uintptr(0) >> 63)
    72  
    73  //go:nosplit
    74  func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
    75  	return unsafe.Pointer(uintptr(p) + x)
    76  }
    77  
    78  //go:nosplit
    79  func get_value(f interface{}) uint64 {
    80  	return uint64(**(**uintptr)(unsafe.Pointer((add(unsafe.Pointer(&f), ptrSize)))))
    81  }
    82  
    83  func init() {
    84  	for i := 0; i < (NSIG - 1); i++ {
    85  		Signal(i, defaultSighandler)
    86  	}
    87  	C.wtf = C.uint64_t(get_value(defaultSighandler))
    88  	go process_signals()
    89  }
    90  
    91  func process_signals() {
    92  	for {
    93  		Futex((*int32)(&C.__sigpending), FUTEX_WAIT, 0, nil, nil, 0)
    94  		C.__sigpending = 0
    95  		sigmap := C.__sigmap
    96  		C.__sigmap &^= sigmap
    97  
    98  		signr := 0
    99  		for sigmap != 0 {
   100  			for {
   101  				bit := sigmap & 1
   102  				sigmap >>= 1
   103  				signr++
   104  				if bit == 1 {
   105  					break
   106  				}
   107  			}
   108  			// if somebody has updated the signal handler call the new one
   109  			// else convert to internal signal and loop back around
   110  			if get_value(sighandlers[signr-1]) == get_value(defaultSighandler) {
   111  				C.pthread_wake(C.int(signr))
   112  			} else {
   113  				sighandlers[signr-1](signr)
   114  			}
   115  		}
   116  	}
   117  }
   118  
   119  func Signal(signr int, newh SignalHandler) (SignalHandler, int) {
   120  	if signr < 1 || signr >= NSIG {
   121  		return nil, -1
   122  	}
   123  
   124  	oldh := sighandlers[signr-1]
   125  	sighandlers[signr-1] = newh
   126  
   127  	__sigact := sigact
   128  	if newh == nil {
   129  		__sigact.Sigact = SIG_DFL
   130  	}
   131  	ret := int(C.sigaction(C.int(signr), (*C.struct_sigaction)(unsafe.Pointer(&__sigact)), nil))
   132  	if ret != 0 {
   133  		return nil, ret
   134  	}
   135  	return oldh, ret
   136  }