As another step toward multiplexing goroutines onto OS threads, this patch adopts the g variable used in the other Go's compiler runtime support library. g is a thread-local global which holds goroutine-specific information, as opposed to the existing thread-local global m which holds thread-specific information. The only goroutine-specific information at present is the panic/defer stuff, which was formerly stored in __go_panic_defer. This patch essentially replaces __go_panic_defer. Much of the patch is mechanical.
The use of g0 is temporary until full support for multiplexing goroutines goes in. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline. Ian
diff -r b9bf54c65ba3 libgo/Makefile.am --- a/libgo/Makefile.am Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/Makefile.am Fri Nov 11 12:57:37 2011 -0800 @@ -434,7 +434,6 @@ runtime/go-new.c \ runtime/go-note.c \ runtime/go-panic.c \ - runtime/go-panic-defer.c \ runtime/go-print.c \ runtime/go-rand.c \ runtime/go-rec-big.c \ diff -r b9bf54c65ba3 libgo/runtime/go-defer.c --- a/libgo/runtime/go-defer.c Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/runtime/go-defer.c Fri Nov 11 12:57:37 2011 -0800 @@ -6,6 +6,7 @@ #include <stddef.h> +#include "runtime.h" #include "go-alloc.h" #include "go-panic.h" #include "go-defer.h" @@ -17,18 +18,14 @@ { struct __go_defer_stack *n; - if (__go_panic_defer == NULL) - __go_panic_defer = ((struct __go_panic_defer_struct *) - __go_alloc (sizeof (struct __go_panic_defer_struct))); - n = (struct __go_defer_stack *) __go_alloc (sizeof (struct __go_defer_stack)); - n->__next = __go_panic_defer->__defer; + n->__next = g->defer; n->__frame = frame; - n->__panic = __go_panic_defer->__panic; + n->__panic = g->panic; n->__pfn = pfn; n->__arg = arg; n->__retaddr = NULL; - __go_panic_defer->__defer = n; + g->defer = n; } /* This function is called when we want to undefer the stack. */ @@ -36,22 +33,19 @@ void __go_undefer (_Bool *frame) { - if (__go_panic_defer == NULL) - return; - while (__go_panic_defer->__defer != NULL - && __go_panic_defer->__defer->__frame == frame) + while (g->defer != NULL && g->defer->__frame == frame) { struct __go_defer_stack *d; void (*pfn) (void *); - d = __go_panic_defer->__defer; + d = g->defer; pfn = d->__pfn; d->__pfn = NULL; if (pfn != NULL) (*pfn) (d->__arg); - __go_panic_defer->__defer = d->__next; + g->defer = d->__next; __go_free (d); /* Since we are executing a defer function here, we know we are @@ -69,7 +63,7 @@ _Bool __go_set_defer_retaddr (void *retaddr) { - if (__go_panic_defer != NULL && __go_panic_defer->__defer != NULL) - __go_panic_defer->__defer->__retaddr = retaddr; + if (g->defer != NULL) + g->defer->__retaddr = retaddr; return 0; } diff -r b9bf54c65ba3 libgo/runtime/go-deferred-recover.c --- a/libgo/runtime/go-deferred-recover.c Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/runtime/go-deferred-recover.c Fri Nov 11 12:57:37 2011 -0800 @@ -6,6 +6,7 @@ #include <stddef.h> +#include "runtime.h" #include "go-panic.h" #include "go-defer.h" @@ -78,9 +79,7 @@ struct __go_empty_interface __go_deferred_recover () { - if (__go_panic_defer == NULL - || __go_panic_defer->__defer == NULL - || __go_panic_defer->__defer->__panic != __go_panic_defer->__panic) + if (g->defer == NULL || g->defer->__panic != g->panic) { struct __go_empty_interface ret; diff -r b9bf54c65ba3 libgo/runtime/go-go.c --- a/libgo/runtime/go-go.c Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/runtime/go-go.c Fri Nov 11 12:57:37 2011 -0800 @@ -115,6 +115,7 @@ any code from here to thread exit must not assume that m is valid. */ m = NULL; + g = NULL; i = pthread_mutex_unlock (&__go_thread_ids_lock); __go_assert (i == 0); @@ -135,10 +136,11 @@ #ifdef __rtems__ __wrap_rtems_task_variable_add ((void **) &m); - __wrap_rtems_task_variable_add ((void **) &__go_panic_defer); + __wrap_rtems_task_variable_add ((void **) &g); #endif m = newm; + g = m->curg; pthread_cleanup_push (remove_current_thread, NULL); @@ -230,6 +232,9 @@ newm->list_entry = list_entry; + newm->curg = __go_alloc (sizeof (G)); + newm->curg->m = newm; + newm->id = __sync_fetch_and_add (&mcount, 1); newm->fastrand = 0x49f6428aUL + newm->id; @@ -299,9 +304,6 @@ } #endif - /* FIXME: Perhaps we should just move __go_panic_defer into M. */ - m->gc_panic_defer = __go_panic_defer; - /* Tell the garbage collector that we are ready by posting to the semaphore. */ i = sem_post (&__go_thread_ready_sem); @@ -433,10 +435,6 @@ --c; } - /* The gc_panic_defer field should now be set for all M's except the - one in this thread. Set this one now. */ - m->gc_panic_defer = __go_panic_defer; - /* Leave with __go_thread_ids_lock held. */ } diff -r b9bf54c65ba3 libgo/runtime/go-main.c --- a/libgo/runtime/go-main.c Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/runtime/go-main.c Fri Nov 11 12:57:37 2011 -0800 @@ -48,6 +48,10 @@ int i; struct __go_string *values; + m = &runtime_m0; + g = &runtime_g0; + m->curg = g; + g->m = m; runtime_mallocinit (); runtime_cpuprofinit (); __go_gc_goroutine_init (&argc); diff -r b9bf54c65ba3 libgo/runtime/go-panic-defer.c --- a/libgo/runtime/go-panic-defer.c Fri Nov 04 16:02:15 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -/* go-panic-stack.c -- The panic/defer stack. - - Copyright 2010 The Go Authors. All rights reserved. - Use of this source code is governed by a BSD-style - license that can be found in the LICENSE file. */ - -#include "go-panic.h" - -#ifdef __rtems__ -#define __thread -#endif - -__thread struct __go_panic_defer_struct *__go_panic_defer; diff -r b9bf54c65ba3 libgo/runtime/go-panic.c --- a/libgo/runtime/go-panic.c Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/runtime/go-panic.c Fri Nov 11 12:57:37 2011 -0800 @@ -41,14 +41,10 @@ { struct __go_panic_stack *n; - if (__go_panic_defer == NULL) - __go_panic_defer = ((struct __go_panic_defer_struct *) - __go_alloc (sizeof (struct __go_panic_defer_struct))); - n = (struct __go_panic_stack *) __go_alloc (sizeof (struct __go_panic_stack)); n->__arg = arg; - n->__next = __go_panic_defer->__panic; - __go_panic_defer->__panic = n; + n->__next = g->panic; + g->panic = n; /* Run all the defer functions. */ @@ -57,7 +53,7 @@ struct __go_defer_stack *d; void (*pfn) (void *); - d = __go_panic_defer->__defer; + d = g->defer; if (d == NULL) break; @@ -73,7 +69,7 @@ /* Some defer function called recover. That means that we should stop running this panic. */ - __go_panic_defer->__panic = n->__next; + g->panic = n->__next; __go_free (n); /* Now unwind the stack by throwing an exception. The @@ -96,13 +92,13 @@ *d->__frame = 0; } - __go_panic_defer->__defer = d->__next; + g->defer = d->__next; __go_free (d); } /* The panic was not recovered. */ - __printpanics (__go_panic_defer->__panic); + __printpanics (g->panic); /* FIXME: We should dump a call stack here. */ abort (); diff -r b9bf54c65ba3 libgo/runtime/go-panic.h --- a/libgo/runtime/go-panic.h Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/runtime/go-panic.h Fri Nov 11 12:57:37 2011 -0800 @@ -31,36 +31,6 @@ _Bool __is_foreign; }; -/* The panic and defer stacks, grouped together into a single thread - local variable for convenience for systems without TLS. */ - -struct __go_panic_defer_struct -{ - /* The list of defers to execute. */ - struct __go_defer_stack *__defer; - - /* The list of currently active panics. There will be more than one - if a deferred function calls panic. */ - struct __go_panic_stack *__panic; - - /* The current exception being thrown when unwinding after a call to - panic . This is really struct _UnwindException *. */ - void *__exception; - - /* Whether the current exception is from some other language. */ - _Bool __is_foreign; -}; - -#ifdef __rtems__ -#define __thread -#endif - -extern __thread struct __go_panic_defer_struct *__go_panic_defer; - -#ifdef __rtems__ -#undef __thread -#endif - extern void __go_panic (struct __go_empty_interface) __attribute__ ((noreturn)); diff -r b9bf54c65ba3 libgo/runtime/go-recover.c --- a/libgo/runtime/go-recover.c Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/runtime/go-recover.c Fri Nov 11 12:57:37 2011 -0800 @@ -4,6 +4,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ +#include "runtime.h" #include "interface.h" #include "go-panic.h" #include "go-defer.h" @@ -21,9 +22,7 @@ const char* ret; const char* dret; - if (__go_panic_defer == NULL) - return 0; - d = __go_panic_defer->__defer; + d = g->defer; if (d == NULL) return 0; @@ -31,7 +30,7 @@ of the panic stack. We do not want to recover it if that panic was on the top of the panic stack when this function was deferred. */ - if (d->__panic == __go_panic_defer->__panic) + if (d->__panic == g->panic) return 0; /* D->__RETADDR is the address of a label immediately following the @@ -53,9 +52,7 @@ { struct __go_panic_stack *p; - if (__go_panic_defer == NULL - || __go_panic_defer->__panic == NULL - || __go_panic_defer->__panic->__was_recovered) + if (g->panic == NULL || g->panic->__was_recovered) { struct __go_empty_interface ret; @@ -63,7 +60,7 @@ ret.__object = NULL; return ret; } - p = __go_panic_defer->__panic; + p = g->panic; p->__was_recovered = 1; return p->__arg; } diff -r b9bf54c65ba3 libgo/runtime/go-unwind.c --- a/libgo/runtime/go-unwind.c Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/runtime/go-unwind.c Fri Nov 11 12:57:37 2011 -0800 @@ -13,6 +13,7 @@ #define NO_SIZE_OF_ENCODED_VALUE #include "unwind-pe.h" +#include "runtime.h" #include "go-alloc.h" #include "go-defer.h" #include "go-panic.h" @@ -48,12 +49,12 @@ { struct _Unwind_Exception *hdr; - if (__go_panic_defer == NULL) + if (g == NULL) { /* Some other language has thrown an exception. We know there are no defer handlers, so there is nothing to do. */ } - else if (__go_panic_defer->__is_foreign) + else if (g->is_foreign) { struct __go_panic_stack *n; _Bool was_recovered; @@ -69,20 +70,20 @@ n->__arg.__object = NULL; n->__was_recovered = 0; n->__is_foreign = 1; - n->__next = __go_panic_defer->__panic; - __go_panic_defer->__panic = n; + n->__next = g->panic; + g->panic = n; while (1) { struct __go_defer_stack *d; void (*pfn) (void *); - d = __go_panic_defer->__defer; + d = g->defer; if (d == NULL || d->__frame != frame || d->__pfn == NULL) break; pfn = d->__pfn; - __go_panic_defer->__defer = d->__next; + g->defer = d->__next; (*pfn) (d->__arg); @@ -97,7 +98,7 @@ } was_recovered = n->__was_recovered; - __go_panic_defer->__panic = n->__next; + g->panic = n->__next; __go_free (n); if (was_recovered) @@ -110,17 +111,17 @@ /* We are panicing through this function. */ *frame = 0; } - else if (__go_panic_defer->__defer != NULL - && __go_panic_defer->__defer->__pfn == NULL - && __go_panic_defer->__defer->__frame == frame) + else if (g->defer != NULL + && g->defer->__pfn == NULL + && g->defer->__frame == frame) { struct __go_defer_stack *d; /* This is the defer function which called recover. Simply return to stop the stack unwind, and let the Go code continue to execute. */ - d = __go_panic_defer->__defer; - __go_panic_defer->__defer = d->__next; + d = g->defer; + g->defer = d->__next; __go_free (d); /* We are returning from this function. */ @@ -132,7 +133,7 @@ /* This is some other defer function. It was already run by the call to panic, or just above. Rethrow the exception. */ - hdr = (struct _Unwind_Exception *) __go_panic_defer->__exception; + hdr = (struct _Unwind_Exception *) g->exception; #ifdef LIBGO_SJLJ_EXCEPTIONS _Unwind_SjLj_Resume_or_Rethrow (hdr); @@ -163,7 +164,7 @@ sizeof hdr->exception_class); hdr->exception_cleanup = NULL; - __go_panic_defer->__exception = hdr; + g->exception = hdr; #ifdef __USING_SJLJ_EXCEPTIONS__ _Unwind_SjLj_RaiseException (hdr); @@ -413,17 +414,17 @@ return _URC_HANDLER_FOUND; } - /* It's possible for __go_panic_defer to be NULL here for an - exception thrown by a language other than Go. */ - if (__go_panic_defer == NULL) + /* It's possible for g to be NULL here for an exception thrown by a + language other than Go. */ + if (g == NULL) { if (!is_foreign) abort (); } else { - __go_panic_defer->__exception = ue_header; - __go_panic_defer->__is_foreign = is_foreign; + g->exception = ue_header; + g->is_foreign = is_foreign; } _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), diff -r b9bf54c65ba3 libgo/runtime/mgc0.c --- a/libgo/runtime/mgc0.c Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/runtime/mgc0.c Fri Nov 11 12:57:37 2011 -0800 @@ -652,7 +652,8 @@ } } - scan((byte*)&m0, sizeof m0); + scan((byte*)&runtime_m0, sizeof runtime_m0); + scan((byte*)&runtime_g0, sizeof runtime_g0); scan((byte*)&finq, sizeof finq); runtime_MProf_Mark(scan); diff -r b9bf54c65ba3 libgo/runtime/proc.c --- a/libgo/runtime/proc.c Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/runtime/proc.c Fri Nov 11 12:57:37 2011 -0800 @@ -8,13 +8,15 @@ typedef struct Sched Sched; -M m0; +G runtime_g0; +M runtime_m0; #ifdef __rtems__ #define __thread #endif -__thread M *m = &m0; +__thread G *g; +__thread M *m; static struct { Lock; diff -r b9bf54c65ba3 libgo/runtime/runtime.h --- a/libgo/runtime/runtime.h Fri Nov 04 16:02:15 2011 -0700 +++ b/libgo/runtime/runtime.h Fri Nov 11 12:57:37 2011 -0800 @@ -48,11 +48,15 @@ typedef uint8 bool; typedef uint8 byte; +typedef struct G G; typedef struct M M; typedef struct MCache MCache; typedef struct FixAlloc FixAlloc; typedef struct Lock Lock; +typedef struct __go_defer_stack Defer; +typedef struct __go_panic_stack Panic; + /* We use mutexes for locks. 6g uses futexes directly, and perhaps someday we will do that too. */ @@ -76,9 +80,11 @@ #define __thread #endif +extern __thread G* g; extern __thread M* m; -extern M m0; +extern M runtime_m0; +extern G runtime_g0; #ifdef __rtems__ #undef __thread @@ -94,8 +100,34 @@ /* Structures. */ +struct G +{ + Defer* defer; + Panic* panic; + void* exception; // current exception being thrown + bool is_foreign; // whether current exception from other language + byte* entry; // initial function + G* alllink; // on allg + void* param; // passed parameter on wakeup + int16 status; + int32 goid; + int8* waitreason; // if status==Gwaiting + G* schedlink; + bool readyonstop; + bool ispanic; + M* m; // for debuggers, but offset not hard-coded + M* lockedm; + M* idlem; + // int32 sig; + // uintptr sigcode0; + // uintptr sigcode1; + // uintptr sigpc; + // uintptr gopc; // pc of go statement that created this goroutine +}; + struct M { + G* curg; // current running goroutine int32 id; int32 mallocing; int32 gcing; @@ -117,7 +149,6 @@ void *gc_next_segment; void *gc_next_sp; void *gc_initial_sp; - struct __go_panic_defer_struct *gc_panic_defer; }; /* Macros. */