Skip to content

Commit ef53de8

Browse files
committed
runtime: wrap darwin libc calls to keep profiler happy
The profiler reports "ExternalCode" when a profiler interrupt happens while in libc code. Instead, keep track of the most recent Go frame for the profiler to use. There is a test for this using time.Now (runtime.TestTimePprof), which will work once time.Now is moved to using libc (my next CL). Change-Id: I940ea83edada482a482e2ab103d3a65589979464 Reviewed-on: https://go-review.googlesource.com/114798 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent db9341a commit ef53de8

File tree

1 file changed

+42
-16
lines changed

1 file changed

+42
-16
lines changed

src/runtime/sys_darwin.go

+42-16
Original file line numberDiff line numberDiff line change
@@ -6,48 +6,74 @@ package runtime
66

77
import "unsafe"
88

9+
// Call fn with arg as its argument. Return what fn returns.
10+
// fn is the raw pc value of the entry point of the desired function.
11+
// Switches to the system stack, if not already there.
12+
// Preserves the calling point as the location where a profiler traceback will begin.
13+
//go:nosplit
14+
func libcCall(fn, arg unsafe.Pointer) int32 {
15+
// Leave caller's PC/SP/G around for traceback.
16+
gp := getg()
17+
var mp *m
18+
if gp != nil {
19+
mp = gp.m
20+
}
21+
if mp != nil {
22+
mp.libcallg.set(gp)
23+
mp.libcallpc = getcallerpc()
24+
// sp must be the last, because once async cpu profiler finds
25+
// all three values to be non-zero, it will use them
26+
mp.libcallsp = getcallersp()
27+
}
28+
res := asmcgocall(fn, arg)
29+
if mp != nil {
30+
mp.libcallsp = 0
31+
}
32+
return res
33+
}
34+
935
// The *_trampoline functions convert from the Go calling convention to the C calling convention
1036
// and then call the underlying libc function. They are defined in sys_darwin_$ARCH.s.
1137

1238
//go:nosplit
1339
//go:cgo_unsafe_args
1440
func pthread_attr_init(attr *pthreadattr) int32 {
15-
return asmcgocall(unsafe.Pointer(funcPC(pthread_attr_init_trampoline)), unsafe.Pointer(&attr))
41+
return libcCall(unsafe.Pointer(funcPC(pthread_attr_init_trampoline)), unsafe.Pointer(&attr))
1642
}
1743
func pthread_attr_init_trampoline()
1844

1945
//go:nosplit
2046
//go:cgo_unsafe_args
2147
func pthread_attr_setstacksize(attr *pthreadattr, size uintptr) int32 {
22-
return asmcgocall(unsafe.Pointer(funcPC(pthread_attr_setstacksize_trampoline)), unsafe.Pointer(&attr))
48+
return libcCall(unsafe.Pointer(funcPC(pthread_attr_setstacksize_trampoline)), unsafe.Pointer(&attr))
2349
}
2450
func pthread_attr_setstacksize_trampoline()
2551

2652
//go:nosplit
2753
//go:cgo_unsafe_args
2854
func pthread_attr_setdetachstate(attr *pthreadattr, state int) int32 {
29-
return asmcgocall(unsafe.Pointer(funcPC(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr))
55+
return libcCall(unsafe.Pointer(funcPC(pthread_attr_setdetachstate_trampoline)), unsafe.Pointer(&attr))
3056
}
3157
func pthread_attr_setdetachstate_trampoline()
3258

3359
//go:nosplit
3460
//go:cgo_unsafe_args
3561
func pthread_create(attr *pthreadattr, start uintptr, arg unsafe.Pointer) int32 {
36-
return asmcgocall(unsafe.Pointer(funcPC(pthread_create_trampoline)), unsafe.Pointer(&attr))
62+
return libcCall(unsafe.Pointer(funcPC(pthread_create_trampoline)), unsafe.Pointer(&attr))
3763
}
3864
func pthread_create_trampoline()
3965

4066
//go:nosplit
4167
//go:cgo_unsafe_args
4268
func raise(sig uint32) {
43-
asmcgocall(unsafe.Pointer(funcPC(raise_trampoline)), unsafe.Pointer(&sig))
69+
libcCall(unsafe.Pointer(funcPC(raise_trampoline)), unsafe.Pointer(&sig))
4470
}
4571
func raise_trampoline()
4672

4773
//go:nosplit
4874
//go:cgo_unsafe_args
4975
func pthread_self() (t pthread) {
50-
asmcgocall(unsafe.Pointer(funcPC(pthread_self_trampoline)), unsafe.Pointer(&t))
76+
libcCall(unsafe.Pointer(funcPC(pthread_self_trampoline)), unsafe.Pointer(&t))
5177
return
5278
}
5379
func pthread_self_trampoline()
@@ -61,64 +87,64 @@ func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (un
6187
ret1 unsafe.Pointer
6288
ret2 int
6389
}{addr, n, prot, flags, fd, off, nil, 0}
64-
asmcgocall(unsafe.Pointer(funcPC(mmap_trampoline)), unsafe.Pointer(&args))
90+
libcCall(unsafe.Pointer(funcPC(mmap_trampoline)), unsafe.Pointer(&args))
6591
return args.ret1, args.ret2
6692
}
6793
func mmap_trampoline()
6894

