func Test4029(t *testing.T) { test4029(t) }
func TestBoolAlign(t *testing.T) { testBoolAlign(t) }
func Test3729(t *testing.T) { test3729(t) }
+func Test3775(t *testing.T) { test3775(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
--- /dev/null
+package cgotest
+
+/*
+void lockOSThreadCallback(void);
+inline static void lockOSThreadC(void)
+{
+ lockOSThreadCallback();
+}
+int usleep(unsigned usec);
+*/
+import "C"
+
+import (
+ "runtime"
+ "testing"
+)
+
+func test3775(t *testing.T) {
+ // Used to panic because of the UnlockOSThread below.
+ C.lockOSThreadC()
+}
+
+//export lockOSThreadCallback
+func lockOSThreadCallback() {
+ runtime.LockOSThread()
+ runtime.UnlockOSThread()
+ go C.usleep(10000)
+ runtime.Gosched()
+}
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.
/*
* Lock g to m to ensure we stay on the same stack if we do a
- * cgo callback.
+ * cgo callback. Add entry to defer stack in case of panic.
*/
- d.special = 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.special = true;
- d.free = false;
- g->defer = &d;
- }
+ runtime·lockOSThread();
+ d.fn = (byte*)runtime·unlockOSThread;
+ 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++;
m->cgomal = nil;
}
- if(d.special) {
- if(g->defer != &d || d.fn != (byte*)unlockm)
- runtime·throw("runtime: bad defer entry in cgocallback");
- g->defer = d.link;
- unlockm();
- }
+ if(g->defer != &d || d.fn != (byte*)runtime·unlockOSThread)
+ runtime·throw("runtime: bad defer entry in cgocallback");
+ g->defer = d.link;
+ runtime·unlockOSThread();
if(raceenabled)
runtime·raceacquire(&cgosync);
}
-static void
-unlockm(void)
-{
- m->lockedg = nil;
- g->lockedm = nil;
-}
-
void
runtime·NumCgoCall(int64 ret)
{
int32 profilehz; // cpu profiling rate
bool init; // running initialization
- bool lockmain; // init called runtime.LockOSThread
Note stopped; // one g can set waitstop and wait here for m's to stop
};
// Those can arrange for main.main to run in the main thread
// by calling runtime.LockOSThread during initialization
// to preserve the lock.
- runtime·LockOSThread();
+ runtime·lockOSThread();
// From now on, newgoroutines may use non-main threads.
setmcpumax(runtime·gomaxprocs);
runtime·sched.init = true;
scvg->issystem = true;
main·init();
runtime·sched.init = false;
- if(!runtime·sched.lockmain)
- runtime·UnlockOSThread();
+ runtime·unlockOSThread();
// The deadlock detection has false negatives.
// Let scvg start up, to eliminate the false negative
if(gp->lockedm) {
gp->lockedm = nil;
m->lockedg = nil;
+ m->locked = 0;
}
gp->idlem = nil;
runtime·unwindstack(gp, nil);
return ret;
}
-void
-runtime·LockOSThread(void)
+static void
+LockOSThread(void)
{
- if(m == &runtime·m0 && runtime·sched.init) {
- runtime·sched.lockmain = true;
- return;
- }
m->lockedg = g;
g->lockedm = m;
}
void
-runtime·UnlockOSThread(void)
+runtime·LockOSThread(void)
+{
+ m->locked |= LockExternal;
+ LockOSThread();
+}
+
+void
+runtime·lockOSThread(void)
+{
+ m->locked += LockInternal;
+ LockOSThread();
+}
+
+static void
+UnlockOSThread(void)
{
- if(m == &runtime·m0 && runtime·sched.init) {
- runtime·sched.lockmain = false;
+ if(m->locked != 0)
return;
- }
m->lockedg = nil;
g->lockedm = nil;
+}
+
+void
+runtime·UnlockOSThread(void)
+{
+ m->locked &= ~LockExternal;
+ UnlockOSThread();
+}
+
+void
+runtime·unlockOSThread(void)
+{
+ if(m->locked < LockInternal)
+ runtime·throw("runtime: internal error: misuse of lockOSThread/unlockOSThread");
+ m->locked -= LockInternal;
+ UnlockOSThread();
}
bool
uint32 freglo[16]; // D[i] lsb and F[i]
uint32 freghi[16]; // D[i] msb and F[i+16]
uint32 fflag; // floating point compare flags
+ uint32 locked; // tracking for LockOSThread
M* nextwaitm; // next M waiting for lock
uintptr waitsema; // semaphore for parking on locks
uint32 waitsemacount;
uintptr end[];
};
+// The m->locked word holds a single bit saying whether
+// external calls to LockOSThread are in effect, and then a counter
+// of the internal nesting depth of lockOSThread / unlockOSThread.
+enum
+{
+ LockExternal = 1,
+ LockInternal = 2,
+};
+
struct Stktop
{
// The offsets of these fields are known to (hard-coded in) libmach.
int32 runtime·gomaxprocsfunc(int32 n);
void runtime·procyield(uint32);
void runtime·osyield(void);
-void runtime·LockOSThread(void);
-void runtime·UnlockOSThread(void);
+void runtime·lockOSThread(void);
+void runtime·unlockOSThread(void);
void runtime·mapassign(MapType*, Hmap*, byte*, byte*);
void runtime·mapaccess(MapType*, Hmap*, byte*, byte*, bool*);
t = &runtime·sigtab[sig];
if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Work around Leopard bug that doesn't set FPE_INTDIV.
// Look at instruction to see if it is a divide.
runtime·printf("%s\n", runtime·sigtab[sig].name);
}
- runtime·printf("pc: %x\n", r->eip);
+ runtime·printf("PC=%x\n", r->eip);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
t = &runtime·sigtab[sig];
if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Work around Leopard bug that doesn't set FPE_INTDIV.
// Look at instruction to see if it is a divide.
runtime·printf("%s\n", runtime·sigtab[sig].name);
}
- runtime·printf("pc: %X\n", r->rip);
+ runtime·printf("PC=%X\n", r->rip);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
t = &runtime·sigtab[sig];
if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%X\n", r->mc_eip);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
t = &runtime·sigtab[sig];
if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%X\n", r->mc_rip);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
t = &runtime·sigtab[sig];
if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%x\n", r->r15);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
t = &runtime·sigtab[sig];
if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%X\n", r->eip);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
t = &runtime·sigtab[sig];
if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%X\n", r->rip);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
t = &runtime·sigtab[sig];
if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%x\n", r->arm_pc);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
t = &runtime·sigtab[sig];
if(info->_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Make it look like a call to the signal func.
// We need to pass arguments out of band since
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%X\n", mc->__gregs[REG_EIP]);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
t = &runtime·sigtab[sig];
if(info->_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Make it look like a call to the signal func.
// We need to pass arguments out of band since augmenting the
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%X\n", mc->__gregs[REG_RIP]);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
t = &runtime·sigtab[sig];
if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%X\n", r->sc_eip);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
t = &runtime·sigtab[sig];
if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil)
+ if(gp == nil || gp == m->g0)
goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
runtime·printf("%s\n", runtime·sigtab[sig].name);
runtime·printf("PC=%X\n", r->sc_rip);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
info->ExceptionInformation[0], info->ExceptionInformation[1]);
runtime·printf("PC=%x\n", r->Eip);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
info->ExceptionInformation[0], info->ExceptionInformation[1]);
runtime·printf("PC=%X\n", r->Rip);
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
runtime·printf("\n");
if(runtime·gotraceback()){
void
runtime·traceback(byte *pc0, byte *sp, byte *lr, G *gp)
{
+ if(gp->status == Gsyscall) {
+ // Override signal registers if blocked in system call.
+ pc0 = gp->sched.pc;
+ sp = (byte*)gp->sched.sp;
+ lr = nil;
+ }
runtime·gentraceback(pc0, sp, lr, gp, 0, nil, 100);
}
void
runtime·traceback(byte *pc0, byte *sp, byte*, G *gp)
{
+ if(gp->status == Gsyscall) {
+ // Override signal registers if blocked in system call.
+ pc0 = gp->sched.pc;
+ sp = (byte*)gp->sched.sp;
+ }
runtime·gentraceback(pc0, sp, nil, gp, 0, nil, 100);
}