github.com/cilium/ebpf@v0.10.0/internal/sys/signals.go (about) 1 package sys 2 3 import ( 4 "fmt" 5 "runtime" 6 "unsafe" 7 8 "github.com/cilium/ebpf/internal/unix" 9 ) 10 11 var profSet unix.Sigset_t 12 13 func init() { 14 if err := sigsetAdd(&profSet, unix.SIGPROF); err != nil { 15 panic(fmt.Errorf("creating signal set: %w", err)) 16 } 17 } 18 19 // maskProfilerSignal locks the calling goroutine to its underlying OS thread 20 // and adds SIGPROF to the thread's signal mask. This prevents pprof from 21 // interrupting expensive syscalls like e.g. BPF_PROG_LOAD. 22 // 23 // The caller must defer sys.UnmaskProfilerSignal() to reverse the operation. 24 func maskProfilerSignal() { 25 runtime.LockOSThread() 26 27 if err := unix.PthreadSigmask(unix.SIG_BLOCK, &profSet, nil); err != nil { 28 runtime.UnlockOSThread() 29 panic(fmt.Errorf("masking profiler signal: %w", err)) 30 } 31 } 32 33 // unmaskProfilerSignal removes SIGPROF from the underlying thread's signal 34 // mask, allowing it to be interrupted for profiling once again. 35 // 36 // It also unlocks the current goroutine from its underlying OS thread. 37 func unmaskProfilerSignal() { 38 defer runtime.UnlockOSThread() 39 40 if err := unix.PthreadSigmask(unix.SIG_UNBLOCK, &profSet, nil); err != nil { 41 panic(fmt.Errorf("unmasking profiler signal: %w", err)) 42 } 43 } 44 45 const ( 46 wordBytes = int(unsafe.Sizeof(unix.Sigset_t{}.Val[0])) 47 wordBits = wordBytes * 8 48 49 setBytes = int(unsafe.Sizeof(unix.Sigset_t{})) 50 setBits = setBytes * 8 51 ) 52 53 // sigsetAdd adds signal to set. 54 // 55 // Note: Sigset_t.Val's value type is uint32 or uint64 depending on the arch. 56 // This function must be able to deal with both and so must avoid any direct 57 // references to u32 or u64 types. 58 func sigsetAdd(set *unix.Sigset_t, signal unix.Signal) error { 59 if signal < 1 { 60 return fmt.Errorf("signal %d must be larger than 0", signal) 61 } 62 if int(signal) > setBits { 63 return fmt.Errorf("signal %d does not fit within unix.Sigset_t", signal) 64 } 65 66 // For amd64, runtime.sigaddset() performs the following operation: 67 // set[(signal-1)/32] |= 1 << ((uint32(signal) - 1) & 31) 68 // 69 // This trick depends on sigset being two u32's, causing a signal in the the 70 // bottom 31 bits to be written to the low word if bit 32 is low, or the high 71 // word if bit 32 is high. 72 73 // Signal is the nth bit in the bitfield. 74 bit := int(signal - 1) 75 // Word within the sigset the bit needs to be written to. 76 word := bit / wordBits 77 78 // Write the signal bit into its corresponding word at the corrected offset. 79 set.Val[word] |= 1 << (bit % wordBits) 80 81 return nil 82 }