...
Run Format

Text file src/pkg/runtime/cgocall.c

     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	#include "runtime.h"
     6	#include "arch_GOARCH.h"
     7	#include "stack.h"
     8	#include "cgocall.h"
     9	#include "race.h"
    10	#include "../../cmd/ld/textflag.h"
    11	
    12	// Cgo call and callback support.
    13	//
    14	// To call into the C function f from Go, the cgo-generated code calls
    15	// runtime.cgocall(_cgo_Cfunc_f, frame), where _cgo_Cfunc_f is a
    16	// gcc-compiled function written by cgo.
    17	//
    18	// runtime.cgocall (below) locks g to m, calls entersyscall
    19	// so as not to block other goroutines or the garbage collector,
    20	// and then calls runtime.asmcgocall(_cgo_Cfunc_f, frame). 
    21	//
    22	// runtime.asmcgocall (in asm_$GOARCH.s) switches to the m->g0 stack
    23	// (assumed to be an operating system-allocated stack, so safe to run
    24	// gcc-compiled code on) and calls _cgo_Cfunc_f(frame).
    25	//
    26	// _cgo_Cfunc_f invokes the actual C function f with arguments
    27	// taken from the frame structure, records the results in the frame,
    28	// and returns to runtime.asmcgocall.
    29	//
    30	// After it regains control, runtime.asmcgocall switches back to the
    31	// original g (m->curg)'s stack and returns to runtime.cgocall.
    32	//
    33	// After it regains control, runtime.cgocall calls exitsyscall, which blocks
    34	// until this m can run Go code without violating the $GOMAXPROCS limit,
    35	// and then unlocks g from m.
    36	//
    37	// The above description skipped over the possibility of the gcc-compiled
    38	// function f calling back into Go.  If that happens, we continue down
    39	// the rabbit hole during the execution of f.
    40	//
    41	// To make it possible for gcc-compiled C code to call a Go function p.GoF,
    42	// cgo writes a gcc-compiled function named GoF (not p.GoF, since gcc doesn't
    43	// know about packages).  The gcc-compiled C function f calls GoF.
    44	//
    45	// GoF calls crosscall2(_cgoexp_GoF, frame, framesize).  Crosscall2
    46	// (in cgo/gcc_$GOARCH.S, a gcc-compiled assembly file) is a two-argument
    47	// adapter from the gcc function call ABI to the 6c function call ABI.
    48	// It is called from gcc to call 6c functions.  In this case it calls
    49	// _cgoexp_GoF(frame, framesize), still running on m->g0's stack
    50	// and outside the $GOMAXPROCS limit.  Thus, this code cannot yet
    51	// call arbitrary Go code directly and must be careful not to allocate
    52	// memory or use up m->g0's stack.
    53	//
    54	// _cgoexp_GoF calls runtime.cgocallback(p.GoF, frame, framesize).
    55	// (The reason for having _cgoexp_GoF instead of writing a crosscall3
    56	// to make this call directly is that _cgoexp_GoF, because it is compiled
    57	// with 6c instead of gcc, can refer to dotted names like
    58	// runtime.cgocallback and p.GoF.)
    59	//
    60	// runtime.cgocallback (in asm_$GOARCH.s) switches from m->g0's
    61	// stack to the original g (m->curg)'s stack, on which it calls
    62	// runtime.cgocallbackg(p.GoF, frame, framesize).
    63	// As part of the stack switch, runtime.cgocallback saves the current
    64	// SP as m->g0->sched.sp, so that any use of m->g0's stack during the
    65	// execution of the callback will be done below the existing stack frames.
    66	// Before overwriting m->g0->sched.sp, it pushes the old value on the
    67	// m->g0 stack, so that it can be restored later.
    68	//
    69	// runtime.cgocallbackg (below) is now running on a real goroutine
    70	// stack (not an m->g0 stack).  First it calls runtime.exitsyscall, which will
    71	// block until the $GOMAXPROCS limit allows running this goroutine.
    72	// Once exitsyscall has returned, it is safe to do things like call the memory
    73	// allocator or invoke the Go callback function p.GoF.  runtime.cgocallbackg
    74	// first defers a function to unwind m->g0.sched.sp, so that if p.GoF
    75	// panics, m->g0.sched.sp will be restored to its old value: the m->g0 stack
    76	// and the m->curg stack will be unwound in lock step.
    77	// Then it calls p.GoF.  Finally it pops but does not execute the deferred
    78	// function, calls runtime.entersyscall, and returns to runtime.cgocallback.
    79	//
    80	// After it regains control, runtime.cgocallback switches back to
    81	// m->g0's stack (the pointer is still in m->g0.sched.sp), restores the old
    82	// m->g0.sched.sp value from the stack, and returns to _cgoexp_GoF.
    83	//
    84	// _cgoexp_GoF immediately returns to crosscall2, which restores the
    85	// callee-save registers for gcc and returns to GoF, which returns to f.
    86	
    87	void *_cgo_init;	/* filled in by dynamic linker when Cgo is available */
    88	static int64 cgosync;  /* represents possible synchronization in C code */
    89	
    90	static void unwindm(void);
    91	
    92	// Call from Go to C.
    93	
    94	static void endcgo(void);
    95	static FuncVal endcgoV = { endcgo };
    96	
    97	void
    98	runtime·cgocall(void (*fn)(void*), void *arg)
    99	{
   100		Defer d;
   101	
   102		if(!runtime·iscgo && !Solaris && !Windows)
   103			runtime·throw("cgocall unavailable");
   104	
   105		if(fn == 0)
   106			runtime·throw("cgocall nil");
   107	
   108		if(raceenabled)
   109			runtime·racereleasemerge(&cgosync);
   110	
   111		// Create an extra M for callbacks on threads not created by Go on first cgo call.
   112		if(runtime·needextram && runtime·cas(&runtime·needextram, 1, 0))
   113			runtime·newextram();
   114	
   115		m->ncgocall++;
   116	
   117		/*
   118		 * Lock g to m to ensure we stay on the same stack if we do a
   119		 * cgo callback. Add entry to defer stack in case of panic.
   120		 */
   121		runtime·lockOSThread();
   122		d.fn = &endcgoV;
   123		d.siz = 0;
   124		d.link = g->defer;
   125		d.argp = NoArgs;
   126		d.special = true;
   127		g->defer = &d;
   128		
   129		m->ncgo++;
   130	
   131		/*
   132		 * Announce we are entering a system call
   133		 * so that the scheduler knows to create another
   134		 * M to run goroutines while we are in the
   135		 * foreign code.
   136		 *
   137		 * The call to asmcgocall is guaranteed not to
   138		 * split the stack and does not allocate memory,
   139		 * so it is safe to call while "in a system call", outside
   140		 * the $GOMAXPROCS accounting.
   141		 */
   142		runtime·entersyscall();
   143		runtime·asmcgocall(fn, arg);
   144		runtime·exitsyscall();
   145	
   146		if(g->defer != &d || d.fn != &endcgoV)
   147			runtime·throw("runtime: bad defer entry in cgocallback");
   148		g->defer = d.link;
   149		endcgo();
   150	}
   151	
   152	static void
   153	endcgo(void)
   154	{
   155		runtime·unlockOSThread();
   156		m->ncgo--;
   157		if(m->ncgo == 0) {
   158			// We are going back to Go and are not in a recursive
   159			// call.  Let the GC collect any memory allocated via
   160			// _cgo_allocate that is no longer referenced.
   161			m->cgomal = nil;
   162		}
   163	
   164		if(raceenabled)
   165			runtime·raceacquire(&cgosync);
   166	}
   167	
   168	// Helper functions for cgo code.
   169	
   170	void (*_cgo_malloc)(void*);
   171	void (*_cgo_free)(void*);
   172	
   173	void*
   174	runtime·cmalloc(uintptr n)
   175	{
   176		struct {
   177			uint64 n;
   178			void *ret;
   179		} a;
   180	
   181		a.n = n;
   182		a.ret = nil;
   183		runtime·cgocall(_cgo_malloc, &a);
   184		if(a.ret == nil)
   185			runtime·throw("runtime: C malloc failed");
   186		return a.ret;
   187	}
   188	
   189	void
   190	runtime·cfree(void *p)
   191	{
   192		runtime·cgocall(_cgo_free, p);
   193	}
   194	
   195	// Call from C back to Go.
   196	
   197	static FuncVal unwindmf = {unwindm};
   198	
   199	typedef struct CallbackArgs CallbackArgs;
   200	struct CallbackArgs
   201	{
   202		FuncVal *fn;
   203		void *arg;
   204		uintptr argsize;
   205	};
   206	
   207	// Location of callback arguments depends on stack frame layout
   208	// and size of stack frame of cgocallback_gofunc.
   209	
   210	// On arm, stack frame is two words and there's a saved LR between
   211	// SP and the stack frame and between the stack frame and the arguments.
   212	#ifdef GOARCH_arm
   213	#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+4*sizeof(void*))
   214	#endif
   215	
   216	// On amd64, stack frame is one word, plus caller PC.
   217	#ifdef GOARCH_amd64
   218	#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+2*sizeof(void*))
   219	#endif
   220	
   221	// Unimplemented on amd64p32
   222	#ifdef GOARCH_amd64p32
   223	#define CBARGS (CallbackArgs*)(nil)
   224	#endif
   225	
   226	// On 386, stack frame is three words, plus caller PC.
   227	#ifdef GOARCH_386
   228	#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+4*sizeof(void*))
   229	#endif
   230	
   231	void runtime·cgocallbackg1(void);
   232	
   233	#pragma textflag NOSPLIT
   234	void
   235	runtime·cgocallbackg(void)
   236	{
   237		if(g != m->curg) {
   238			runtime·prints("runtime: bad g in cgocallback");
   239			runtime·exit(2);
   240		}
   241	
   242		runtime·exitsyscall();	// coming out of cgo call
   243		runtime·cgocallbackg1();
   244		runtime·entersyscall();	// going back to cgo call
   245	}
   246	
   247	void
   248	runtime·cgocallbackg1(void)
   249	{
   250		CallbackArgs *cb;
   251		Defer d;
   252	
   253		if(m->needextram) {
   254			m->needextram = 0;
   255			runtime·newextram();
   256		}
   257	
   258		// Add entry to defer stack in case of panic.
   259		d.fn = &unwindmf;
   260		d.siz = 0;
   261		d.link = g->defer;
   262		d.argp = NoArgs;
   263		d.special = true;
   264		g->defer = &d;
   265	
   266		if(raceenabled)
   267			runtime·raceacquire(&cgosync);
   268	
   269		// Invoke callback.
   270		cb = CBARGS;
   271		runtime·newstackcall(cb->fn, cb->arg, cb->argsize);
   272	
   273		if(raceenabled)
   274			runtime·racereleasemerge(&cgosync);
   275	
   276		// Pop defer.
   277		// Do not unwind m->g0->sched.sp.
   278		// Our caller, cgocallback, will do that.
   279		if(g->defer != &d || d.fn != &unwindmf)
   280			runtime·throw("runtime: bad defer entry in cgocallback");
   281		g->defer = d.link;
   282	}
   283	
   284	static void
   285	unwindm(void)
   286	{
   287		// Restore sp saved by cgocallback during
   288		// unwind of g's stack (see comment at top of file).
   289		switch(thechar){
   290		default:
   291			runtime·throw("runtime: unwindm not implemented");
   292		case '8':
   293		case '6':
   294			m->g0->sched.sp = *(uintptr*)m->g0->sched.sp;
   295			break;
   296		case '5':
   297			m->g0->sched.sp = *(uintptr*)((byte*)m->g0->sched.sp + 4);
   298			break;
   299		}
   300	}
   301	
   302	void
   303	runtime·badcgocallback(void)	// called from assembly
   304	{
   305		runtime·throw("runtime: misaligned stack in cgocallback");
   306	}
   307	
   308	void
   309	runtime·cgounimpl(void)	// called from (incomplete) assembly
   310	{
   311		runtime·throw("runtime: cgo not implemented");
   312	}
   313	
   314	// For cgo-using programs with external linking,
   315	// export "main" (defined in assembly) so that libc can handle basic
   316	// C runtime startup and call the Go program as if it were
   317	// the C main function.
   318	#pragma cgo_export_static main

View as plain text