6995
//go:nosplit
7096
//go:cgo_unsafe_args
7197
func munmap(addr unsafe.Pointer, n uintptr) {
72-
asmcgocall(unsafe.Pointer(funcPC(munmap_trampoline)), unsafe.Pointer(&addr))
98+
libcCall(unsafe.Pointer(funcPC(munmap_trampoline)), unsafe.Pointer(&addr))
7399
}
74100
func munmap_trampoline()
75101

76102
//go:nosplit
77103
//go:cgo_unsafe_args
78104
func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
79-
asmcgocall(unsafe.Pointer(funcPC(madvise_trampoline)), unsafe.Pointer(&addr))
105+
libcCall(unsafe.Pointer(funcPC(madvise_trampoline)), unsafe.Pointer(&addr))
80106
}
81107
func madvise_trampoline()
82108

83109
//go:nosplit
84110
//go:cgo_unsafe_args
85111
func read(fd int32, p unsafe.Pointer, n int32) int32 {
86-
return asmcgocall(unsafe.Pointer(funcPC(read_trampoline)), unsafe.Pointer(&fd))
112+
return libcCall(unsafe.Pointer(funcPC(read_trampoline)), unsafe.Pointer(&fd))
87113
}
88114
func read_trampoline()
89115

90116
//go:nosplit
91117
//go:cgo_unsafe_args
92118
func closefd(fd int32) int32 {
93-
return asmcgocall(unsafe.Pointer(funcPC(close_trampoline)), unsafe.Pointer(&fd))
119+
return libcCall(unsafe.Pointer(funcPC(close_trampoline)), unsafe.Pointer(&fd))
94120
}
95121
func close_trampoline()
96122

97123
//go:nosplit
98124
//go:cgo_unsafe_args
99125
func exit(code int32) {
100-
asmcgocall(unsafe.Pointer(funcPC(exit_trampoline)), unsafe.Pointer(&code))
126+
libcCall(unsafe.Pointer(funcPC(exit_trampoline)), unsafe.Pointer(&code))
101127
}
102128
func exit_trampoline()
103129

104130
//go:nosplit
105131
//go:cgo_unsafe_args
106132
func usleep(usec uint32) {
107-
asmcgocall(unsafe.Pointer(funcPC(usleep_trampoline)), unsafe.Pointer(&usec))
133+
libcCall(unsafe.Pointer(funcPC(usleep_trampoline)), unsafe.Pointer(&usec))
108134
}
109135
func usleep_trampoline()
110136

111137
//go:nosplit
112138
//go:cgo_unsafe_args
113139
func write(fd uintptr, p unsafe.Pointer, n int32) int32 {
114-
return asmcgocall(unsafe.Pointer(funcPC(write_trampoline)), unsafe.Pointer(&fd))
140+
return libcCall(unsafe.Pointer(funcPC(write_trampoline)), unsafe.Pointer(&fd))
115141
}
116142
func write_trampoline()
117143

118144
//go:nosplit
119145
//go:cgo_unsafe_args
120146
func open(name *byte, mode, perm int32) (ret int32) {
121-
return asmcgocall(unsafe.Pointer(funcPC(open_trampoline)), unsafe.Pointer(&name))
147+
return libcCall(unsafe.Pointer(funcPC(open_trampoline)), unsafe.Pointer(&name))
122148
}
123149
func open_trampoline()
124150

@@ -129,7 +155,7 @@ func nanotime() int64 {
129155
t int64 // raw timer
130156
numer, denom uint32 // conversion factors. nanoseconds = t * numer / denom.
131157
}
132-
asmcgocall(unsafe.Pointer(funcPC(nanotime_trampoline)), unsafe.Pointer(&r))
158+
libcCall(unsafe.Pointer(funcPC(nanotime_trampoline)), unsafe.Pointer(&r))
133159
// Note: Apple seems unconcerned about overflow here. See
134160
// https://developer.apple.com/library/content/qa/qa1398/_index.html
135161
// Note also, numer == denom == 1 is common.

0 commit comments

Comments
 (0)