| /* 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-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. */ |
| |
| 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 ("__go_tdn_string"); |
| |
| void |
| _cgo_panic (const char *p) |
| { |
| int len; |
| unsigned char *data; |
| struct __go_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->__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; |
| } |