void runtime·cgocall(void (*fn)(void*), void *arg) { Defer d; if(m->racecall) { runtime·asmcgocall(fn, arg); return; } if(!runtime·iscgo && !Windows) runtime·throw("cgocall unavailable"); if(fn == 0) runtime·throw("cgocall nil"); if(raceenabled) runtime·racereleasemerge(&cgosync); // Create an extra M for callbacks on threads not created by Go on first cgo call. if(runtime·needextram && runtime·cas(&runtime·needextram, 1, 0)) runtime·newextram(); m->ncgocall++; /* * Lock g to m to ensure we stay on the same stack if we do a * cgo callback. Add entry to defer stack in case of panic. */ runtime·lockOSThread(); d.fn = &endcgoV; d.siz = 0; d.link = g->defer; d.argp = (void*)-1; // unused because unlockm never recovers d.special = true; d.free = false; g->defer = &d; m->ncgo++; /* * 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(g->defer != &d || d.fn != &endcgoV) runtime·throw("runtime: bad defer entry in cgocallback"); g->defer = d.link; endcgo(); }
void runtime·cgocallbackg(FuncVal *fn, void *arg, uintptr argsize) { Defer d; if(m->racecall) { reflect·call(fn, arg, argsize); return; } if(g != m->curg) runtime·throw("runtime: bad g in cgocallback"); runtime·exitsyscall(); // coming out of cgo call if(m->needextram) { m->needextram = 0; runtime·newextram(); } // Add entry to defer stack in case of panic. d.fn = &unwindmf; d.siz = 0; d.link = g->defer; d.argp = (void*)-1; // unused because unwindm never recovers d.special = true; d.free = false; g->defer = &d; if(raceenabled) runtime·raceacquire(&cgosync); // Invoke callback. reflect·call(fn, arg, argsize); if(raceenabled) runtime·racereleasemerge(&cgosync); // Pop defer. // Do not unwind m->g0->sched.sp. // Our caller, cgocallback, will do that. if(g->defer != &d || d.fn != &unwindmf) runtime·throw("runtime: bad defer entry in cgocallback"); g->defer = d.link; runtime·entersyscall(); // going back to cgo call }
void runtime·cgocallbackg1(void) { CallbackArgs *cb; Defer d; if(m->needextram) { m->needextram = 0; runtime·newextram(); } // Add entry to defer stack in case of panic. d.fn = &unwindmf; d.siz = 0; d.link = g->defer; d.argp = (void*)-1; // unused because unwindm never recovers d.special = true; d.free = false; g->defer = &d; if(raceenabled && !m->racecall) runtime·raceacquire(&cgosync); // Invoke callback. cb = CBARGS; runtime·newstackcall(cb->fn, cb->arg, cb->argsize); if(raceenabled && !m->racecall) runtime·racereleasemerge(&cgosync); // Pop defer. // Do not unwind m->g0->sched.sp. // Our caller, cgocallback, will do that. if(g->defer != &d || d.fn != &unwindmf) runtime·throw("runtime: bad defer entry in cgocallback"); g->defer = d.link; }