github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/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 #include "go-type.h" 12 13 extern void __go_receive (ChanType *, Hchan *, byte *); 14 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 22 23 syscall.Cgocall() 24 defer syscall.Cgocalldone() 25 cfunction() 26 27 */ 28 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"); 34 35 void 36 syscall_cgocall () 37 { 38 M* m; 39 G* g; 40 41 if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0)) 42 runtime_newextram (); 43 44 m = runtime_m (); 45 ++m->ncgocall; 46 g = runtime_g (); 47 ++g->ncgo; 48 runtime_entersyscall (); 49 } 50 51 /* Prepare to return to Go code from C/C++ code. */ 52 53 void 54 syscall_cgocalldone () 55 { 56 G* g; 57 58 g = runtime_g (); 59 __go_assert (g != NULL); 60 --g->ncgo; 61 if (g->ncgo == 0) 62 { 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->cgomal = NULL; 67 } 68 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->status == Gsyscall) 72 runtime_exitsyscall (); 73 } 74 75 /* Call back from C/C++ code to Go code. */ 76 77 void 78 syscall_cgocallback () 79 { 80 M *mp; 81 82 mp = runtime_m (); 83 if (mp == NULL) 84 { 85 runtime_needm (); 86 mp = runtime_m (); 87 mp->dropextram = true; 88 } 89 90 runtime_exitsyscall (); 91 92 if (runtime_g ()->ncgo == 0) 93 { 94 /* The C call to Go came from a thread not currently running any 95 Go. In the case of -buildmode=c-archive or c-shared, this 96 call may be coming in before package initialization is 97 complete. Wait until it is. */ 98 __go_receive (NULL, runtime_main_init_done, NULL); 99 } 100 101 mp = runtime_m (); 102 if (mp->needextram) 103 { 104 mp->needextram = 0; 105 runtime_newextram (); 106 } 107 } 108 109 /* Prepare to return to C/C++ code from a callback to Go code. */ 110 111 void 112 syscall_cgocallbackdone () 113 { 114 M *mp; 115 116 runtime_entersyscall (); 117 mp = runtime_m (); 118 if (mp->dropextram && runtime_g ()->ncgo == 0) 119 { 120 mp->dropextram = false; 121 runtime_dropm (); 122 } 123 } 124 125 /* Allocate memory and save it in a list visible to the Go garbage 126 collector. */ 127 128 void * 129 alloc_saved (size_t n) 130 { 131 void *ret; 132 G *g; 133 CgoMal *c; 134 135 ret = __go_alloc (n); 136 137 g = runtime_g (); 138 c = (CgoMal *) __go_alloc (sizeof (CgoMal)); 139 c->next = g->cgomal; 140 c->alloc = ret; 141 g->cgomal = c; 142 143 return ret; 144 } 145 146 /* These are routines used by SWIG. The gc runtime library provides 147 the same routines under the same name, though in that case the code 148 is required to import runtime/cgo. */ 149 150 void * 151 _cgo_allocate (size_t n) 152 { 153 void *ret; 154 155 runtime_exitsyscall (); 156 ret = alloc_saved (n); 157 runtime_entersyscall (); 158 return ret; 159 } 160 161 extern const struct __go_type_descriptor string_type_descriptor 162 __asm__ (GOSYM_PREFIX "__go_tdn_string"); 163 164 void 165 _cgo_panic (const char *p) 166 { 167 intgo len; 168 unsigned char *data; 169 String *ps; 170 struct __go_empty_interface e; 171 172 runtime_exitsyscall (); 173 len = __builtin_strlen (p); 174 data = alloc_saved (len); 175 __builtin_memcpy (data, p, len); 176 ps = alloc_saved (sizeof *ps); 177 ps->str = data; 178 ps->len = len; 179 e.__type_descriptor = &string_type_descriptor; 180 e.__object = ps; 181 182 /* We don't call runtime_entersyscall here, because normally what 183 will happen is that we will walk up the stack to a Go deferred 184 function that calls recover. However, this will do the wrong 185 thing if this panic is recovered and the stack unwinding is 186 caught by a C++ exception handler. It might be possible to 187 handle this by calling runtime_entersyscall in the personality 188 function in go-unwind.c. FIXME. */ 189 190 __go_panic (e); 191 } 192 193 /* Used for _cgo_wait_runtime_init_done. This is based on code in 194 runtime/cgo/gcc_libinit.c in the master library. */ 195 196 static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER; 197 static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER; 198 static _Bool runtime_init_done; 199 200 /* This is called by exported cgo functions to ensure that the runtime 201 has been initialized before we enter the function. This is needed 202 when building with -buildmode=c-archive or similar. */ 203 204 void 205 _cgo_wait_runtime_init_done (void) 206 { 207 int err; 208 209 if (__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE)) 210 return; 211 212 err = pthread_mutex_lock (&runtime_init_mu); 213 if (err != 0) 214 abort (); 215 while (!__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE)) 216 { 217 err = pthread_cond_wait (&runtime_init_cond, &runtime_init_mu); 218 if (err != 0) 219 abort (); 220 } 221 err = pthread_mutex_unlock (&runtime_init_mu); 222 if (err != 0) 223 abort (); 224 } 225 226 /* This is called by runtime_main after the Go runtime is 227 initialized. */ 228 229 void 230 _cgo_notify_runtime_init_done (void) 231 { 232 int err; 233 234 err = pthread_mutex_lock (&runtime_init_mu); 235 if (err != 0) 236 abort (); 237 __atomic_store_n (&runtime_init_done, 1, __ATOMIC_RELEASE); 238 err = pthread_cond_broadcast (&runtime_init_cond); 239 if (err != 0) 240 abort (); 241 err = pthread_mutex_unlock (&runtime_init_mu); 242 if (err != 0) 243 abort (); 244 } 245 246 // runtime_iscgo is set to true if some cgo code is linked in. 247 // This is done by a constructor in the cgo generated code. 248 _Bool runtime_iscgo; 249 250 // runtime_cgoHasExtraM is set on startup when an extra M is created 251 // for cgo. The extra M must be created before any C/C++ code calls 252 // cgocallback. 253 _Bool runtime_cgoHasExtraM;