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   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
syscall_cgocalldone()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
syscall_cgocallback()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
syscall_cgocallbackdone()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 *
alloc_saved(size_t n)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 *
_cgo_allocate(size_t n)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
_cgo_panic(const char * p)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 }
180 
181 /* Return the number of CGO calls.  */
182 
183 int64 runtime_NumCgoCall (void) __asm__ (GOSYM_PREFIX "runtime.NumCgoCall");
184 
185 int64
runtime_NumCgoCall(void)186 runtime_NumCgoCall (void)
187 {
188   int64 ret;
189   M* m;
190 
191   ret = 0;
192   for (m = runtime_atomicloadp (&runtime_allm); m != NULL; m = m->alllink)
193     ret += m->ncgocall;
194   return ret;
195 }
196