runtime: Support -buildmode=c-shared.
authorIan Lance Taylor <ian@gcc.gnu.org>
Wed, 29 Apr 2015 21:31:53 +0000 (21:31 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 29 Apr 2015 21:31:53 +0000 (21:31 +0000)
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

libgo/Makefile.am
libgo/Makefile.in
libgo/runtime/go-cgo.c
libgo/runtime/go-libmain.c [new file with mode: 0644]
libgo/runtime/go-main.c
libgo/runtime/proc.c
libgo/runtime/runtime.h

index 15af3dc1bec98c8fa803052b6fb2630d61cb6f31..fa4fcaa6404e581624a86c2e0cf9d7a2738cdf1c 100644 (file)
@@ -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 = 
index 29602d378815c452094c40b34187b309f22381e8..99ffbb276118264bad688990646cb9bb49707ea7 100644 (file)
@@ -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
index 2b7baa4df9c1c0a6013227d06674646adbcaf185..a36eac92704eb55e1680495559f0806ec1805bf1 100644 (file)
@@ -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 (file)
index 0000000..f578aab
--- /dev/null
@@ -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 <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#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);
+}
index 77233d3239c1fe96419c92ac773f27ea3cf5bf52..8e9ceab9f3a4531d6a2c2d5e0a1086c5d3cf8b9d 100644 (file)
@@ -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 ();
index da0f2ed3a75ab3a40312eff6647e2d22b7abff77..babad01ea95bcb8168151ac7f1f3a4aa9b39f6d3 100644 (file)
@@ -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
index 515ae58ff85bf02e022ffb51cbef35d6e9937620..b9264236227a532461281a30b9ecc0c7499067f4 100644 (file)
@@ -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;