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

View as plain text