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