2016-07-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
[official-gcc.git] / libgo / runtime / go-cgo.c
blob610bcf5ec4e8d246f34fb3162a6dc5ae26df9cf4
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;
39 G* g;
41 if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0))
42 runtime_newextram ();
44 runtime_lockOSThread();
46 m = runtime_m ();
47 ++m->ncgocall;
48 g = runtime_g ();
49 ++g->ncgo;
50 runtime_entersyscall ();
53 /* Prepare to return to Go code from C/C++ code. */
55 void
56 syscall_cgocalldone ()
58 G* g;
60 g = runtime_g ();
61 __go_assert (g != NULL);
62 --g->ncgo;
63 if (g->ncgo == 0)
65 /* We are going back to Go, and we are not in a recursive call.
66 Let the garbage collector clean up any unreferenced
67 memory. */
68 g->cgomal = NULL;
71 /* If we are invoked because the C function called _cgo_panic, then
72 _cgo_panic will already have exited syscall mode. */
73 if (g->status == Gsyscall)
74 runtime_exitsyscall ();
76 runtime_unlockOSThread();
79 /* Call back from C/C++ code to Go code. */
81 void
82 syscall_cgocallback ()
84 M *mp;
86 mp = runtime_m ();
87 if (mp == NULL)
89 runtime_needm ();
90 mp = runtime_m ();
91 mp->dropextram = true;
94 runtime_exitsyscall ();
96 if (runtime_g ()->ncgo == 0)
98 /* The C call to Go came from a thread not currently running any
99 Go. In the case of -buildmode=c-archive or c-shared, this
100 call may be coming in before package initialization is
101 complete. Wait until it is. */
102 __go_receive (NULL, runtime_main_init_done, NULL);
105 mp = runtime_m ();
106 if (mp->needextram)
108 mp->needextram = 0;
109 runtime_newextram ();
113 /* Prepare to return to C/C++ code from a callback to Go code. */
115 void
116 syscall_cgocallbackdone ()
118 M *mp;
120 runtime_entersyscall ();
121 mp = runtime_m ();
122 if (mp->dropextram && runtime_g ()->ncgo == 0)
124 mp->dropextram = false;
125 runtime_dropm ();
129 /* Allocate memory and save it in a list visible to the Go garbage
130 collector. */
132 void *
133 alloc_saved (size_t n)
135 void *ret;
136 G *g;
137 CgoMal *c;
139 ret = __go_alloc (n);
141 g = runtime_g ();
142 c = (CgoMal *) __go_alloc (sizeof (CgoMal));
143 c->next = g->cgomal;
144 c->alloc = ret;
145 g->cgomal = c;
147 return ret;
150 /* These are routines used by SWIG. The gc runtime library provides
151 the same routines under the same name, though in that case the code
152 is required to import runtime/cgo. */
154 void *
155 _cgo_allocate (size_t n)
157 void *ret;
159 runtime_exitsyscall ();
160 ret = alloc_saved (n);
161 runtime_entersyscall ();
162 return ret;
165 extern const struct __go_type_descriptor string_type_descriptor
166 __asm__ (GOSYM_PREFIX "__go_tdn_string");
168 void
169 _cgo_panic (const char *p)
171 intgo len;
172 unsigned char *data;
173 String *ps;
174 struct __go_empty_interface e;
176 runtime_exitsyscall ();
177 len = __builtin_strlen (p);
178 data = alloc_saved (len);
179 __builtin_memcpy (data, p, len);
180 ps = alloc_saved (sizeof *ps);
181 ps->str = data;
182 ps->len = len;
183 e.__type_descriptor = &string_type_descriptor;
184 e.__object = ps;
186 /* We don't call runtime_entersyscall here, because normally what
187 will happen is that we will walk up the stack to a Go deferred
188 function that calls recover. However, this will do the wrong
189 thing if this panic is recovered and the stack unwinding is
190 caught by a C++ exception handler. It might be possible to
191 handle this by calling runtime_entersyscall in the personality
192 function in go-unwind.c. FIXME. */
194 __go_panic (e);
197 /* Used for _cgo_wait_runtime_init_done. This is based on code in
198 runtime/cgo/gcc_libinit.c in the master library. */
200 static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
201 static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
202 static _Bool runtime_init_done;
204 /* This is called by exported cgo functions to ensure that the runtime
205 has been initialized before we enter the function. This is needed
206 when building with -buildmode=c-archive or similar. */
208 void
209 _cgo_wait_runtime_init_done (void)
211 int err;
213 if (__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE))
214 return;
216 err = pthread_mutex_lock (&runtime_init_mu);
217 if (err != 0)
218 abort ();
219 while (!__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE))
221 err = pthread_cond_wait (&runtime_init_cond, &runtime_init_mu);
222 if (err != 0)
223 abort ();
225 err = pthread_mutex_unlock (&runtime_init_mu);
226 if (err != 0)
227 abort ();
230 /* This is called by runtime_main after the Go runtime is
231 initialized. */
233 void
234 _cgo_notify_runtime_init_done (void)
236 int err;
238 err = pthread_mutex_lock (&runtime_init_mu);
239 if (err != 0)
240 abort ();
241 __atomic_store_n (&runtime_init_done, 1, __ATOMIC_RELEASE);
242 err = pthread_cond_broadcast (&runtime_init_cond);
243 if (err != 0)
244 abort ();
245 err = pthread_mutex_unlock (&runtime_init_mu);
246 if (err != 0)
247 abort ();
250 // runtime_iscgo is set to true if some cgo code is linked in.
251 // This is done by a constructor in the cgo generated code.
252 _Bool runtime_iscgo;
254 // runtime_cgoHasExtraM is set on startup when an extra M is created
255 // for cgo. The extra M must be created before any C/C++ code calls
256 // cgocallback.
257 _Bool runtime_cgoHasExtraM;