123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- /* 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;
- G* g;
- if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0))
- runtime_newextram ();
- 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->cgomal = 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 ()
- {
- M *mp;
- mp = runtime_m ();
- if (mp == NULL)
- {
- runtime_needm ();
- mp = runtime_m ();
- mp->dropextram = true;
- }
- 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)
- {
- 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 && runtime_g ()->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;
- G *g;
- CgoMal *c;
- ret = __go_alloc (n);
- g = runtime_g ();
- c = (CgoMal *) __go_alloc (sizeof (CgoMal));
- c->next = g->cgomal;
- c->alloc = ret;
- g->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;
|