github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/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  
    12  /* Prepare to call from code written in Go to code written in C or
    13     C++.  This takes the current goroutine out of the Go scheduler, as
    14     though it were making a system call.  Otherwise the program can
    15     lock up if the C code goes to sleep on a mutex or for some other
    16     reason.  This idea is to call this function, then immediately call
    17     the C/C++ function.  After the C/C++ function returns, call
    18     syscall_cgocalldone.  The usual Go code would look like
    19  
    20         syscall.Cgocall()
    21         defer syscall.Cgocalldone()
    22         cfunction()
    23  
    24     */
    25  
    26  /* We let Go code call these via the syscall package.  */
    27  void syscall_cgocall(void) __asm__ (GOSYM_PREFIX "syscall.Cgocall");
    28  void syscall_cgocalldone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallDone");
    29  void syscall_cgocallback(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBack");
    30  void syscall_cgocallbackdone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBackDone");
    31  
    32  void
    33  syscall_cgocall ()
    34  {
    35    M* m;
    36    G* g;
    37  
    38    if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0))
    39      runtime_newextram ();
    40  
    41    m = runtime_m ();
    42    ++m->ncgocall;
    43    g = runtime_g ();
    44    ++g->ncgo;
    45    runtime_entersyscall ();
    46  }
    47  
    48  /* Prepare to return to Go code from C/C++ code.  */
    49  
    50  void
    51  syscall_cgocalldone ()
    52  {
    53    G* g;
    54  
    55    g = runtime_g ();
    56    __go_assert (g != NULL);
    57    --g->ncgo;
    58    if (g->ncgo == 0)
    59      {
    60        /* We are going back to Go, and we are not in a recursive call.
    61  	 Let the garbage collector clean up any unreferenced
    62  	 memory.  */
    63        g->cgomal = NULL;
    64      }
    65  
    66    /* If we are invoked because the C function called _cgo_panic, then
    67       _cgo_panic will already have exited syscall mode.  */
    68    if (g->status == Gsyscall)
    69      runtime_exitsyscall ();
    70  }
    71  
    72  /* Call back from C/C++ code to Go code.  */
    73  
    74  void
    75  syscall_cgocallback ()
    76  {
    77    M *mp;
    78  
    79    mp = runtime_m ();
    80    if (mp == NULL)
    81      {
    82        runtime_needm ();
    83        mp = runtime_m ();
    84        mp->dropextram = true;
    85      }
    86  
    87    runtime_exitsyscall ();
    88  
    89    mp = runtime_m ();
    90    if (mp->needextram)
    91      {
    92        mp->needextram = 0;
    93        runtime_newextram ();
    94      }
    95  }
    96  
    97  /* Prepare to return to C/C++ code from a callback to Go code.  */
    98  
    99  void
   100  syscall_cgocallbackdone ()
   101  {
   102    M *mp;
   103  
   104    runtime_entersyscall ();
   105    mp = runtime_m ();
   106    if (mp->dropextram && runtime_g ()->ncgo == 0)
   107      {
   108        mp->dropextram = false;
   109        runtime_dropm ();
   110      }
   111  }
   112  
   113  /* Allocate memory and save it in a list visible to the Go garbage
   114     collector.  */
   115  
   116  void *
   117  alloc_saved (size_t n)
   118  {
   119    void *ret;
   120    G *g;
   121    CgoMal *c;
   122  
   123    ret = __go_alloc (n);
   124  
   125    g = runtime_g ();
   126    c = (CgoMal *) __go_alloc (sizeof (CgoMal));
   127    c->next = g->cgomal;
   128    c->alloc = ret;
   129    g->cgomal = c;
   130  
   131    return ret;
   132  }
   133  
   134  /* These are routines used by SWIG.  The gc runtime library provides
   135     the same routines under the same name, though in that case the code
   136     is required to import runtime/cgo.  */
   137  
   138  void *
   139  _cgo_allocate (size_t n)
   140  {
   141    void *ret;
   142  
   143    runtime_exitsyscall ();
   144    ret = alloc_saved (n);
   145    runtime_entersyscall ();
   146    return ret;
   147  }
   148  
   149  extern const struct __go_type_descriptor string_type_descriptor
   150    __asm__ (GOSYM_PREFIX "__go_tdn_string");
   151  
   152  void
   153  _cgo_panic (const char *p)
   154  {
   155    intgo len;
   156    unsigned char *data;
   157    String *ps;
   158    struct __go_empty_interface e;
   159  
   160    runtime_exitsyscall ();
   161    len = __builtin_strlen (p);
   162    data = alloc_saved (len);
   163    __builtin_memcpy (data, p, len);
   164    ps = alloc_saved (sizeof *ps);
   165    ps->str = data;
   166    ps->len = len;
   167    e.__type_descriptor = &string_type_descriptor;
   168    e.__object = ps;
   169  
   170    /* We don't call runtime_entersyscall here, because normally what
   171       will happen is that we will walk up the stack to a Go deferred
   172       function that calls recover.  However, this will do the wrong
   173       thing if this panic is recovered and the stack unwinding is
   174       caught by a C++ exception handler.  It might be possible to
   175       handle this by calling runtime_entersyscall in the personality
   176       function in go-unwind.c.  FIXME.  */
   177  
   178    __go_panic (e);
   179  }