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 }
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(); }
uintptr runtime·syscall(void *fn, uintptr nargs, void *args, uintptr *err) { G *oldlock; uintptr ret; /* * Lock g to m to ensure we stay on the same stack if we do a callback. */ oldlock = m->lockedg; m->lockedg = g; g->lockedm = m; runtime·entersyscall(); runtime·setlasterror(0); ret = (uintptr)runtime·stdcall_raw(fn, nargs, args); if(err) *err = runtime·getlasterror(); runtime·exitsyscall(); m->lockedg = oldlock; if(oldlock == nil) g->lockedm = nil; return ret; }
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(); } }
void runtime·cgocallbackg(void) { if(g != m->curg) { runtime·prints("runtime: bad g in cgocallback"); runtime·exit(2); } runtime·exitsyscall(); // coming out of cgo call runtime·cgocallbackg1(); runtime·entersyscall(); // going back to cgo call }
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·cgocallbackg(void) { if(g != m->curg) { runtime·prints("runtime: bad g in cgocallback"); runtime·exit(2); } if(m->racecall) { // We were not in syscall, so no need to call runtime·exitsyscall. // However we must set m->locks for the following reason. // Race detector runtime makes __tsan_symbolize cgo callback // holding internal mutexes. The mutexes are not cooperative with Go scheduler. // So if we deschedule a goroutine that holds race detector internal mutex // (e.g. preempt it), another goroutine will deadlock trying to acquire the same mutex. m->locks++; runtime·cgocallbackg1(); m->locks--; } else { runtime·exitsyscall(); // coming out of cgo call runtime·cgocallbackg1(); runtime·entersyscall(); // going back to cgo call } }