diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-06-04 05:34:59 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-06-04 05:34:59 +0000 |
commit | 7bea4023f2128cde89e4d7942c988b5145bfac19 (patch) | |
tree | 77d873edc7e97c39f5ed4f5de2a3da54a835ba74 /libgo | |
parent | 7b4cf2664334bce391a661d72d4367da728c3fca (diff) | |
download | gcc-7bea4023f2128cde89e4d7942c988b5145bfac19.zip gcc-7bea4023f2128cde89e4d7942c988b5145bfac19.tar.gz gcc-7bea4023f2128cde89e4d7942c988b5145bfac19.tar.bz2 |
runtime: Better SWIG interface for allocating Go memory from C/C++.
From-SVN: r188164
Diffstat (limited to 'libgo')
-rw-r--r-- | libgo/go/syscall/libcall_support.go | 6 | ||||
-rw-r--r-- | libgo/runtime/go-cgo.c | 142 | ||||
-rw-r--r-- | libgo/runtime/runtime.h | 4 |
3 files changed, 149 insertions, 3 deletions
diff --git a/libgo/go/syscall/libcall_support.go b/libgo/go/syscall/libcall_support.go index 7746cc2..cacc556 100644 --- a/libgo/go/syscall/libcall_support.go +++ b/libgo/go/syscall/libcall_support.go @@ -10,3 +10,9 @@ func Entersyscall() func Exitsyscall() func GetErrno() Errno func SetErrno(Errno) + +// These functions are used by CGO and SWIG. +func Cgocall() +func CgocallDone() +func CgocallBack() +func CgocallBackDone() diff --git a/libgo/runtime/go-cgo.c b/libgo/runtime/go-cgo.c index 94917bc..173696e 100644 --- a/libgo/runtime/go-cgo.c +++ b/libgo/runtime/go-cgo.c @@ -4,11 +4,116 @@ 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-string.h" +/* Go memory allocated by code not written in Go. We keep a linked + list of these allocations so that the garbage collector can see + them. */ + +struct cgoalloc +{ + struct cgoalloc *next; + void *alloc; +}; + +/* 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__ ("syscall.Cgocall"); +void syscall_cgocalldone(void) __asm__ ("syscall.CgocallDone"); +void syscall_cgocallback(void) __asm__ ("syscall.CgocallBack"); +void syscall_cgocallbackdone(void) __asm__ ("syscall.CgocallBackDone"); + +void +syscall_cgocall () +{ + M* m; + G* g; + + m = runtime_m (); + ++m->ncgocall; + g = runtime_g (); + ++g->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->ncgo; + if (g->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->cgoalloc = NULL; + } + + /* If we are invoked because the C function called _cgo_panic, then + _cgo_panic will already have exited syscall mode. */ + if (g->status == Gsyscall) + runtime_exitsyscall (); +} + +/* Call back from C/C++ code to Go code. */ + +void +syscall_cgocallback () +{ + runtime_exitsyscall (); +} + +/* Prepare to return to C/C++ code from a callback to Go code. */ + +void +syscall_cgocallbackdone () +{ + runtime_entersyscall (); +} + +/* Allocate memory and save it in a list visible to the Go garbage + collector. */ + +void * +alloc_saved (size_t n) +{ + void *ret; + G *g; + struct cgoalloc *c; + + ret = __go_alloc (n); + + g = runtime_g (); + c = (struct cgoalloc *) __go_alloc (sizeof (struct cgoalloc)); + c->next = g->cgoalloc; + c->alloc = ret; + g->cgoalloc = 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. */ @@ -16,7 +121,12 @@ void * _cgo_allocate (size_t n) { - return __go_alloc (n); + void *ret; + + runtime_exitsyscall (); + ret = alloc_saved (n); + runtime_entersyscall (); + return ret; } extern const struct __go_type_descriptor string_type_descriptor @@ -30,13 +140,39 @@ _cgo_panic (const char *p) struct __go_string *ps; struct __go_empty_interface e; + runtime_exitsyscall (); len = __builtin_strlen (p); - data = __go_alloc (len); + data = alloc_saved (len); __builtin_memcpy (data, p, len); - ps = __go_alloc (sizeof *ps); + ps = alloc_saved (sizeof *ps); ps->__data = data; ps->__length = 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); } + +/* Return the number of CGO calls. */ + +int64 runtime_NumCgoCall (void) __asm__ ("runtime.NumCgoCall"); + +int64 +runtime_NumCgoCall (void) +{ + int64 ret; + M* m; + + ret = 0; + for (m = runtime_atomicloadp (&runtime_allm); m != NULL; m = m->alllink) + ret += m->ncgocall; + return ret; +} diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 94f8911..76a9eef 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -153,6 +153,9 @@ struct G // uintptr sigpc; uintptr gopc; // pc of go statement that created this goroutine + int32 ncgo; + struct cgoalloc *cgoalloc; + Traceback* traceback; ucontext_t context; @@ -174,6 +177,7 @@ struct M int32 profilehz; int32 helpgc; uint32 fastrand; + uint64 ncgocall; Note havenextg; G* nextg; M* alllink; // on allm |