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
syscall_cgocall()33 syscall_cgocall ()
34 {
35   M* m;
36   G* g;
37 
38   m = runtime_m ();
39   ++m->ncgocall;
40   g = runtime_g ();
41   ++g->ncgo;
42   runtime_entersyscall ();
43 }
44 
45 /* Prepare to return to Go code from C/C++ code.  */
46 
47 void
syscall_cgocalldone()48 syscall_cgocalldone ()
49 {
50   G* g;
51 
52   g = runtime_g ();
53   __go_assert (g != NULL);
54   --g->ncgo;
55   if (g->ncgo == 0)
56     {
57       /* We are going back to Go, and we are not in a recursive call.
58 	 Let the garbage collector clean up any unreferenced
59 	 memory.  */
60       g->cgomal = NULL;
61     }
62 
63   /* If we are invoked because the C function called _cgo_panic, then
64      _cgo_panic will already have exited syscall mode.  */
65   if (g->status == Gsyscall)
66     runtime_exitsyscall ();
67 }
68 
69 /* Call back from C/C++ code to Go code.  */
70 
71 void
syscall_cgocallback()72 syscall_cgocallback ()
73 {
74   runtime_exitsyscall ();
75 }
76 
77 /* Prepare to return to C/C++ code from a callback to Go code.  */
78 
79 void
syscall_cgocallbackdone()80 syscall_cgocallbackdone ()
81 {
82   runtime_entersyscall ();
83 }
84 
85 /* Allocate memory and save it in a list visible to the Go garbage
86    collector.  */
87 
88 void *
alloc_saved(size_t n)89 alloc_saved (size_t n)
90 {
91   void *ret;
92   G *g;
93   CgoMal *c;
94 
95   ret = __go_alloc (n);
96 
97   g = runtime_g ();
98   c = (CgoMal *) __go_alloc (sizeof (CgoMal));
99   c->next = g->cgomal;
100   c->alloc = ret;
101   g->cgomal = c;
102 
103   return ret;
104 }
105 
106 /* These are routines used by SWIG.  The gc runtime library provides
107    the same routines under the same name, though in that case the code
108    is required to import runtime/cgo.  */
109 
110 void *
_cgo_allocate(size_t n)111 _cgo_allocate (size_t n)
112 {
113   void *ret;
114 
115   runtime_exitsyscall ();
116   ret = alloc_saved (n);
117   runtime_entersyscall ();
118   return ret;
119 }
120 
121 extern const struct __go_type_descriptor string_type_descriptor
122   __asm__ (GOSYM_PREFIX "__go_tdn_string");
123 
124 void
_cgo_panic(const char * p)125 _cgo_panic (const char *p)
126 {
127   intgo len;
128   unsigned char *data;
129   String *ps;
130   struct __go_empty_interface e;
131 
132   runtime_exitsyscall ();
133   len = __builtin_strlen (p);
134   data = alloc_saved (len);
135   __builtin_memcpy (data, p, len);
136   ps = alloc_saved (sizeof *ps);
137   ps->str = data;
138   ps->len = len;
139   e.__type_descriptor = &string_type_descriptor;
140   e.__object = ps;
141 
142   /* We don't call runtime_entersyscall here, because normally what
143      will happen is that we will walk up the stack to a Go deferred
144      function that calls recover.  However, this will do the wrong
145      thing if this panic is recovered and the stack unwinding is
146      caught by a C++ exception handler.  It might be possible to
147      handle this by calling runtime_entersyscall in the personality
148      function in go-unwind.c.  FIXME.  */
149 
150   __go_panic (e);
151 }
152 
153 /* Return the number of CGO calls.  */
154 
155 int64 runtime_NumCgoCall (void) __asm__ (GOSYM_PREFIX "runtime.NumCgoCall");
156 
157 int64
runtime_NumCgoCall(void)158 runtime_NumCgoCall (void)
159 {
160   int64 ret;
161   M* m;
162 
163   ret = 0;
164   for (m = runtime_atomicloadp (&runtime_allm); m != NULL; m = m->alllink)
165     ret += m->ncgocall;
166   return ret;
167 }
168