aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime/cgocall.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/cgocall.c')
-rw-r--r--src/pkg/runtime/cgocall.c41
1 files changed, 28 insertions, 13 deletions
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
index 888e09c561..07aef495cf 100644
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -255,22 +255,39 @@ struct CallbackArgs
#define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+4*sizeof(void*))
#endif
+void runtime·cgocallbackg1(void);
+
+#pragma textflag 7
void
runtime·cgocallbackg(void)
{
- Defer d;
- CallbackArgs *cb;
+ if(g != m->curg) {
+ runtime·prints("runtime: bad g in cgocallback");
+ runtime·exit(2);
+ }
if(m->racecall) {
- cb = CBARGS;
- reflect·call(cb->fn, cb->arg, cb->argsize);
- return;
+ // 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
}
+}
- if(g != m->curg)
- runtime·throw("runtime: bad g in cgocallback");
-
- runtime·exitsyscall(); // coming out of cgo call
+void
+runtime·cgocallbackg1(void)
+{
+ CallbackArgs *cb;
+ Defer d;
if(m->needextram) {
m->needextram = 0;
@@ -286,14 +303,14 @@ runtime·cgocallbackg(void)
d.free = false;
g->defer = &d;
- if(raceenabled)
+ if(raceenabled && !m->racecall)
runtime·raceacquire(&cgosync);
// Invoke callback.
cb = CBARGS;
reflect·call(cb->fn, cb->arg, cb->argsize);
- if(raceenabled)
+ if(raceenabled && !m->racecall)
runtime·racereleasemerge(&cgosync);
// Pop defer.
@@ -302,8 +319,6 @@ runtime·cgocallbackg(void)
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
}
static void