github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/go-cgo.c (about)

     1  /* go-cgo.c -- SWIG support routines for libgo.
     2  
     3     Copyright 2011 The Go Authors. All rights reserved.
     4     Use of this source code is governed by a BSD-style
     5     license that can be found in the LICENSE file.  */
     6  
     7  #include "runtime.h"
     8  #include "go-alloc.h"
     9  #include "interface.h"
    10  #include "go-panic.h"
    11  #include "go-type.h"
    12  
    13  extern void __go_receive (ChanType *, Hchan *, byte *);
    14  
    15  /* Prepare to call from code written in Go to code written in C or
    16     C++.  This takes the current goroutine out of the Go scheduler, as
    17     though it were making a system call.  Otherwise the program can
    18     lock up if the C code goes to sleep on a mutex or for some other
    19     reason.  This idea is to call this function, then immediately call
    20     the C/C++ function.  After the C/C++ function returns, call
    21     syscall_cgocalldone.  The usual Go code would look like
    22  
    23         syscall.Cgocall()
    24         defer syscall.Cgocalldone()
    25         cfunction()
    26  
    27     */
    28  
    29  /* We let Go code call these via the syscall package.  */
    30  void syscall_cgocall(void) __asm__ (GOSYM_PREFIX "syscall.Cgocall");
    31  void syscall_cgocalldone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallDone");
    32  void syscall_cgocallback(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBack");
    33  void syscall_cgocallbackdone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBackDone");
    34  
    35  void
    36  syscall_cgocall ()
    37  {
    38    M* m;
    39    G* g;
    40  
    41    if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0))
    42      runtime_newextram ();
    43  
    44    m = runtime_m ();
    45    ++m->ncgocall;
    46    g = runtime_g ();
    47    ++g->ncgo;
    48    runtime_entersyscall ();
    49  }
    50  
    51  /* Prepare to return to Go code from C/C++ code.  */
    52  
    53  void
    54  syscall_cgocalldone ()
    55  {
    56    G* g;
    57  
    58    g = runtime_g ();
    59    __go_assert (g != NULL);
    60    --g->ncgo;
    61    if (g->ncgo == 0)
    62      {
    63        /* We are going back to Go, and we are not in a recursive call.
    64  	 Let the garbage collector clean up any unreferenced
    65  	 memory.  */
    66        g->cgomal = NULL;
    67      }
    68  
    69    /* If we are invoked because the C function called _cgo_panic, then
    70       _cgo_panic will already have exited syscall mode.  */
    71    if (g->status == Gsyscall)
    72      runtime_exitsyscall ();
    73  }
    74  
    75  /* Call back from C/C++ code to Go code.  */
    76  
    77  void
    78  syscall_cgocallback ()
    79  {
    80    M *mp;
    81  
    82    mp = runtime_m ();
    83    if (mp == NULL)
    84      {
    85        runtime_needm ();
    86        mp = runtime_m ();
    87        mp->dropextram = true;
    88      }
    89  
    90    runtime_exitsyscall ();
    91  
    92    if (runtime_g ()->ncgo == 0)
    93      {
    94        /* The C call to Go came from a thread not currently running any
    95  	 Go.  In the case of -buildmode=c-archive or c-shared, this
    96  	 call may be coming in before package initialization is
    97  	 complete.  Wait until it is.  */
    98        __go_receive (NULL, runtime_main_init_done, NULL);
    99      }
   100  
   101    mp = runtime_m ();
   102    if (mp->needextram)
   103      {
   104        mp->needextram = 0;
   105        runtime_newextram ();
   106      }
   107  }
   108  
   109  /* Prepare to return to C/C++ code from a callback to Go code.  */
   110  
   111  void
   112  syscall_cgocallbackdone ()
   113  {
   114    M *mp;
   115  
   116    runtime_entersyscall ();
   117    mp = runtime_m ();
   118    if (mp->dropextram && runtime_g ()->ncgo == 0)
   119      {
   120        mp->dropextram = false;
   121        runtime_dropm ();
   122      }
   123  }
   124  
   125  /* Allocate memory and save it in a list visible to the Go garbage
   126     collector.  */
   127  
   128  void *
   129  alloc_saved (size_t n)
   130  {
   131    void *ret;
   132    G *g;
   133    CgoMal *c;
   134  
   135    ret = __go_alloc (n);
   136  
   137    g = runtime_g ();
   138    c = (CgoMal *) __go_alloc (sizeof (CgoMal));
   139    c->next = g->cgomal;
   140    c->alloc = ret;
   141    g->cgomal = c;
   142  
   143    return ret;
   144  }
   145  
   146  /* These are routines used by SWIG.  The gc runtime library provides
   147     the same routines under the same name, though in that case the code
   148     is required to import runtime/cgo.  */
   149  
   150  void *
   151  _cgo_allocate (size_t n)
   152  {
   153    void *ret;
   154  
   155    runtime_exitsyscall ();
   156    ret = alloc_saved (n);
   157    runtime_entersyscall ();
   158    return ret;
   159  }
   160  
   161  extern const struct __go_type_descriptor string_type_descriptor
   162    __asm__ (GOSYM_PREFIX "__go_tdn_string");
   163  
   164  void
   165  _cgo_panic (const char *p)
   166  {
   167    intgo len;
   168    unsigned char *data;
   169    String *ps;
   170    struct __go_empty_interface e;
   171  
   172    runtime_exitsyscall ();
   173    len = __builtin_strlen (p);
   174    data = alloc_saved (len);
   175    __builtin_memcpy (data, p, len);
   176    ps = alloc_saved (sizeof *ps);
   177    ps->str = data;
   178    ps->len = len;
   179    e.__type_descriptor = &string_type_descriptor;
   180    e.__object = ps;
   181  
   182    /* We don't call runtime_entersyscall here, because normally what
   183       will happen is that we will walk up the stack to a Go deferred
   184       function that calls recover.  However, this will do the wrong
   185       thing if this panic is recovered and the stack unwinding is
   186       caught by a C++ exception handler.  It might be possible to
   187       handle this by calling runtime_entersyscall in the personality
   188       function in go-unwind.c.  FIXME.  */
   189  
   190    __go_panic (e);
   191  }
   192  
   193  /* Used for _cgo_wait_runtime_init_done.  This is based on code in
   194     runtime/cgo/gcc_libinit.c in the master library.  */
   195  
   196  static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
   197  static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
   198  static _Bool runtime_init_done;
   199  
   200  /* This is called by exported cgo functions to ensure that the runtime
   201     has been initialized before we enter the function.  This is needed
   202     when building with -buildmode=c-archive or similar.  */
   203  
   204  void
   205  _cgo_wait_runtime_init_done (void)
   206  {
   207    int err;
   208  
   209    if (__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE))
   210      return;
   211  
   212    err = pthread_mutex_lock (&runtime_init_mu);
   213    if (err != 0)
   214      abort ();
   215    while (!__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE))
   216      {
   217        err = pthread_cond_wait (&runtime_init_cond, &runtime_init_mu);
   218        if (err != 0)
   219  	abort ();
   220      }
   221    err = pthread_mutex_unlock (&runtime_init_mu);
   222    if (err != 0)
   223      abort ();
   224  }
   225  
   226  /* This is called by runtime_main after the Go runtime is
   227     initialized.  */
   228  
   229  void
   230  _cgo_notify_runtime_init_done (void)
   231  {
   232    int err;
   233  
   234    err = pthread_mutex_lock (&runtime_init_mu);
   235    if (err != 0)
   236      abort ();
   237    __atomic_store_n (&runtime_init_done, 1, __ATOMIC_RELEASE);
   238    err = pthread_cond_broadcast (&runtime_init_cond);
   239    if (err != 0)
   240      abort ();
   241    err = pthread_mutex_unlock (&runtime_init_mu);
   242    if (err != 0)
   243      abort ();
   244  }
   245  
   246  // runtime_iscgo is set to true if some cgo code is linked in.
   247  // This is done by a constructor in the cgo generated code.
   248  _Bool runtime_iscgo;
   249  
   250  // runtime_cgoHasExtraM is set on startup when an extra M is created
   251  // for cgo.  The extra M must be created before any C/C++ code calls
   252  // cgocallback.
   253  _Bool runtime_cgoHasExtraM;