mirror of git://gcc.gnu.org/git/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
This commit is contained in:
parent
2f79da78f3
commit
081564faed
|
|
@ -105,7 +105,7 @@ toolexeclib_LTLIBRARIES = libgo-llgo.la
|
||||||
toolexeclib_LIBRARIES = libgobegin-llgo.a
|
toolexeclib_LIBRARIES = libgobegin-llgo.a
|
||||||
else
|
else
|
||||||
toolexeclib_LTLIBRARIES = libgo.la
|
toolexeclib_LTLIBRARIES = libgo.la
|
||||||
toolexeclib_LIBRARIES = libgobegin.a libnetgo.a
|
toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a libnetgo.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
toolexeclibgo_DATA = \
|
toolexeclibgo_DATA = \
|
||||||
|
|
@ -2036,6 +2036,11 @@ libgobegin_llgo_a_SOURCES = \
|
||||||
libgobegin_a_CFLAGS = $(AM_CFLAGS) -fPIC
|
libgobegin_a_CFLAGS = $(AM_CFLAGS) -fPIC
|
||||||
libgobegin_llgo_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_SOURCES = $(go_netgo_files)
|
||||||
libnetgo_a_LIBADD = netgo.o
|
libnetgo_a_LIBADD = netgo.o
|
||||||
|
|
||||||
|
|
@ -2067,7 +2072,7 @@ BUILDPACKAGE = \
|
||||||
BUILDNETGO = \
|
BUILDNETGO = \
|
||||||
$(MKDIR_P) $(@D); \
|
$(MKDIR_P) $(@D); \
|
||||||
files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
|
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 =
|
GOTESTFLAGS =
|
||||||
GOBENCH =
|
GOBENCH =
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,10 @@ libgobegin_a_AR = $(AR) $(ARFLAGS)
|
||||||
libgobegin_a_LIBADD =
|
libgobegin_a_LIBADD =
|
||||||
am_libgobegin_a_OBJECTS = libgobegin_a-go-main.$(OBJEXT)
|
am_libgobegin_a_OBJECTS = libgobegin_a-go-main.$(OBJEXT)
|
||||||
libgobegin_a_OBJECTS = $(am_libgobegin_a_OBJECTS)
|
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_AR = $(AR) $(ARFLAGS)
|
||||||
libnetgo_a_DEPENDENCIES = netgo.o
|
libnetgo_a_DEPENDENCIES = netgo.o
|
||||||
am__objects_1 =
|
am__objects_1 =
|
||||||
|
|
@ -264,8 +268,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||||
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||||
$(LDFLAGS) -o $@
|
$(LDFLAGS) -o $@
|
||||||
SOURCES = $(libgobegin_llgo_a_SOURCES) $(libgobegin_a_SOURCES) \
|
SOURCES = $(libgobegin_llgo_a_SOURCES) $(libgobegin_a_SOURCES) \
|
||||||
$(libnetgo_a_SOURCES) $(libgo_llgo_la_SOURCES) \
|
$(libgolibbegin_a_SOURCES) $(libnetgo_a_SOURCES) \
|
||||||
$(libgo_la_SOURCES)
|
$(libgo_llgo_la_SOURCES) $(libgo_la_SOURCES)
|
||||||
MULTISRCTOP =
|
MULTISRCTOP =
|
||||||
MULTIBUILDTOP =
|
MULTIBUILDTOP =
|
||||||
MULTIDIRS =
|
MULTIDIRS =
|
||||||
|
|
@ -532,7 +536,7 @@ AM_MAKEFLAGS = \
|
||||||
FLAGS_TO_PASS = $(AM_MAKEFLAGS)
|
FLAGS_TO_PASS = $(AM_MAKEFLAGS)
|
||||||
@GOC_IS_LLGO_FALSE@toolexeclib_LTLIBRARIES = libgo.la
|
@GOC_IS_LLGO_FALSE@toolexeclib_LTLIBRARIES = libgo.la
|
||||||
@GOC_IS_LLGO_TRUE@toolexeclib_LTLIBRARIES = libgo-llgo.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
|
@GOC_IS_LLGO_TRUE@toolexeclib_LIBRARIES = libgobegin-llgo.a
|
||||||
toolexeclibgo_DATA = \
|
toolexeclibgo_DATA = \
|
||||||
bufio.gox \
|
bufio.gox \
|
||||||
|
|
@ -2102,6 +2106,10 @@ libgobegin_llgo_a_SOURCES = \
|
||||||
# Use -fPIC for libgobegin so that it can be put in a PIE.
|
# Use -fPIC for libgobegin so that it can be put in a PIE.
|
||||||
libgobegin_a_CFLAGS = $(AM_CFLAGS) -fPIC
|
libgobegin_a_CFLAGS = $(AM_CFLAGS) -fPIC
|
||||||
libgobegin_llgo_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_SOURCES = $(go_netgo_files)
|
||||||
libnetgo_a_LIBADD = netgo.o
|
libnetgo_a_LIBADD = netgo.o
|
||||||
LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
|
LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
|
||||||
|
|
@ -2132,7 +2140,7 @@ BUILDPACKAGE = \
|
||||||
BUILDNETGO = \
|
BUILDNETGO = \
|
||||||
$(MKDIR_P) $(@D); \
|
$(MKDIR_P) $(@D); \
|
||||||
files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
|
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 =
|
GOTESTFLAGS =
|
||||||
GOBENCH =
|
GOBENCH =
|
||||||
|
|
@ -2421,6 +2429,10 @@ libgobegin.a: $(libgobegin_a_OBJECTS) $(libgobegin_a_DEPENDENCIES)
|
||||||
-rm -f libgobegin.a
|
-rm -f libgobegin.a
|
||||||
$(libgobegin_a_AR) libgobegin.a $(libgobegin_a_OBJECTS) $(libgobegin_a_LIBADD)
|
$(libgobegin_a_AR) libgobegin.a $(libgobegin_a_OBJECTS) $(libgobegin_a_LIBADD)
|
||||||
$(RANLIB) libgobegin.a
|
$(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)
|
libnetgo.a: $(libnetgo_a_OBJECTS) $(libnetgo_a_DEPENDENCIES)
|
||||||
-rm -f libnetgo.a
|
-rm -f libnetgo.a
|
||||||
$(libnetgo_a_AR) libnetgo.a $(libnetgo_a_OBJECTS) $(libnetgo_a_LIBADD)
|
$(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)/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_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)/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_futex.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock_sema.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__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@
|
@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`
|
@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
|
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@ $(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
|
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-append.Tpo $(DEPDIR)/go-append.Plo
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@
|
||||||
#include "go-alloc.h"
|
#include "go-alloc.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "go-panic.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
|
/* 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
|
C++. This takes the current goroutine out of the Go scheduler, as
|
||||||
|
|
@ -86,6 +89,15 @@ syscall_cgocallback ()
|
||||||
|
|
||||||
runtime_exitsyscall ();
|
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 ();
|
mp = runtime_m ();
|
||||||
if (mp->needextram)
|
if (mp->needextram)
|
||||||
{
|
{
|
||||||
|
|
@ -177,3 +189,65 @@ _cgo_panic (const char *p)
|
||||||
|
|
||||||
__go_panic (e);
|
__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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
@ -35,6 +35,12 @@ extern char **environ;
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
runtime_isarchive = false;
|
||||||
|
|
||||||
|
if (runtime_isstarted)
|
||||||
|
return NULL;
|
||||||
|
runtime_isstarted = true;
|
||||||
|
|
||||||
runtime_check ();
|
runtime_check ();
|
||||||
runtime_args (argc, (byte **) argv);
|
runtime_args (argc, (byte **) argv);
|
||||||
runtime_osinit ();
|
runtime_osinit ();
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,6 @@ enum
|
||||||
Sched runtime_sched;
|
Sched runtime_sched;
|
||||||
int32 runtime_gomaxprocs;
|
int32 runtime_gomaxprocs;
|
||||||
uint32 runtime_needextram = 1;
|
uint32 runtime_needextram = 1;
|
||||||
bool runtime_iscgo = true;
|
|
||||||
M runtime_m0;
|
M runtime_m0;
|
||||||
G runtime_g0; // idle goroutine for m0
|
G runtime_g0; // idle goroutine for m0
|
||||||
G* runtime_lastg;
|
G* runtime_lastg;
|
||||||
|
|
@ -389,6 +388,8 @@ G** runtime_allg;
|
||||||
uintptr runtime_allglen;
|
uintptr runtime_allglen;
|
||||||
static uintptr allgcap;
|
static uintptr allgcap;
|
||||||
|
|
||||||
|
bool runtime_isarchive;
|
||||||
|
|
||||||
void* runtime_mstart(void*);
|
void* runtime_mstart(void*);
|
||||||
static void runqput(P*, G*);
|
static void runqput(P*, G*);
|
||||||
static G* runqget(P*);
|
static G* runqget(P*);
|
||||||
|
|
@ -428,6 +429,8 @@ static bool preemptall(void);
|
||||||
static bool exitsyscallfast(void);
|
static bool exitsyscallfast(void);
|
||||||
static void allgadd(G*);
|
static void allgadd(G*);
|
||||||
|
|
||||||
|
bool runtime_isstarted;
|
||||||
|
|
||||||
// The bootstrap sequence is:
|
// The bootstrap sequence is:
|
||||||
//
|
//
|
||||||
// call osinit
|
// call osinit
|
||||||
|
|
@ -490,6 +493,64 @@ runtime_schedinit(void)
|
||||||
extern void main_init(void) __asm__ (GOSYM_PREFIX "__go_init_main");
|
extern void main_init(void) __asm__ (GOSYM_PREFIX "__go_init_main");
|
||||||
extern void main_main(void) __asm__ (GOSYM_PREFIX "main.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
|
static void
|
||||||
initDone(void *arg __attribute__ ((unused))) {
|
initDone(void *arg __attribute__ ((unused))) {
|
||||||
runtime_unlockOSThread();
|
runtime_unlockOSThread();
|
||||||
|
|
@ -535,8 +596,15 @@ runtime_main(void* dummy __attribute__((unused)))
|
||||||
if(m != &runtime_m0)
|
if(m != &runtime_m0)
|
||||||
runtime_throw("runtime_main not on m0");
|
runtime_throw("runtime_main not on m0");
|
||||||
__go_go(runtime_MHeap_Scavenger, nil);
|
__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();
|
main_init();
|
||||||
|
|
||||||
|
closechan(runtime_main_init_done);
|
||||||
|
|
||||||
if(g->defer != &d || d.__pfn != initDone)
|
if(g->defer != &d || d.__pfn != initDone)
|
||||||
runtime_throw("runtime: bad defer entry after init");
|
runtime_throw("runtime: bad defer entry after init");
|
||||||
g->defer = d.__next;
|
g->defer = d.__next;
|
||||||
|
|
@ -547,6 +615,14 @@ runtime_main(void* dummy __attribute__((unused)))
|
||||||
// roots.
|
// roots.
|
||||||
mstats.enablegc = 1;
|
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();
|
main_main();
|
||||||
|
|
||||||
// Make racy client program work: if panicking on
|
// 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
|
// Install signal handlers; after minit so that minit can
|
||||||
// prepare the thread to be able to handle the signals.
|
// 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();
|
runtime_initsig();
|
||||||
|
}
|
||||||
|
|
||||||
if(m->mstartfn)
|
if(m->mstartfn)
|
||||||
m->mstartfn();
|
m->mstartfn();
|
||||||
|
|
@ -2747,6 +2829,13 @@ checkdead(void)
|
||||||
int32 run, grunning, s;
|
int32 run, grunning, s;
|
||||||
uintptr i;
|
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
|
// -1 for sysmon
|
||||||
run = runtime_sched.mcount - runtime_sched.nmidle - runtime_sched.nmidlelocked - 1 - countextra();
|
run = runtime_sched.mcount - runtime_sched.nmidle - runtime_sched.nmidlelocked - 1 - countextra();
|
||||||
if(run > 0)
|
if(run > 0)
|
||||||
|
|
@ -3332,6 +3421,7 @@ void
|
||||||
runtime_proc_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj))
|
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_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
|
// Return whether we are waiting for a GC. This gc toolchain uses
|
||||||
|
|
|
||||||
|
|
@ -509,6 +509,9 @@ extern uint32 runtime_Hchansize;
|
||||||
extern DebugVars runtime_debug;
|
extern DebugVars runtime_debug;
|
||||||
extern uintptr runtime_maxstacksize;
|
extern uintptr runtime_maxstacksize;
|
||||||
|
|
||||||
|
extern bool runtime_isstarted;
|
||||||
|
extern bool runtime_isarchive;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* common functions and data
|
* common functions and data
|
||||||
*/
|
*/
|
||||||
|
|
@ -845,3 +848,9 @@ struct time_now_ret
|
||||||
|
|
||||||
struct time_now_ret now() __asm__ (GOSYM_PREFIX "time.now")
|
struct time_now_ret now() __asm__ (GOSYM_PREFIX "time.now")
|
||||||
__attribute__ ((no_split_stack));
|
__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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue