Home | History | Annotate | Download | only in runtime
      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) int32 {
     87 	if !iscgo && GOOS != "solaris" && GOOS != "windows" {
     88 		throw("cgocall unavailable")
     89 	}
     90 
     91 	if fn == nil {
     92 		throw("cgocall nil")
     93 	}
     94 
     95 	if raceenabled {
     96 		racereleasemerge(unsafe.Pointer(&racecgosync))
     97 	}
     98 
     99 	/*
    100 	 * Lock g to m to ensure we stay on the same stack if we do a
    101 	 * cgo callback. Add entry to defer stack in case of panic.
    102 	 */
    103 	lockOSThread()
    104 	mp := getg().m
    105 	mp.ncgocall++
    106 	mp.ncgo++
    107 	defer endcgo(mp)
    108 
    109 	/*
    110 	 * Announce we are entering a system call
    111 	 * so that the scheduler knows to create another
    112 	 * M to run goroutines while we are in the
    113 	 * foreign code.
    114 	 *
    115 	 * The call to asmcgocall is guaranteed not to
    116 	 * split the stack and does not allocate memory,
    117 	 * so it is safe to call while "in a system call", outside
    118 	 * the $GOMAXPROCS accounting.
    119 	 */
    120 	entersyscall(0)
    121 	errno := asmcgocall(fn, arg)
    122 	exitsyscall(0)
    123 
    124 	return errno
    125 }
    126 
    127 //go:nosplit
    128 func endcgo(mp *m) {
    129 	mp.ncgo--
    130 
    131 	if raceenabled {
    132 		raceacquire(unsafe.Pointer(&racecgosync))
    133 	}
    134 
    135 	unlockOSThread() // invalidates mp
    136 }
    137 
    138 // Helper functions for cgo code.
    139 
    140 func cmalloc(n uintptr) unsafe.Pointer {
    141 	var args struct {
    142 		n   uint64
    143 		ret unsafe.Pointer
    144 	}
    145 	args.n = uint64(n)
    146 	cgocall(_cgo_malloc, unsafe.Pointer(&args))
    147 	if args.ret == nil {
    148 		throw("C malloc failed")
    149 	}
    150 	return args.ret
    151 }
    152 
    153 func cfree(p unsafe.Pointer) {
    154 	cgocall(_cgo_free, p)
    155 }
    156 
    157 // Call from C back to Go.
    158 //go:nosplit
    159 func cgocallbackg() {
    160 	gp := getg()
    161 	if gp != gp.m.curg {
    162 		println("runtime: bad g in cgocallback")
    163 		exit(2)
    164 	}
    165 
    166 	// Save current syscall parameters, so m.syscall can be
    167 	// used again if callback decide to make syscall.
    168 	syscall := gp.m.syscall
    169 
    170 	// entersyscall saves the caller's SP to allow the GC to trace the Go
    171 	// stack. However, since we're returning to an earlier stack frame and
    172 	// need to pair with the entersyscall() call made by cgocall, we must
    173 	// save syscall* and let reentersyscall restore them.
    174 	savedsp := unsafe.Pointer(gp.syscallsp)
    175 	savedpc := gp.syscallpc
    176 	exitsyscall(0) // coming out of cgo call
    177 	cgocallbackg1()
    178 	// going back to cgo call
    179 	reentersyscall(savedpc, uintptr(savedsp))
    180 
    181 	gp.m.syscall = syscall
    182 }
    183 
    184 func cgocallbackg1() {
    185 	gp := getg()
    186 	if gp.m.needextram {
    187 		gp.m.needextram = false
    188 		systemstack(newextram)
    189 	}
    190 
    191 	if gp.m.ncgo == 0 {
    192 		// The C call to Go came from a thread not currently running
    193 		// any Go. In the case of -buildmode=c-archive or c-shared,
    194 		// this call may be coming in before package initialization
    195 		// is complete. Wait until it is.
    196 		<-main_init_done
    197 	}
    198 
    199 	// Add entry to defer stack in case of panic.
    200 	restore := true
    201 	defer unwindm(&restore)
    202 
    203 	if raceenabled {
    204 		raceacquire(unsafe.Pointer(&racecgosync))
    205 	}
    206 
    207 	type args struct {
    208 		fn      *funcval
    209 		arg     unsafe.Pointer
    210 		argsize uintptr
    211 	}
    212 	var cb *args
    213 
    214 	// Location of callback arguments depends on stack frame layout
    215 	// and size of stack frame of cgocallback_gofunc.
    216 	sp := gp.m.g0.sched.sp
    217 	switch GOARCH {
    218 	default:
    219 		throw("cgocallbackg is unimplemented on arch")
    220 	case "arm":
    221 		// On arm, stack frame is two words and there's a saved LR between
    222 		// SP and the stack frame and between the stack frame and the arguments.
    223 		cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
    224 	case "arm64":
    225 		// On arm64, stack frame is four words and there's a saved LR between
    226 		// SP and the stack frame and between the stack frame and the arguments.
    227 		cb = (*args)(unsafe.Pointer(sp + 5*ptrSize))
    228 	case "amd64":
    229 		// On amd64, stack frame is one word, plus caller PC.
    230 		if framepointer_enabled {
    231 			// In this case, there's also saved BP.
    232 			cb = (*args)(unsafe.Pointer(sp + 3*ptrSize))
    233 			break
    234 		}
    235 		cb = (*args)(unsafe.Pointer(sp + 2*ptrSize))
    236 	case "386":
    237 		// On 386, stack frame is three words, plus caller PC.
    238 		cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
    239 	case "ppc64", "ppc64le":
    240 		// On ppc64, stack frame is two words and there's a
    241 		// saved LR between SP and the stack frame and between
    242 		// the stack frame and the arguments.
    243 		cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
    244 	}
    245 
    246 	// Invoke callback.
    247 	// NOTE(rsc): passing nil for argtype means that the copying of the
    248 	// results back into cb.arg happens without any corresponding write barriers.
    249 	// For cgo, cb.arg points into a C stack frame and therefore doesn't
    250 	// hold any pointers that the GC can find anyway - the write barrier
    251 	// would be a no-op.
    252 	reflectcall(nil, unsafe.Pointer(cb.fn), unsafe.Pointer(cb.arg), uint32(cb.argsize), 0)
    253 
    254 	if raceenabled {
    255 		racereleasemerge(unsafe.Pointer(&racecgosync))
    256 	}
    257 
    258 	// Do not unwind m->g0->sched.sp.
    259 	// Our caller, cgocallback, will do that.
    260 	restore = false
    261 }
    262 
    263 func unwindm(restore *bool) {
    264 	if !*restore {
    265 		return
    266 	}
    267 	// Restore sp saved by cgocallback during
    268 	// unwind of g's stack (see comment at top of file).
    269 	mp := acquirem()
    270 	sched := &mp.g0.sched
    271 	switch GOARCH {
    272 	default:
    273 		throw("unwindm not implemented")
    274 	case "386", "amd64":
    275 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp))
    276 	case "arm":
    277 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 4))
    278 	case "arm64":
    279 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 16))
    280 	case "ppc64", "ppc64le":
    281 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 8))
    282 	}
    283 	releasem(mp)
    284 }
    285 
    286 // called from assembly
    287 func badcgocallback() {
    288 	throw("misaligned stack in cgocallback")
    289 }
    290 
    291 // called from (incomplete) assembly
    292 func cgounimpl() {
    293 	throw("cgo not implemented")
    294 }
    295 
    296 var racecgosync uint64 // represents possible synchronization in C code
    297