From: Ian Lance Taylor Date: Wed, 29 Apr 2015 21:31:53 +0000 (+0000) Subject: runtime: Support -buildmode=c-shared. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=081564faed7cc138dfcaa48021cc01a94fd1ba3c;p=gcc.git runtime: Support -buildmode=c-shared. These changes permit using the go tool from the upcoming Go 1.5 release with -buildmode=c-archive to build gccgo code into an archive file that can be linked with a C program. From-SVN: r222594 --- diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 15af3dc1bec..fa4fcaa6404 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -105,7 +105,7 @@ toolexeclib_LTLIBRARIES = libgo-llgo.la toolexeclib_LIBRARIES = libgobegin-llgo.a else toolexeclib_LTLIBRARIES = libgo.la -toolexeclib_LIBRARIES = libgobegin.a libnetgo.a +toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a libnetgo.a endif toolexeclibgo_DATA = \ @@ -2036,6 +2036,11 @@ libgobegin_llgo_a_SOURCES = \ libgobegin_a_CFLAGS = $(AM_CFLAGS) -fPIC libgobegin_llgo_a_CFLAGS = $(AM_CFLAGS) -fPIC +libgolibbegin_a_SOURCES = \ + runtime/go-libmain.c + +libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -fPIC + libnetgo_a_SOURCES = $(go_netgo_files) libnetgo_a_LIBADD = netgo.o @@ -2067,7 +2072,7 @@ BUILDPACKAGE = \ BUILDNETGO = \ $(MKDIR_P) $(@D); \ files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \ - $(GOCOMPILE) -I . -c -fgo-pkgpath=net -o $@ $$files + $(GOCOMPILE) -I . -c -fPIC -fgo-pkgpath=net -o $@ $$files GOTESTFLAGS = GOBENCH = diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 29602d37881..99ffbb27611 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -136,6 +136,10 @@ libgobegin_a_AR = $(AR) $(ARFLAGS) libgobegin_a_LIBADD = am_libgobegin_a_OBJECTS = libgobegin_a-go-main.$(OBJEXT) libgobegin_a_OBJECTS = $(am_libgobegin_a_OBJECTS) +libgolibbegin_a_AR = $(AR) $(ARFLAGS) +libgolibbegin_a_LIBADD = +am_libgolibbegin_a_OBJECTS = libgolibbegin_a-go-libmain.$(OBJEXT) +libgolibbegin_a_OBJECTS = $(am_libgolibbegin_a_OBJECTS) libnetgo_a_AR = $(AR) $(ARFLAGS) libnetgo_a_DEPENDENCIES = netgo.o am__objects_1 = @@ -264,8 +268,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libgobegin_llgo_a_SOURCES) $(libgobegin_a_SOURCES) \ - $(libnetgo_a_SOURCES) $(libgo_llgo_la_SOURCES) \ - $(libgo_la_SOURCES) + $(libgolibbegin_a_SOURCES) $(libnetgo_a_SOURCES) \ + $(libgo_llgo_la_SOURCES) $(libgo_la_SOURCES) MULTISRCTOP = MULTIBUILDTOP = MULTIDIRS = @@ -532,7 +536,7 @@ AM_MAKEFLAGS = \ FLAGS_TO_PASS = $(AM_MAKEFLAGS) @GOC_IS_LLGO_FALSE@toolexeclib_LTLIBRARIES = libgo.la @GOC_IS_LLGO_TRUE@toolexeclib_LTLIBRARIES = libgo-llgo.la -@GOC_IS_LLGO_FALSE@toolexeclib_LIBRARIES = libgobegin.a libnetgo.a +@GOC_IS_LLGO_FALSE@toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a libnetgo.a @GOC_IS_LLGO_TRUE@toolexeclib_LIBRARIES = libgobegin-llgo.a toolexeclibgo_DATA = \ bufio.gox \ @@ -2102,6 +2106,10 @@ libgobegin_llgo_a_SOURCES = \ # Use -fPIC for libgobegin so that it can be put in a PIE. libgobegin_a_CFLAGS = $(AM_CFLAGS) -fPIC libgobegin_llgo_a_CFLAGS = $(AM_CFLAGS) -fPIC +libgolibbegin_a_SOURCES = \ + runtime/go-libmain.c + +libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -fPIC libnetgo_a_SOURCES = $(go_netgo_files) libnetgo_a_LIBADD = netgo.o LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) @@ -2132,7 +2140,7 @@ BUILDPACKAGE = \ BUILDNETGO = \ $(MKDIR_P) $(@D); \ files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \ - $(GOCOMPILE) -I . -c -fgo-pkgpath=net -o $@ $$files + $(GOCOMPILE) -I . -c -fPIC -fgo-pkgpath=net -o $@ $$files GOTESTFLAGS = GOBENCH = @@ -2421,6 +2429,10 @@ libgobegin.a: $(libgobegin_a_OBJECTS) $(libgobegin_a_DEPENDENCIES) -rm -f libgobegin.a $(libgobegin_a_AR) libgobegin.a $(libgobegin_a_OBJECTS) $(libgobegin_a_LIBADD) $(RANLIB) libgobegin.a +libgolibbegin.a: $(libgolibbegin_a_OBJECTS) $(libgolibbegin_a_DEPENDENCIES) + -rm -f libgolibbegin.a + $(libgolibbegin_a_AR) libgolibbegin.a $(libgolibbegin_a_OBJECTS) $(libgolibbegin_a_LIBADD) + $(RANLIB) libgolibbegin.a libnetgo.a: $(libnetgo_a_OBJECTS) $(libnetgo_a_DEPENDENCIES) -rm -f libnetgo.a $(libnetgo_a_AR) libnetgo.a $(libnetgo_a_OBJECTS) $(libnetgo_a_LIBADD) @@ -2546,6 +2558,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lfstack.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgobegin_a-go-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgobegin_llgo_a-go-main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgolibbegin_a-go-libmain.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock_futex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock_sema.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@ @@ -2631,6 +2644,20 @@ libgobegin_a-go-main.obj: runtime/go-main.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgobegin_a_CFLAGS) $(CFLAGS) -c -o libgobegin_a-go-main.obj `if test -f 'runtime/go-main.c'; then $(CYGPATH_W) 'runtime/go-main.c'; else $(CYGPATH_W) '$(srcdir)/runtime/go-main.c'; fi` +libgolibbegin_a-go-libmain.o: runtime/go-libmain.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgolibbegin_a_CFLAGS) $(CFLAGS) -MT libgolibbegin_a-go-libmain.o -MD -MP -MF $(DEPDIR)/libgolibbegin_a-go-libmain.Tpo -c -o libgolibbegin_a-go-libmain.o `test -f 'runtime/go-libmain.c' || echo '$(srcdir)/'`runtime/go-libmain.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libgolibbegin_a-go-libmain.Tpo $(DEPDIR)/libgolibbegin_a-go-libmain.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-libmain.c' object='libgolibbegin_a-go-libmain.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgolibbegin_a_CFLAGS) $(CFLAGS) -c -o libgolibbegin_a-go-libmain.o `test -f 'runtime/go-libmain.c' || echo '$(srcdir)/'`runtime/go-libmain.c + +libgolibbegin_a-go-libmain.obj: runtime/go-libmain.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgolibbegin_a_CFLAGS) $(CFLAGS) -MT libgolibbegin_a-go-libmain.obj -MD -MP -MF $(DEPDIR)/libgolibbegin_a-go-libmain.Tpo -c -o libgolibbegin_a-go-libmain.obj `if test -f 'runtime/go-libmain.c'; then $(CYGPATH_W) 'runtime/go-libmain.c'; else $(CYGPATH_W) '$(srcdir)/runtime/go-libmain.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libgolibbegin_a-go-libmain.Tpo $(DEPDIR)/libgolibbegin_a-go-libmain.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-libmain.c' object='libgolibbegin_a-go-libmain.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgolibbegin_a_CFLAGS) $(CFLAGS) -c -o libgolibbegin_a-go-libmain.obj `if test -f 'runtime/go-libmain.c'; then $(CYGPATH_W) 'runtime/go-libmain.c'; else $(CYGPATH_W) '$(srcdir)/runtime/go-libmain.c'; fi` + go-append.lo: runtime/go-append.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-append.lo -MD -MP -MF $(DEPDIR)/go-append.Tpo -c -o go-append.lo `test -f 'runtime/go-append.c' || echo '$(srcdir)/'`runtime/go-append.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-append.Tpo $(DEPDIR)/go-append.Plo diff --git a/libgo/runtime/go-cgo.c b/libgo/runtime/go-cgo.c index 2b7baa4df9c..a36eac92704 100644 --- a/libgo/runtime/go-cgo.c +++ b/libgo/runtime/go-cgo.c @@ -8,6 +8,9 @@ #include "go-alloc.h" #include "interface.h" #include "go-panic.h" +#include "go-type.h" + +extern void __go_receive (ChanType *, Hchan *, byte *); /* Prepare to call from code written in Go to code written in C or C++. This takes the current goroutine out of the Go scheduler, as @@ -86,6 +89,15 @@ syscall_cgocallback () runtime_exitsyscall (); + if (runtime_g ()->ncgo == 0) + { + /* The C call to Go came from a thread not currently running any + Go. In the case of -buildmode=c-archive or c-shared, this + call may be coming in before package initialization is + complete. Wait until it is. */ + __go_receive (NULL, runtime_main_init_done, NULL); + } + mp = runtime_m (); if (mp->needextram) { @@ -177,3 +189,65 @@ _cgo_panic (const char *p) __go_panic (e); } + +/* Used for _cgo_wait_runtime_init_done. This is based on code in + runtime/cgo/gcc_libinit.c in the master library. */ + +static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER; +static _Bool runtime_init_done; + +/* This is called by exported cgo functions to ensure that the runtime + has been initialized before we enter the function. This is needed + when building with -buildmode=c-archive or similar. */ + +void +_cgo_wait_runtime_init_done (void) +{ + int err; + + if (__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE)) + return; + + err = pthread_mutex_lock (&runtime_init_mu); + if (err != 0) + abort (); + while (!__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE)) + { + err = pthread_cond_wait (&runtime_init_cond, &runtime_init_mu); + if (err != 0) + abort (); + } + err = pthread_mutex_unlock (&runtime_init_mu); + if (err != 0) + abort (); +} + +/* This is called by runtime_main after the Go runtime is + initialized. */ + +void +_cgo_notify_runtime_init_done (void) +{ + int err; + + err = pthread_mutex_lock (&runtime_init_mu); + if (err != 0) + abort (); + __atomic_store_n (&runtime_init_done, 1, __ATOMIC_RELEASE); + err = pthread_cond_broadcast (&runtime_init_cond); + if (err != 0) + abort (); + err = pthread_mutex_unlock (&runtime_init_mu); + if (err != 0) + abort (); +} + +// runtime_iscgo is set to true if some cgo code is linked in. +// This is done by a constructor in the cgo generated code. +_Bool runtime_iscgo; + +// runtime_cgoHasExtraM is set on startup when an extra M is created +// for cgo. The extra M must be created before any C/C++ code calls +// cgocallback. +_Bool runtime_cgoHasExtraM; diff --git a/libgo/runtime/go-libmain.c b/libgo/runtime/go-libmain.c new file mode 100644 index 00000000000..f578aab43b7 --- /dev/null +++ b/libgo/runtime/go-libmain.c @@ -0,0 +1,114 @@ +/* go-libmain.c -- the startup function for a Go library. + + Copyright 2015 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 "config.h" + +#include +#include +#include +#include +#include + +#include "runtime.h" +#include "go-alloc.h" +#include "array.h" +#include "arch.h" +#include "malloc.h" + +/* This is used when building a standalone Go library using the Go + command's -buildmode=c-archive or -buildmode=c-shared option. It + starts up the Go code as a global constructor but does not take any + other action. The main program is written in some other language + and calls exported Go functions as needed. */ + +static void die (const char *, int); +static void initfn (int, char **, char **); +static void *gostart (void *); + +/* Used to pass arguments to the thread that runs the Go startup. */ + +struct args { + int argc; + char **argv; +}; + +/* We use .init_array so that we can get the command line arguments. + This obviously assumes .init_array support; different systems may + require other approaches. */ + +typedef void (*initarrayfn) (int, char **, char **); + +static initarrayfn initarray[1] +__attribute__ ((section (".init_array"), used)) = + { initfn }; + +/* This function is called at program startup time. It starts a new + thread to do the actual Go startup, so that program startup is not + paused waiting for the Go initialization functions. Exported cgo + functions will wait for initialization to complete if + necessary. */ + +static void +initfn (int argc, char **argv, char** env __attribute__ ((unused))) +{ + int err; + pthread_attr_t attr; + struct args *a; + pthread_t tid; + + a = (struct args *) malloc (sizeof *a); + if (a == NULL) + die ("malloc", errno); + a->argc = argc; + a->argv = argv; + + err = pthread_attr_init (&attr); + if (err != 0) + die ("pthread_attr_init", err); + err = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + if (err != 0) + die ("pthread_attr_setdetachstate", err); + + err = pthread_create (&tid, &attr, gostart, (void *) a); + if (err != 0) + die ("pthread_create", err); + + err = pthread_attr_destroy (&attr); + if (err != 0) + die ("pthread_attr_destroy", err); +} + +/* Start up the Go runtime. */ + +static void * +gostart (void *arg) +{ + struct args *a = (struct args *) arg; + + runtime_isarchive = true; + + if (runtime_isstarted) + return NULL; + runtime_isstarted = true; + + runtime_check (); + runtime_args (a->argc, (byte **) a->argv); + runtime_osinit (); + runtime_schedinit (); + __go_go (runtime_main, NULL); + runtime_mstart (runtime_m ()); + abort (); +} + +/* If something goes wrong during program startup, crash. There is no + way to report failure and nobody to whom to report it. */ + +static void +die (const char *fn, int err) +{ + fprintf (stderr, "%s: %d\n", fn, err); + exit (EXIT_FAILURE); +} diff --git a/libgo/runtime/go-main.c b/libgo/runtime/go-main.c index 77233d3239c..8e9ceab9f3a 100644 --- a/libgo/runtime/go-main.c +++ b/libgo/runtime/go-main.c @@ -35,6 +35,12 @@ extern char **environ; int main (int argc, char **argv) { + runtime_isarchive = false; + + if (runtime_isstarted) + return NULL; + runtime_isstarted = true; + runtime_check (); runtime_args (argc, (byte **) argv); runtime_osinit (); diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index da0f2ed3a75..babad01ea95 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -372,7 +372,6 @@ enum Sched runtime_sched; int32 runtime_gomaxprocs; uint32 runtime_needextram = 1; -bool runtime_iscgo = true; M runtime_m0; G runtime_g0; // idle goroutine for m0 G* runtime_lastg; @@ -389,6 +388,8 @@ G** runtime_allg; uintptr runtime_allglen; static uintptr allgcap; +bool runtime_isarchive; + void* runtime_mstart(void*); static void runqput(P*, G*); static G* runqget(P*); @@ -428,6 +429,8 @@ static bool preemptall(void); static bool exitsyscallfast(void); static void allgadd(G*); +bool runtime_isstarted; + // The bootstrap sequence is: // // call osinit @@ -490,6 +493,64 @@ runtime_schedinit(void) extern void main_init(void) __asm__ (GOSYM_PREFIX "__go_init_main"); extern void main_main(void) __asm__ (GOSYM_PREFIX "main.main"); +// Used to determine the field alignment. + +struct field_align +{ + char c; + Hchan *p; +}; + +// main_init_done is a signal used by cgocallbackg that initialization +// has been completed. It is made before _cgo_notify_runtime_init_done, +// so all cgo calls can rely on it existing. When main_init is +// complete, it is closed, meaning cgocallbackg can reliably receive +// from it. +Hchan *runtime_main_init_done; + +// The chan bool type, for runtime_main_init_done. + +extern const struct __go_type_descriptor bool_type_descriptor + __asm__ (GOSYM_PREFIX "__go_tdn_bool"); + +static struct __go_channel_type chan_bool_type_descriptor = + { + /* __common */ + { + /* __code */ + GO_CHAN, + /* __align */ + __alignof (Hchan *), + /* __field_align */ + offsetof (struct field_align, p) - 1, + /* __size */ + sizeof (Hchan *), + /* __hash */ + 0, /* This value doesn't matter. */ + /* __hashfn */ + __go_type_hash_error, + /* __equalfn */ + __go_type_equal_error, + /* __gc */ + NULL, /* This value doesn't matter */ + /* __reflection */ + NULL, /* This value doesn't matter */ + /* __uncommon */ + NULL, + /* __pointer_to_this */ + NULL, + /* __zero */ + NULL /* This value doesn't matter */ + }, + /* __element_type */ + &bool_type_descriptor, + /* __dir */ + CHANNEL_BOTH_DIR + }; + +extern Hchan *__go_new_channel (ChanType *, uintptr); +extern void closechan(Hchan *) __asm__ (GOSYM_PREFIX "runtime.closechan"); + static void initDone(void *arg __attribute__ ((unused))) { runtime_unlockOSThread(); @@ -535,8 +596,15 @@ runtime_main(void* dummy __attribute__((unused))) if(m != &runtime_m0) runtime_throw("runtime_main not on m0"); __go_go(runtime_MHeap_Scavenger, nil); + + runtime_main_init_done = __go_new_channel(&chan_bool_type_descriptor, 0); + + _cgo_notify_runtime_init_done(); + main_init(); + closechan(runtime_main_init_done); + if(g->defer != &d || d.__pfn != initDone) runtime_throw("runtime: bad defer entry after init"); g->defer = d.__next; @@ -547,6 +615,14 @@ runtime_main(void* dummy __attribute__((unused))) // roots. mstats.enablegc = 1; + if(runtime_isarchive) { + // This is not a complete program, but is instead a + // library built using -buildmode=c-archive or + // c-shared. Now that we are initialized, there is + // nothing further to do. + return; + } + main_main(); // Make racy client program work: if panicking on @@ -1011,8 +1087,14 @@ runtime_mstart(void* mp) // Install signal handlers; after minit so that minit can // prepare the thread to be able to handle the signals. - if(m == &runtime_m0) + if(m == &runtime_m0) { + if(runtime_iscgo && !runtime_cgoHasExtraM) { + runtime_cgoHasExtraM = true; + runtime_newextram(); + runtime_needextram = 0; + } runtime_initsig(); + } if(m->mstartfn) m->mstartfn(); @@ -2747,6 +2829,13 @@ checkdead(void) int32 run, grunning, s; uintptr i; + // For -buildmode=c-shared or -buildmode=c-archive it's OK if + // there are no running goroutines. The calling program is + // assumed to be running. + if(runtime_isarchive) { + return; + } + // -1 for sysmon run = runtime_sched.mcount - runtime_sched.nmidle - runtime_sched.nmidlelocked - 1 - countextra(); if(run > 0) @@ -3332,6 +3421,7 @@ void runtime_proc_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj)) { enqueue1(wbufp, (Obj){(byte*)&runtime_sched, sizeof runtime_sched, 0}); + enqueue1(wbufp, (Obj){(byte*)&runtime_main_init_done, sizeof runtime_main_init_done, 0}); } // Return whether we are waiting for a GC. This gc toolchain uses diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 515ae58ff85..b9264236227 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -509,6 +509,9 @@ extern uint32 runtime_Hchansize; extern DebugVars runtime_debug; extern uintptr runtime_maxstacksize; +extern bool runtime_isstarted; +extern bool runtime_isarchive; + /* * common functions and data */ @@ -845,3 +848,9 @@ struct time_now_ret struct time_now_ret now() __asm__ (GOSYM_PREFIX "time.now") __attribute__ ((no_split_stack)); + +extern void _cgo_wait_runtime_init_done (void); +extern void _cgo_notify_runtime_init_done (void); +extern _Bool runtime_iscgo; +extern _Bool runtime_cgoHasExtraM; +extern Hchan *runtime_main_init_done;