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 }