liyujie
2025-08-28 d9927380ed7c8366f762049be9f3fee225860833
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
 
// Support for memory sanitizer. See runtime/cgo/sigaction.go.
 
// +build linux,amd64 freebsd,amd64 linux,arm64
 
package runtime
 
import "unsafe"
 
// _cgo_sigaction is filled in by runtime/cgo when it is linked into the
// program, so it is only non-nil when using cgo.
//go:linkname _cgo_sigaction _cgo_sigaction
var _cgo_sigaction unsafe.Pointer
 
//go:nosplit
//go:nowritebarrierrec
func sigaction(sig uint32, new, old *sigactiont) {
   // The runtime package is explicitly blacklisted from sanitizer
   // instrumentation in racewalk.go, but we might be calling into instrumented C
   // functions here — so we need the pointer parameters to be properly marked.
   //
   // Mark the input as having been written before the call and the output as
   // read after.
   if msanenabled && new != nil {
       msanwrite(unsafe.Pointer(new), unsafe.Sizeof(*new))
   }
 
   if _cgo_sigaction == nil || inForkedChild {
       sysSigaction(sig, new, old)
   } else {
       // We need to call _cgo_sigaction, which means we need a big enough stack
       // for C.  To complicate matters, we may be in libpreinit (before the
       // runtime has been initialized) or in an asynchronous signal handler (with
       // the current thread in transition between goroutines, or with the g0
       // system stack already in use).
 
       var ret int32
 
       g := getg()
       sp := uintptr(unsafe.Pointer(&sig))
       switch {
       case g == nil:
           // No g: we're on a C stack or a signal stack.
           ret = callCgoSigaction(uintptr(sig), new, old)
       case sp < g.stack.lo || sp >= g.stack.hi:
           // We're no longer on g's stack, so we must be handling a signal.  It's
           // possible that we interrupted the thread during a transition between g
           // and g0, so we should stay on the current stack to avoid corrupting g0.
           ret = callCgoSigaction(uintptr(sig), new, old)
       default:
           // We're running on g's stack, so either we're not in a signal handler or
           // the signal handler has set the correct g.  If we're on gsignal or g0,
           // systemstack will make the call directly; otherwise, it will switch to
           // g0 to ensure we have enough room to call a libc function.
           //
           // The function literal that we pass to systemstack is not nosplit, but
           // that's ok: we'll be running on a fresh, clean system stack so the stack
           // check will always succeed anyway.
           systemstack(func() {
               ret = callCgoSigaction(uintptr(sig), new, old)
           })
       }
 
       const EINVAL = 22
       if ret == EINVAL {
           // libc reserves certain signals — normally 32-33 — for pthreads, and
           // returns EINVAL for sigaction calls on those signals.  If we get EINVAL,
           // fall back to making the syscall directly.
           sysSigaction(sig, new, old)
       }
   }
 
   if msanenabled && old != nil {
       msanread(unsafe.Pointer(old), unsafe.Sizeof(*old))
   }
}
 
// callCgoSigaction calls the sigaction function in the runtime/cgo package
// using the GCC calling convention. It is implemented in assembly.
//go:noescape
func callCgoSigaction(sig uintptr, new, old *sigactiont) int32