github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/runtime/cgocall.go (about) 1 // Copyright 2009 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 // Cgo call and callback support. 6 // 7 // To call into the C function f from Go, the cgo-generated code calls 8 // runtime.cgocall(_cgo_Cfunc_f, frame), where _cgo_Cfunc_f is a 9 // gcc-compiled function written by cgo. 10 // 11 // runtime.cgocall (below) locks g to m, calls entersyscall 12 // so as not to block other goroutines or the garbage collector, 13 // and then calls runtime.asmcgocall(_cgo_Cfunc_f, frame). 14 // 15 // runtime.asmcgocall (in asm_$GOARCH.s) switches to the m->g0 stack 16 // (assumed to be an operating system-allocated stack, so safe to run 17 // gcc-compiled code on) and calls _cgo_Cfunc_f(frame). 18 // 19 // _cgo_Cfunc_f invokes the actual C function f with arguments 20 // taken from the frame structure, records the results in the frame, 21 // and returns to runtime.asmcgocall. 22 // 23 // After it regains control, runtime.asmcgocall switches back to the 24 // original g (m->curg)'s stack and returns to runtime.cgocall. 25 // 26 // After it regains control, runtime.cgocall calls exitsyscall, which blocks 27 // until this m can run Go code without violating the $GOMAXPROCS limit, 28 // and then unlocks g from m. 29 // 30 // The above description skipped over the possibility of the gcc-compiled 31 // function f calling back into Go. If that happens, we continue down 32 // the rabbit hole during the execution of f. 33 // 34 // To make it possible for gcc-compiled C code to call a Go function p.GoF, 35 // cgo writes a gcc-compiled function named GoF (not p.GoF, since gcc doesn't 36 // know about packages). The gcc-compiled C function f calls GoF. 37 // 38 // GoF calls crosscall2(_cgoexp_GoF, frame, framesize). Crosscall2 39 // (in cgo/gcc_$GOARCH.S, a gcc-compiled assembly file) is a two-argument 40 // adapter from the gcc function call ABI to the 6c function call ABI. 41 // It is called from gcc to call 6c functions. In this case it calls 42 // _cgoexp_GoF(frame, framesize), still running on m->g0's stack 43 // and outside the $GOMAXPROCS limit. Thus, this code cannot yet 44 // call arbitrary Go code directly and must be careful not to allocate 45 // memory or use up m->g0's stack. 46 // 47 // _cgoexp_GoF calls runtime.cgocallback(p.GoF, frame, framesize). 48 // (The reason for having _cgoexp_GoF instead of writing a crosscall3 49 // to make this call directly is that _cgoexp_GoF, because it is compiled 50 // with 6c instead of gcc, can refer to dotted names like 51 // runtime.cgocallback and p.GoF.) 52 // 53 // runtime.cgocallback (in asm_$GOARCH.s) switches from m->g0's 54 // stack to the original g (m->curg)'s stack, on which it calls 55 // runtime.cgocallbackg(p.GoF, frame, framesize). 56 // As part of the stack switch, runtime.cgocallback saves the current 57 // SP as m->g0->sched.sp, so that any use of m->g0's stack during the 58 // execution of the callback will be done below the existing stack frames. 59 // Before overwriting m->g0->sched.sp, it pushes the old value on the 60 // m->g0 stack, so that it can be restored later. 61 // 62 // runtime.cgocallbackg (below) is now running on a real goroutine 63 // stack (not an m->g0 stack). First it calls runtime.exitsyscall, which will 64 // block until the $GOMAXPROCS limit allows running this goroutine. 65 // Once exitsyscall has returned, it is safe to do things like call the memory 66 // allocator or invoke the Go callback function p.GoF. runtime.cgocallbackg 67 // first defers a function to unwind m->g0.sched.sp, so that if p.GoF 68 // panics, m->g0.sched.sp will be restored to its old value: the m->g0 stack 69 // and the m->curg stack will be unwound in lock step. 70 // Then it calls p.GoF. Finally it pops but does not execute the deferred 71 // function, calls runtime.entersyscall, and returns to runtime.cgocallback. 72 // 73 // After it regains control, runtime.cgocallback switches back to 74 // m->g0's stack (the pointer is still in m->g0.sched.sp), restores the old 75 // m->g0.sched.sp value from the stack, and returns to _cgoexp_GoF. 76 // 77 // _cgoexp_GoF immediately returns to crosscall2, which restores the 78 // callee-save registers for gcc and returns to GoF, which returns to f. 79 80 package runtime 81 82 import "unsafe" 83 84 // Call from Go to C. 85 //go:nosplit 86 func cgocall(fn, arg unsafe.Pointer) { 87 cgocall_errno(fn, arg) 88 } 89 90 //go:nosplit 91 func cgocall_errno(fn, arg unsafe.Pointer) int32 { 92 if !iscgo && GOOS != "solaris" && GOOS != "windows" { 93 gothrow("cgocall unavailable") 94 } 95 96 if fn == nil { 97 gothrow("cgocall nil") 98 } 99 100 if raceenabled { 101 racereleasemerge(unsafe.Pointer(&racecgosync)) 102 } 103 104 // Create an extra M for callbacks on threads not created by Go on first cgo call. 105 if needextram == 1 && cas(&needextram, 1, 0) { 106 systemstack(newextram) 107 } 108 109 /* 110 * Lock g to m to ensure we stay on the same stack if we do a 111 * cgo callback. Add entry to defer stack in case of panic. 112 */ 113 lockOSThread() 114 mp := getg().m 115 mp.ncgocall++ 116 mp.ncgo++ 117 defer endcgo(mp) 118 119 /* 120 * Announce we are entering a system call 121 * so that the scheduler knows to create another 122 * M to run goroutines while we are in the 123 * foreign code. 124 * 125 * The call to asmcgocall is guaranteed not to 126 * split the stack and does not allocate memory, 127 * so it is safe to call while "in a system call", outside 128 * the $GOMAXPROCS accounting. 129 */ 130 entersyscall(0) 131 errno := asmcgocall_errno(fn, arg) 132 exitsyscall(0) 133 134 return errno 135 } 136 137 //go:nosplit 138 func endcgo(mp *m) { 139 mp.ncgo-- 140 if mp.ncgo == 0 { 141 // We are going back to Go and are not in a recursive 142 // call. Let the GC collect any memory allocated via 143 // _cgo_allocate that is no longer referenced. 144 mp.cgomal = nil 145 } 146 147 if raceenabled { 148 raceacquire(unsafe.Pointer(&racecgosync)) 149 } 150 151 unlockOSThread() // invalidates mp 152 } 153 154 // Helper functions for cgo code. 155 156 func cmalloc(n uintptr) unsafe.Pointer { 157 var args struct { 158 n uint64 159 ret unsafe.Pointer 160 } 161 args.n = uint64(n) 162 cgocall(_cgo_malloc, unsafe.Pointer(&args)) 163 if args.ret == nil { 164 gothrow("C malloc failed") 165 } 166 return args.ret 167 } 168 169 func cfree(p unsafe.Pointer) { 170 cgocall(_cgo_free, p) 171 } 172 173 // Call from C back to Go. 174 //go:nosplit 175 func cgocallbackg() { 176 gp := getg() 177 if gp != gp.m.curg { 178 println("runtime: bad g in cgocallback") 179 exit(2) 180 } 181 182 // entersyscall saves the caller's SP to allow the GC to trace the Go 183 // stack. However, since we're returning to an earlier stack frame and 184 // need to pair with the entersyscall() call made by cgocall, we must 185 // save syscall* and let reentersyscall restore them. 186 savedsp := unsafe.Pointer(gp.syscallsp) 187 savedpc := gp.syscallpc 188 exitsyscall(0) // coming out of cgo call 189 cgocallbackg1() 190 // going back to cgo call 191 reentersyscall(savedpc, uintptr(savedsp)) 192 } 193 194 func cgocallbackg1() { 195 gp := getg() 196 if gp.m.needextram { 197 gp.m.needextram = false 198 systemstack(newextram) 199 } 200 201 // Add entry to defer stack in case of panic. 202 restore := true 203 defer unwindm(&restore) 204 205 if raceenabled { 206 raceacquire(unsafe.Pointer(&racecgosync)) 207 } 208 209 type args struct { 210 fn *funcval 211 arg unsafe.Pointer 212 argsize uintptr 213 } 214 var cb *args 215 216 // Location of callback arguments depends on stack frame layout 217 // and size of stack frame of cgocallback_gofunc. 218 sp := gp.m.g0.sched.sp 219 switch GOARCH { 220 default: 221 gothrow("cgocallbackg is unimplemented on arch") 222 case "arm": 223 // On arm, stack frame is two words and there's a saved LR between 224 // SP and the stack frame and between the stack frame and the arguments. 225 cb = (*args)(unsafe.Pointer(sp + 4*ptrSize)) 226 case "amd64": 227 // On amd64, stack frame is one word, plus caller PC. 228 cb = (*args)(unsafe.Pointer(sp + 2*ptrSize)) 229 case "386": 230 // On 386, stack frame is three words, plus caller PC. 231 cb = (*args)(unsafe.Pointer(sp + 4*ptrSize)) 232 } 233 234 // Invoke callback. 235 reflectcall(unsafe.Pointer(cb.fn), unsafe.Pointer(cb.arg), uint32(cb.argsize), 0) 236 237 if raceenabled { 238 racereleasemerge(unsafe.Pointer(&racecgosync)) 239 } 240 241 // Do not unwind m->g0->sched.sp. 242 // Our caller, cgocallback, will do that. 243 restore = false 244 } 245 246 func unwindm(restore *bool) { 247 if !*restore { 248 return 249 } 250 // Restore sp saved by cgocallback during 251 // unwind of g's stack (see comment at top of file). 252 mp := acquirem() 253 sched := &mp.g0.sched 254 switch GOARCH { 255 default: 256 gothrow("unwindm not implemented") 257 case "386", "amd64": 258 sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp)) 259 case "arm": 260 sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 4)) 261 } 262 releasem(mp) 263 } 264 265 // called from assembly 266 func badcgocallback() { 267 gothrow("misaligned stack in cgocallback") 268 } 269 270 // called from (incomplete) assembly 271 func cgounimpl() { 272 gothrow("cgo not implemented") 273 } 274 275 var racecgosync uint64 // represents possible synchronization in C code