Source file src/runtime/sys_libc.go
1 // Copyright 2018 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 //go:build darwin || (openbsd && !mips64) 6 7 package runtime 8 9 import "unsafe" 10 11 // Call fn with arg as its argument. Return what fn returns. 12 // fn is the raw pc value of the entry point of the desired function. 13 // Switches to the system stack, if not already there. 14 // Preserves the calling point as the location where a profiler traceback will begin. 15 //go:nosplit 16 func libcCall(fn, arg unsafe.Pointer) int32 { 17 // Leave caller's PC/SP/G around for traceback. 18 gp := getg() 19 var mp *m 20 if gp != nil { 21 mp = gp.m 22 } 23 if mp != nil && mp.libcallsp == 0 { 24 mp.libcallg.set(gp) 25 mp.libcallpc = getcallerpc() 26 // sp must be the last, because once async cpu profiler finds 27 // all three values to be non-zero, it will use them 28 mp.libcallsp = getcallersp() 29 } else { 30 // Make sure we don't reset libcallsp. This makes 31 // libcCall reentrant; We remember the g/pc/sp for the 32 // first call on an M, until that libcCall instance 33 // returns. Reentrance only matters for signals, as 34 // libc never calls back into Go. The tricky case is 35 // where we call libcX from an M and record g/pc/sp. 36 // Before that call returns, a signal arrives on the 37 // same M and the signal handling code calls another 38 // libc function. We don't want that second libcCall 39 // from within the handler to be recorded, and we 40 // don't want that call's completion to zero 41 // libcallsp. 42 // We don't need to set libcall* while we're in a sighandler 43 // (even if we're not currently in libc) because we block all 44 // signals while we're handling a signal. That includes the 45 // profile signal, which is the one that uses the libcall* info. 46 mp = nil 47 } 48 res := asmcgocall(fn, arg) 49 if mp != nil { 50 mp.libcallsp = 0 51 } 52 return res 53 } 54