blob: e689b0e26169b1876d4149843ca8853855d2b6b3 [file] [log] [blame]
// 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.
package runtime
import (
"runtime/internal/atomic"
"unsafe"
)
// For historical reasons these functions are called as though they
// were in the syscall package.
//go:linkname Cgocall syscall.Cgocall
//go:linkname CgocallDone syscall.CgocallDone
//go:linkname CgocallBack syscall.CgocallBack
//go:linkname CgocallBackDone syscall.CgocallBackDone
// A routine that may be called by SWIG.
//go:linkname _cgo_panic _cgo_panic
// iscgo is set to true if the cgo tool sets the C variable runtime_iscgo
// to true.
var iscgo bool
// cgoHasExtraM is set on startup when an extra M is created for cgo.
// The extra M must be created before any C/C++ code calls cgocallback.
var cgoHasExtraM bool
// cgoAlwaysFalse is a boolean value that is always false.
// The cgo-generated code says if cgoAlwaysFalse { cgoUse(p) }.
// The compiler cannot see that cgoAlwaysFalse is always false,
// so it emits the test and keeps the call, giving the desired
// escape analysis result. The test is cheaper than the call.
var cgoAlwaysFalse bool
// Cgocall prepares to call from code written in Go to code written in
// C/C++. This takes the current goroutine out of the Go scheduler, as
// though it were making a system call. Otherwise the program can
// lookup if the C code blocks. The idea is to call this function,
// then immediately call the C/C++ function. After the C/C++ function
// returns, call cgocalldone. The usual Go code would look like
// syscall.Cgocall()
// defer syscall.Cgocalldone()
// cfunction()
func Cgocall() {
mp := getg().m
mp.ncgocall++
mp.ncgo++
entersyscall()
mp.incgo = true
}
// CgocallDone prepares to return to Go code from C/C++ code.
func CgocallDone() {
gp := getg()
if gp == nil {
throw("no g in CgocallDone")
}
gp.m.incgo = false
gp.m.ncgo--
// If we are invoked because the C function called _cgo_panic,
// then _cgo_panic will already have exited syscall mode.
if readgstatus(gp)&^_Gscan == _Gsyscall {
exitsyscall()
}
}
// CgocallBack is used when calling from C/C++ code into Go code.
// The usual approach is
// syscall.CgocallBack()
// defer syscall.CgocallBackDone()
// gofunction()
//go:nosplit
func CgocallBack() {
gp := getg()
if gp == nil || gp.m == nil {
needm(0)
gp = getg()
mp := gp.m
mp.dropextram = true
}
lockOSThread()
exitsyscall()
gp.m.incgo = false
if gp.m.ncgo == 0 {
// The C call to Go came from a thread created by C.
// The C call to Go came from a thread not currently running
// any Go. In the case of -buildmode=c-archive or c-shared,
// this call may be coming in before package initialization
// is complete. Wait until it is.
<-main_init_done
}
mp := gp.m
if mp.needextram || atomic.Load(&extraMWaiters) > 0 {
mp.needextram = false
newextram()
}
}
// CgocallBackDone prepares to return to C/C++ code that has called
// into Go code.
func CgocallBackDone() {
unlockOSThread()
// If we are the top level Go function called from C/C++, then
// we need to release the m. But don't release it if we are
// panicing; since this is the top level, we are going to
// crash the program, and we need the g and m to print the
// panic values.
//
// Dropping the m is going to clear g. This function is being
// called as a deferred function, so we will return to
// deferreturn which will want to clear the _defer field.
// As soon as we call dropm another thread may call needm and
// start using g, so we must not tamper with the _defer field
// after dropm. So clear _defer now.
gp := getg()
mp := gp.m
drop := false
if mp.dropextram && mp.ncgo == 0 && gp._panic == nil {
d := gp._defer
if d == nil || d.link != nil {
throw("unexpected g._defer in CgocallBackDone")
}
gp._defer = nil
freedefer(d)
drop = true
}
gp.m.incgo = true
entersyscall()
if drop {
mp.dropextram = false
dropm()
}
}
// _cgo_panic may be called by SWIG code to panic.
func _cgo_panic(p *byte) {
exitsyscall()
panic(gostringnocopy(p))
}
// cgo_yield exists in the gc toolchain to let TSAN deliver a signal.
// gccgo does not need this.
var cgo_yield = &_cgo_yield
var _cgo_yield unsafe.Pointer