summaryrefslogtreecommitdiff
path: root/libgo/go/runtime/cgo_gccgo.go
blob: e4d27e8ab67f888df3ea0db70d5133bc3b7f46f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// 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

		// This is a C-created stack.
		// Record the outermost Go frame to help stack scan.
		gp.entrysp = getcallersp()
	}

	lockOSThread()

	gp.m.incgo = false
	exitsyscall()

	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()

	// We are going to stop running in Go mode and return to C mode.
	// We were almost certainly called by defer; if so, clean up
	// the defer struct now, before we leave Go mode. But don't
	// leave Go mode if we are panicing or called from Goexit,
	// since in those cases we will continue executing deferred functions.
	gp := getg()
	mp := gp.m
	drop := false
	if gp.deferring && gp._panic == nil && !gp.goexiting {
		d := gp._defer
		if d == nil {
			throw("no defer struct when deferring")
		}
		gp._defer = d.link
		freedefer(d)

		// If we are the top level Go function called from C,
		// then we need to release the m.
		if mp.dropextram && mp.ncgo == 0 {
			drop = true
		}
	}

	// Don't go back to C mode if we are panicing. Just let the
	// panic walk up through the Go stack.
	if gp._panic == nil && !gp.goexiting {
		gp.m.incgo = true
		entersyscall()
	}

	if drop {
		mp.dropextram = false
		dropm()
	} else if gp.deferring && gp._panic == nil && !gp.goexiting {
		gp.ranCgocallBackDone = true
	}
}

// _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