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 = \
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
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 =
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 =
--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 =
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 \
# 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))
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 =
-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)
@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@
@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
#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
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)
{
__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;
--- /dev/null
+/* 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);
+}
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 ();
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;
uintptr runtime_allglen;
static uintptr allgcap;
+bool runtime_isarchive;
+
void* runtime_mstart(void*);
static void runqput(P*, G*);
static G* runqget(P*);
static bool exitsyscallfast(void);
static void allgadd(G*);
+bool runtime_isstarted;
+
// The bootstrap sequence is:
//
// call osinit
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();
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;
// 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
// 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();
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)
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
extern DebugVars runtime_debug;
extern uintptr runtime_maxstacksize;
+extern bool runtime_isstarted;
+extern bool runtime_isarchive;
+
/*
* common functions and data
*/
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;