75791bab05
Use the new -fgo-c-header option to build a header file for the Go runtime code in libgo/go/runtime, and use the new header file in the C runtime code in libgo/runtime. This will ensure that the Go code and C code share the same data structures as we convert the runtime from C to Go. The new file libgo/go/runtime/runtime2.go is copied from the Go 1.7 release, and then edited to remove unnecessary data structures and modify others for use with libgo. The new file libgo/go/runtime/mcache.go is an initial version of the same files in the Go 1.7 release, and will be replaced by the Go 1.7 file when we convert to the new memory allocator. The new file libgo/go/runtime/type.go describes the gccgo version of the reflection data structures, and replaces the Go 1.7 runtime file which describes the gc version of those structures. Using the new header file means changing a number of struct fields to use Go naming conventions (that is, no underscores) and to rename constants to have a leading underscore so that they are not exported from the Go package. These names were updated in the C code. The C code was also changed to drop the thread-local variable m, as was done some time ago in the gc sources. Now the m field is always accessed using g->m, where g is the single remaining thread-local variable. This in turn required some adjustments to set g->m correctly in all cases. Also pass the new -fgo-compiling-runtime option when compiling the runtime package, although that option doesn't do anything yet. Reviewed-on: https://go-review.googlesource.com/28051 From-SVN: r239872
256 lines
6.2 KiB
C
256 lines
6.2 KiB
C
/* go-cgo.c -- SWIG support routines for libgo.
|
|
|
|
Copyright 2011 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 "runtime.h"
|
|
#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
|
|
though it were making a system call. Otherwise the program can
|
|
lock up if the C code goes to sleep on a mutex or for some other
|
|
reason. This idea is to call this function, then immediately call
|
|
the C/C++ function. After the C/C++ function returns, call
|
|
syscall_cgocalldone. The usual Go code would look like
|
|
|
|
syscall.Cgocall()
|
|
defer syscall.Cgocalldone()
|
|
cfunction()
|
|
|
|
*/
|
|
|
|
/* We let Go code call these via the syscall package. */
|
|
void syscall_cgocall(void) __asm__ (GOSYM_PREFIX "syscall.Cgocall");
|
|
void syscall_cgocalldone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallDone");
|
|
void syscall_cgocallback(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBack");
|
|
void syscall_cgocallbackdone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBackDone");
|
|
|
|
void
|
|
syscall_cgocall ()
|
|
{
|
|
M* m;
|
|
|
|
if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0))
|
|
runtime_newextram ();
|
|
|
|
runtime_lockOSThread();
|
|
|
|
m = runtime_m ();
|
|
++m->ncgocall;
|
|
++m->ncgo;
|
|
runtime_entersyscall ();
|
|
}
|
|
|
|
/* Prepare to return to Go code from C/C++ code. */
|
|
|
|
void
|
|
syscall_cgocalldone ()
|
|
{
|
|
G* g;
|
|
|
|
g = runtime_g ();
|
|
__go_assert (g != NULL);
|
|
--g->m->ncgo;
|
|
if (g->m->ncgo == 0)
|
|
{
|
|
/* We are going back to Go, and we are not in a recursive call.
|
|
Let the garbage collector clean up any unreferenced
|
|
memory. */
|
|
g->m->cgomal = NULL;
|
|
}
|
|
|
|
/* If we are invoked because the C function called _cgo_panic, then
|
|
_cgo_panic will already have exited syscall mode. */
|
|
if (g->atomicstatus == _Gsyscall)
|
|
runtime_exitsyscall ();
|
|
|
|
runtime_unlockOSThread();
|
|
}
|
|
|
|
/* Call back from C/C++ code to Go code. */
|
|
|
|
void
|
|
syscall_cgocallback ()
|
|
{
|
|
M *mp;
|
|
|
|
mp = runtime_m ();
|
|
if (mp == NULL)
|
|
{
|
|
runtime_needm ();
|
|
mp = runtime_m ();
|
|
mp->dropextram = true;
|
|
}
|
|
|
|
runtime_exitsyscall ();
|
|
|
|
if (runtime_m ()->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)
|
|
{
|
|
mp->needextram = 0;
|
|
runtime_newextram ();
|
|
}
|
|
}
|
|
|
|
/* Prepare to return to C/C++ code from a callback to Go code. */
|
|
|
|
void
|
|
syscall_cgocallbackdone ()
|
|
{
|
|
M *mp;
|
|
|
|
runtime_entersyscall ();
|
|
mp = runtime_m ();
|
|
if (mp->dropextram && mp->ncgo == 0)
|
|
{
|
|
mp->dropextram = false;
|
|
runtime_dropm ();
|
|
}
|
|
}
|
|
|
|
/* Allocate memory and save it in a list visible to the Go garbage
|
|
collector. */
|
|
|
|
void *
|
|
alloc_saved (size_t n)
|
|
{
|
|
void *ret;
|
|
M *m;
|
|
CgoMal *c;
|
|
|
|
ret = __go_alloc (n);
|
|
|
|
m = runtime_m ();
|
|
c = (CgoMal *) __go_alloc (sizeof (CgoMal));
|
|
c->next = m->cgomal;
|
|
c->alloc = ret;
|
|
m->cgomal = c;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* These are routines used by SWIG. The gc runtime library provides
|
|
the same routines under the same name, though in that case the code
|
|
is required to import runtime/cgo. */
|
|
|
|
void *
|
|
_cgo_allocate (size_t n)
|
|
{
|
|
void *ret;
|
|
|
|
runtime_exitsyscall ();
|
|
ret = alloc_saved (n);
|
|
runtime_entersyscall ();
|
|
return ret;
|
|
}
|
|
|
|
extern const struct __go_type_descriptor string_type_descriptor
|
|
__asm__ (GOSYM_PREFIX "__go_tdn_string");
|
|
|
|
void
|
|
_cgo_panic (const char *p)
|
|
{
|
|
intgo len;
|
|
unsigned char *data;
|
|
String *ps;
|
|
struct __go_empty_interface e;
|
|
|
|
runtime_exitsyscall ();
|
|
len = __builtin_strlen (p);
|
|
data = alloc_saved (len);
|
|
__builtin_memcpy (data, p, len);
|
|
ps = alloc_saved (sizeof *ps);
|
|
ps->str = data;
|
|
ps->len = len;
|
|
e.__type_descriptor = &string_type_descriptor;
|
|
e.__object = ps;
|
|
|
|
/* We don't call runtime_entersyscall here, because normally what
|
|
will happen is that we will walk up the stack to a Go deferred
|
|
function that calls recover. However, this will do the wrong
|
|
thing if this panic is recovered and the stack unwinding is
|
|
caught by a C++ exception handler. It might be possible to
|
|
handle this by calling runtime_entersyscall in the personality
|
|
function in go-unwind.c. FIXME. */
|
|
|
|
__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;
|