| // Copyright 2009 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. | |
| #include "runtime.h" | |
| #include "arch_GOARCH.h" | |
| #include "stack.h" | |
| #include "cgocall.h" | |
| // Cgo call and callback support. | |
| // | |
| // To call into the C function f from Go, the cgo-generated code calls | |
| // runtime.cgocall(_cgo_Cfunc_f, frame), where _cgo_Cfunc_f is a | |
| // gcc-compiled function written by cgo. | |
| // | |
| // runtime.cgocall (below) locks g to m, calls entersyscall | |
| // so as not to block other goroutines or the garbage collector, | |
| // and then calls runtime.asmcgocall(_cgo_Cfunc_f, frame). | |
| // | |
| // runtime.asmcgocall (in asm_$GOARCH.s) switches to the m->g0 stack | |
| // (assumed to be an operating system-allocated stack, so safe to run | |
| // gcc-compiled code on) and calls _cgo_Cfunc_f(frame). | |
| // | |
| // _cgo_Cfunc_f invokes the actual C function f with arguments | |
| // taken from the frame structure, records the results in the frame, | |
| // and returns to runtime.asmcgocall. | |
| // | |
| // After it regains control, runtime.asmcgocall switches back to the | |
| // original g (m->curg)'s stack and returns to runtime.cgocall. | |
| // | |
| // After it regains control, runtime.cgocall calls exitsyscall, which blocks | |
| // until this m can run Go code without violating the $GOMAXPROCS limit, | |
| // and then unlocks g from m. | |
| // | |
| // The above description skipped over the possibility of the gcc-compiled | |
| // function f calling back into Go. If that happens, we continue down | |
| // the rabbit hole during the execution of f. | |
| // | |
| // To make it possible for gcc-compiled C code to call a Go function p.GoF, | |
| // cgo writes a gcc-compiled function named GoF (not p.GoF, since gcc doesn't | |
| // know about packages). The gcc-compiled C function f calls GoF. | |
| // | |
| // GoF calls crosscall2(_cgoexp_GoF, frame, framesize). Crosscall2 | |
| // (in cgo/$GOOS.S, a gcc-compiled assembly file) is a two-argument | |
| // adapter from the gcc function call ABI to the 6c function call ABI. | |
| // It is called from gcc to call 6c functions. In this case it calls | |
| // _cgoexp_GoF(frame, framesize), still running on m->g0's stack | |
| // and outside the $GOMAXPROCS limit. Thus, this code cannot yet | |
| // call arbitrary Go code directly and must be careful not to allocate | |
| // memory or use up m->g0's stack. | |
| // | |
| // _cgoexp_GoF calls runtime.cgocallback(p.GoF, frame, framesize). | |
| // (The reason for having _cgoexp_GoF instead of writing a crosscall3 | |
| // to make this call directly is that _cgoexp_GoF, because it is compiled | |
| // with 6c instead of gcc, can refer to dotted names like | |
| // runtime.cgocallback and p.GoF.) | |
| // | |
| // runtime.cgocallback (in asm_$GOARCH.s) switches from m->g0's | |
| // stack to the original g (m->curg)'s stack, on which it calls | |
| // runtime.cgocallbackg(p.GoF, frame, framesize). | |
| // As part of the stack switch, runtime.cgocallback saves the current | |
| // SP as m->g0->sched.sp, so that any use of m->g0's stack during the | |
| // execution of the callback will be done below the existing stack frames. | |
| // Before overwriting m->g0->sched.sp, it pushes the old value on the | |
| // m->g0 stack, so that it can be restored later. | |
| // | |
| // runtime.cgocallbackg (below) is now running on a real goroutine | |
| // stack (not an m->g0 stack). First it calls runtime.exitsyscall, which will | |
| // block until the $GOMAXPROCS limit allows running this goroutine. | |
| // Once exitsyscall has returned, it is safe to do things like call the memory | |
| // allocator or invoke the Go callback function p.GoF. runtime.cgocallbackg | |
| // first defers a function to unwind m->g0.sched.sp, so that if p.GoF | |
| // panics, m->g0.sched.sp will be restored to its old value: the m->g0 stack | |
| // and the m->curg stack will be unwound in lock step. | |
| // Then it calls p.GoF. Finally it pops but does not execute the deferred | |
| // function, calls runtime.entersyscall, and returns to runtime.cgocallback. | |
| // | |
| // After it regains control, runtime.cgocallback switches back to | |
| // m->g0's stack (the pointer is still in m->g0.sched.sp), restores the old | |
| // m->g0.sched.sp value from the stack, and returns to _cgoexp_GoF. | |
| // | |
| // _cgoexp_GoF immediately returns to crosscall2, which restores the | |
| // callee-save registers for gcc and returns to GoF, which returns to f. | |
| void *initcgo; /* filled in by dynamic linker when Cgo is available */ | |
| // These two are only used by the architecture where TLS based storage isn't | |
| // the default for g and m (e.g., ARM) | |
| void *cgo_load_gm; /* filled in by dynamic linker when Cgo is available */ | |
| void *cgo_save_gm; /* filled in by dynamic linker when Cgo is available */ | |
| static void unlockm(void); | |
| static void unwindm(void); | |
| // Call from Go to C. | |
| void | |
| runtime·cgocall(void (*fn)(void*), void *arg) | |
| { | |
| Defer d; | |
| if(!runtime·iscgo && !Windows) | |
| runtime·throw("cgocall unavailable"); | |
| if(fn == 0) | |
| runtime·throw("cgocall nil"); | |
| m->ncgocall++; | |
| /* | |
| * Lock g to m to ensure we stay on the same stack if we do a | |
| * cgo callback. | |
| */ | |
| d.nofree = false; | |
| if(m->lockedg == nil) { | |
| m->lockedg = g; | |
| g->lockedm = m; | |
| // Add entry to defer stack in case of panic. | |
| d.fn = (byte*)unlockm; | |
| d.siz = 0; | |
| d.link = g->defer; | |
| d.argp = (void*)-1; // unused because unlockm never recovers | |
| d.nofree = true; | |
| g->defer = &d; | |
| } | |
| /* | |
| * Announce we are entering a system call | |
| * so that the scheduler knows to create another | |
| * M to run goroutines while we are in the | |
| * foreign code. | |
| * | |
| * The call to asmcgocall is guaranteed not to | |
| * split the stack and does not allocate memory, | |
| * so it is safe to call while "in a system call", outside | |
| * the $GOMAXPROCS accounting. | |
| */ | |
| runtime·entersyscall(); | |
| runtime·asmcgocall(fn, arg); | |
| runtime·exitsyscall(); | |
| if(d.nofree) { | |
| if(g->defer != &d || d.fn != (byte*)unlockm) | |
| runtime·throw("runtime: bad defer entry in cgocallback"); | |
| g->defer = d.link; | |
| unlockm(); | |
| } | |
| } | |
| static void | |
| unlockm(void) | |
| { | |
| m->lockedg = nil; | |
| g->lockedm = nil; | |
| } | |
| void | |
| runtime·NumCgoCall(int64 ret) | |
| { | |
| M *m; | |
| ret = 0; | |
| for(m=runtime·atomicloadp(&runtime·allm); m; m=m->alllink) | |
| ret += m->ncgocall; | |
| FLUSH(&ret); | |
| } | |
| // Helper functions for cgo code. | |
| void (*_cgo_malloc)(void*); | |
| void (*_cgo_free)(void*); | |
| void* | |
| runtime·cmalloc(uintptr n) | |
| { | |
| struct { | |
| uint64 n; | |
| void *ret; | |
| } a; | |
| a.n = n; | |
| a.ret = nil; | |
| runtime·cgocall(_cgo_malloc, &a); | |
| return a.ret; | |
| } | |
| void | |
| runtime·cfree(void *p) | |
| { | |
| runtime·cgocall(_cgo_free, p); | |
| } | |
| // Call from C back to Go. | |
| void | |
| runtime·cgocallbackg(void (*fn)(void), void *arg, uintptr argsize) | |
| { | |
| Defer d; | |
| if(g != m->curg) | |
| runtime·throw("runtime: bad g in cgocallback"); | |
| runtime·exitsyscall(); // coming out of cgo call | |
| // Add entry to defer stack in case of panic. | |
| d.fn = (byte*)unwindm; | |
| d.siz = 0; | |
| d.link = g->defer; | |
| d.argp = (void*)-1; // unused because unwindm never recovers | |
| d.nofree = true; | |
| g->defer = &d; | |
| // Invoke callback. | |
| reflect·call((byte*)fn, arg, argsize); | |
| // Pop defer. | |
| // Do not unwind m->g0->sched.sp. | |
| // Our caller, cgocallback, will do that. | |
| if(g->defer != &d || d.fn != (byte*)unwindm) | |
| runtime·throw("runtime: bad defer entry in cgocallback"); | |
| g->defer = d.link; | |
| runtime·entersyscall(); // going back to cgo call | |
| } | |
| static void | |
| unwindm(void) | |
| { | |
| // Restore sp saved by cgocallback during | |
| // unwind of g's stack (see comment at top of file). | |
| switch(thechar){ | |
| default: | |
| runtime·throw("runtime: unwindm not implemented"); | |
| case '8': | |
| case '6': | |
| case '5': | |
| m->g0->sched.sp = *(uintptr*)m->g0->sched.sp; | |
| break; | |
| } | |
| } | |
| void | |
| runtime·badcgocallback(void) // called from assembly | |
| { | |
| runtime·throw("runtime: misaligned stack in cgocallback"); | |
| } | |
| void | |
| runtime·cgounimpl(void) // called from (incomplete) assembly | |
| { | |
| runtime·throw("runtime: cgo not implemented"); | |
| } |