2016-10-07 Steven G. Kargl <kargl@gcc.gnu.org>
[official-gcc.git] / libgo / runtime / go-cgo.c
blob7d0494c3a6580a8ba606b6f36b6d2ddb5405f26e
1 /* go-cgo.c -- SWIG support routines for libgo.
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. */
7 #include "runtime.h"
8 #include "go-alloc.h"
9 #include "interface.h"
10 #include "go-panic.h"
11 #include "go-type.h"
13 extern void __go_receive (ChanType *, Hchan *, byte *);
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
23 syscall.Cgocall()
24 defer syscall.Cgocalldone()
25 cfunction()
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");
35 void
36 syscall_cgocall ()
38 M* m;
40 if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0))
41 runtime_newextram ();
43 runtime_lockOSThread();
45 m = runtime_m ();
46 ++m->ncgocall;
47 ++m->ncgo;
48 runtime_entersyscall (0);
51 /* Prepare to return to Go code from C/C++ code. */
53 void
54 syscall_cgocalldone ()
56 G* g;
58 g = runtime_g ();
59 __go_assert (g != NULL);
60 --g->m->ncgo;
61 if (g->m->ncgo == 0)
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->m->cgomal = NULL;
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->atomicstatus == _Gsyscall)
72 runtime_exitsyscall (0);
74 runtime_unlockOSThread();
77 /* Call back from C/C++ code to Go code. */
79 void
80 syscall_cgocallback ()
82 M *mp;
84 mp = runtime_m ();
85 if (mp == NULL)
87 runtime_needm ();
88 mp = runtime_m ();
89 mp->dropextram = true;
92 runtime_exitsyscall (0);
94 if (runtime_m ()->ncgo == 0)
96 /* The C call to Go came from a thread not currently running any
97 Go. In the case of -buildmode=c-archive or c-shared, this
98 call may be coming in before package initialization is
99 complete. Wait until it is. */
100 __go_receive (NULL, runtime_main_init_done, NULL);
103 mp = runtime_m ();
104 if (mp->needextram)
106 mp->needextram = 0;
107 runtime_newextram ();
111 /* Prepare to return to C/C++ code from a callback to Go code. */
113 void
114 syscall_cgocallbackdone ()
116 M *mp;
118 runtime_entersyscall (0);
119 mp = runtime_m ();
120 if (mp->dropextram && mp->ncgo == 0)
122 mp->dropextram = false;
123 runtime_dropm ();
127 /* Allocate memory and save it in a list visible to the Go garbage
128 collector. */
130 void *
131 alloc_saved (size_t n)
133 void *ret;
134 M *m;
135 CgoMal *c;
137 ret = __go_alloc (n);
139 m = runtime_m ();
140 c = (CgoMal *) __go_alloc (sizeof (CgoMal));
141 c->next = m->cgomal;
142 c->alloc = ret;
143 m->cgomal = c;
145 return ret;
148 /* These are routines used by SWIG. The gc runtime library provides
149 the same routines under the same name, though in that case the code
150 is required to import runtime/cgo. */
152 void *
153 _cgo_allocate (size_t n)
155 void *ret;
157 runtime_exitsyscall (0);
158 ret = alloc_saved (n);
159 runtime_entersyscall (0);
160 return ret;
163 extern const struct __go_type_descriptor string_type_descriptor
164 __asm__ (GOSYM_PREFIX "__go_tdn_string");
166 void
167 _cgo_panic (const char *p)
169 intgo len;
170 unsigned char *data;
171 String *ps;
172 struct __go_empty_interface e;
174 runtime_exitsyscall (0);
175 len = __builtin_strlen (p);
176 data = alloc_saved (len);
177 __builtin_memcpy (data, p, len);
178 ps = alloc_saved (sizeof *ps);
179 ps->str = data;
180 ps->len = len;
181 e.__type_descriptor = &string_type_descriptor;
182 e.__object = ps;
184 /* We don't call runtime_entersyscall here, because normally what
185 will happen is that we will walk up the stack to a Go deferred
186 function that calls recover. However, this will do the wrong
187 thing if this panic is recovered and the stack unwinding is
188 caught by a C++ exception handler. It might be possible to
189 handle this by calling runtime_entersyscall in the personality
190 function in go-unwind.c. FIXME. */
192 __go_panic (e);
195 /* Used for _cgo_wait_runtime_init_done. This is based on code in
196 runtime/cgo/gcc_libinit.c in the master library. */
198 static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
199 static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
200 static _Bool runtime_init_done;
202 /* This is called by exported cgo functions to ensure that the runtime
203 has been initialized before we enter the function. This is needed
204 when building with -buildmode=c-archive or similar. */
206 void
207 _cgo_wait_runtime_init_done (void)
209 int err;
211 if (__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE))
212 return;
214 err = pthread_mutex_lock (&runtime_init_mu);
215 if (err != 0)
216 abort ();
217 while (!__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE))
219 err = pthread_cond_wait (&runtime_init_cond, &runtime_init_mu);
220 if (err != 0)
221 abort ();
223 err = pthread_mutex_unlock (&runtime_init_mu);
224 if (err != 0)
225 abort ();
228 /* This is called by runtime_main after the Go runtime is
229 initialized. */
231 void
232 _cgo_notify_runtime_init_done (void)
234 int err;
236 err = pthread_mutex_lock (&runtime_init_mu);
237 if (err != 0)
238 abort ();
239 __atomic_store_n (&runtime_init_done, 1, __ATOMIC_RELEASE);
240 err = pthread_cond_broadcast (&runtime_init_cond);
241 if (err != 0)
242 abort ();
243 err = pthread_mutex_unlock (&runtime_init_mu);
244 if (err != 0)
245 abort ();
248 // runtime_iscgo is set to true if some cgo code is linked in.
249 // This is done by a constructor in the cgo generated code.
250 _Bool runtime_iscgo;
252 // runtime_cgoHasExtraM is set on startup when an extra M is created
253 // for cgo. The extra M must be created before any C/C++ code calls
254 // cgocallback.
255 _Bool runtime_cgoHasExtraM;