This patch to libgo fixes the handling of the deferring of the unlock thread at program startup. The code was incorrectly freeing a stack object. This patch also cleans up some cases of freeing a defer block to avoid doing it when there is no Go context available. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian
diff -r f3ec8ff457ec -r 9931ebbea550 libgo/runtime/go-defer.c --- a/libgo/runtime/go-defer.c Thu Dec 12 11:23:56 2013 -0800 +++ b/libgo/runtime/go-defer.c Thu Dec 12 12:13:34 2013 -0800 @@ -28,6 +28,7 @@ n->__arg = arg; n->__retaddr = NULL; n->__makefunc_can_recover = 0; + n->__free = 1; g->defer = n; } @@ -59,7 +60,7 @@ have a memory context. Don't try to free anything in that case--the GC will release it later. */ m = runtime_m (); - if (m != NULL && m->mcache != NULL) + if (m != NULL && m->mcache != NULL && d->__free) __go_free (d); /* Since we are executing a defer function here, we know we are diff -r f3ec8ff457ec -r 9931ebbea550 libgo/runtime/go-defer.h --- a/libgo/runtime/go-defer.h Thu Dec 12 11:23:56 2013 -0800 +++ b/libgo/runtime/go-defer.h Thu Dec 12 12:13:34 2013 -0800 @@ -40,4 +40,8 @@ function will be somewhere in libffi, so __retaddr is not useful. */ _Bool __makefunc_can_recover; + + /* Set to true if this defer stack entry should be freed when + done. */ + _Bool __free; }; diff -r f3ec8ff457ec -r 9931ebbea550 libgo/runtime/go-panic.c --- a/libgo/runtime/go-panic.c Thu Dec 12 11:23:56 2013 -0800 +++ b/libgo/runtime/go-panic.c Thu Dec 12 12:13:34 2013 -0800 @@ -102,7 +102,7 @@ have a memory context. Don't try to free anything in that case--the GC will release it later. */ m = runtime_m (); - if (m != NULL && m->mcache != NULL) + if (m != NULL && m->mcache != NULL && d->__free) __go_free (d); } diff -r f3ec8ff457ec -r 9931ebbea550 libgo/runtime/go-unwind.c --- a/libgo/runtime/go-unwind.c Thu Dec 12 11:23:56 2013 -0800 +++ b/libgo/runtime/go-unwind.c Thu Dec 12 12:13:34 2013 -0800 @@ -80,6 +80,7 @@ { struct __go_defer_stack *d; void (*pfn) (void *); + M *m; d = g->defer; if (d == NULL || d->__frame != frame || d->__pfn == NULL) @@ -90,7 +91,9 @@ (*pfn) (d->__arg); - __go_free (d); + m = runtime_m (); + if (m != NULL && m->mcache != NULL && d->__free) + __go_free (d); if (n->__was_recovered) { @@ -119,13 +122,17 @@ && g->defer->__frame == frame) { struct __go_defer_stack *d; + M *m; /* This is the defer function which called recover. Simply return to stop the stack unwind, and let the Go code continue to execute. */ d = g->defer; g->defer = d->__next; - __go_free (d); + + m = runtime_m (); + if (m != NULL && m->mcache != NULL && d->__free) + __go_free (d); /* We are returning from this function. */ *frame = 1; diff -r f3ec8ff457ec -r 9931ebbea550 libgo/runtime/panic.c --- a/libgo/runtime/panic.c Thu Dec 12 11:23:56 2013 -0800 +++ b/libgo/runtime/panic.c Thu Dec 12 12:13:34 2013 -0800 @@ -28,7 +28,8 @@ d->__pfn = nil; if (pfn != nil) (*pfn)(d->__arg); - runtime_free(d); + if (d->__free) + runtime_free(d); } } diff -r f3ec8ff457ec -r 9931ebbea550 libgo/runtime/proc.c --- a/libgo/runtime/proc.c Thu Dec 12 11:23:56 2013 -0800 +++ b/libgo/runtime/proc.c Thu Dec 12 12:13:34 2013 -0800 @@ -541,6 +541,7 @@ d.__retaddr = nil; d.__makefunc_can_recover = 0; d.__frame = &frame; + d.__free = 0; g->defer = &d; if(m != &runtime_m0)