1// Copyright 2016 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 5package runtime 6 7import ( 8 "runtime/internal/atomic" 9 "unsafe" 10) 11 12// For historical reasons these functions are called as though they 13// were in the syscall package. 14//go:linkname Cgocall syscall.Cgocall 15//go:linkname CgocallDone syscall.CgocallDone 16//go:linkname CgocallBack syscall.CgocallBack 17//go:linkname CgocallBackDone syscall.CgocallBackDone 18 19// A routine that may be called by SWIG. 20//go:linkname _cgo_panic _cgo_panic 21 22// iscgo is set to true if the cgo tool sets the C variable runtime_iscgo 23// to true. 24var iscgo bool 25 26// cgoHasExtraM is set on startup when an extra M is created for cgo. 27// The extra M must be created before any C/C++ code calls cgocallback. 28var cgoHasExtraM bool 29 30// cgoAlwaysFalse is a boolean value that is always false. 31// The cgo-generated code says if cgoAlwaysFalse { cgoUse(p) }. 32// The compiler cannot see that cgoAlwaysFalse is always false, 33// so it emits the test and keeps the call, giving the desired 34// escape analysis result. The test is cheaper than the call. 35var cgoAlwaysFalse bool 36 37// Cgocall prepares to call from code written in Go to code written in 38// C/C++. This takes the current goroutine out of the Go scheduler, as 39// though it were making a system call. Otherwise the program can 40// lookup if the C code blocks. The idea is to call this function, 41// then immediately call the C/C++ function. After the C/C++ function 42// returns, call cgocalldone. The usual Go code would look like 43// syscall.Cgocall() 44// defer syscall.Cgocalldone() 45// cfunction() 46func Cgocall() { 47 mp := getg().m 48 mp.ncgocall++ 49 mp.ncgo++ 50 entersyscall() 51 mp.incgo = true 52} 53 54// CgocallDone prepares to return to Go code from C/C++ code. 55func CgocallDone() { 56 gp := getg() 57 if gp == nil { 58 throw("no g in CgocallDone") 59 } 60 gp.m.incgo = false 61 gp.m.ncgo-- 62 63 // If we are invoked because the C function called _cgo_panic, 64 // then _cgo_panic will already have exited syscall mode. 65 if readgstatus(gp)&^_Gscan == _Gsyscall { 66 exitsyscall() 67 } 68} 69 70// CgocallBack is used when calling from C/C++ code into Go code. 71// The usual approach is 72// syscall.CgocallBack() 73// defer syscall.CgocallBackDone() 74// gofunction() 75//go:nosplit 76func CgocallBack() { 77 gp := getg() 78 if gp == nil || gp.m == nil { 79 needm(0) 80 gp = getg() 81 mp := gp.m 82 mp.dropextram = true 83 84 // This is a C-created stack. 85 // Record the outermost Go frame to help stack scan. 86 gp.entrysp = getcallersp() 87 } 88 89 lockOSThread() 90 91 gp.m.incgo = false 92 exitsyscall() 93 94 if gp.m.ncgo == 0 { 95 // The C call to Go came from a thread created by C. 96 // The C call to Go came from a thread not currently running 97 // any Go. In the case of -buildmode=c-archive or c-shared, 98 // this call may be coming in before package initialization 99 // is complete. Wait until it is. 100 <-main_init_done 101 } 102 103 mp := gp.m 104 if mp.needextram || atomic.Load(&extraMWaiters) > 0 { 105 mp.needextram = false 106 newextram() 107 } 108} 109 110// CgocallBackDone prepares to return to C/C++ code that has called 111// into Go code. 112func CgocallBackDone() { 113 unlockOSThread() 114 115 // We are going to stop running in Go mode and return to C mode. 116 // We were almost certainly called by defer; if so, clean up 117 // the defer struct now, before we leave Go mode. But don't 118 // leave Go mode if we are panicing or called from Goexit, 119 // since in those cases we will continue executing deferred functions. 120 gp := getg() 121 mp := gp.m 122 drop := false 123 if gp.deferring && gp._panic == nil && !gp.goexiting { 124 d := gp._defer 125 if d == nil { 126 throw("no defer struct when deferring") 127 } 128 gp._defer = d.link 129 freedefer(d) 130 131 // If we are the top level Go function called from C, 132 // then we need to release the m. 133 if mp.dropextram && mp.ncgo == 0 { 134 drop = true 135 } 136 } 137 138 // Don't go back to C mode if we are panicing. Just let the 139 // panic walk up through the Go stack. 140 if gp._panic == nil && !gp.goexiting { 141 gp.m.incgo = true 142 entersyscall() 143 } 144 145 if drop { 146 mp.dropextram = false 147 dropm() 148 } else if gp.deferring && gp._panic == nil && !gp.goexiting { 149 gp.ranCgocallBackDone = true 150 } 151} 152 153// _cgo_panic may be called by SWIG code to panic. 154func _cgo_panic(p *byte) { 155 exitsyscall() 156 panic(gostringnocopy(p)) 157} 158 159// cgo_yield exists in the gc toolchain to let TSAN deliver a signal. 160// gccgo does not need this. 161var cgo_yield = &_cgo_yield 162var _cgo_yield unsafe.Pointer 163