go-cgo.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /* go-cgo.c -- SWIG support routines for libgo.
  2. Copyright 2011 The Go Authors. All rights reserved.
  3. Use of this source code is governed by a BSD-style
  4. license that can be found in the LICENSE file. */
  5. #include "runtime.h"
  6. #include "go-alloc.h"
  7. #include "interface.h"
  8. #include "go-panic.h"
  9. #include "go-type.h"
  10. extern void __go_receive (ChanType *, Hchan *, byte *);
  11. /* Prepare to call from code written in Go to code written in C or
  12. C++. This takes the current goroutine out of the Go scheduler, as
  13. though it were making a system call. Otherwise the program can
  14. lock up if the C code goes to sleep on a mutex or for some other
  15. reason. This idea is to call this function, then immediately call
  16. the C/C++ function. After the C/C++ function returns, call
  17. syscall_cgocalldone. The usual Go code would look like
  18. syscall.Cgocall()
  19. defer syscall.Cgocalldone()
  20. cfunction()
  21. */
  22. /* We let Go code call these via the syscall package. */
  23. void syscall_cgocall(void) __asm__ (GOSYM_PREFIX "syscall.Cgocall");
  24. void syscall_cgocalldone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallDone");
  25. void syscall_cgocallback(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBack");
  26. void syscall_cgocallbackdone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBackDone");
  27. void
  28. syscall_cgocall ()
  29. {
  30. M* m;
  31. G* g;
  32. if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0))
  33. runtime_newextram ();
  34. m = runtime_m ();
  35. ++m->ncgocall;
  36. g = runtime_g ();
  37. ++g->ncgo;
  38. runtime_entersyscall ();
  39. }
  40. /* Prepare to return to Go code from C/C++ code. */
  41. void
  42. syscall_cgocalldone ()
  43. {
  44. G* g;
  45. g = runtime_g ();
  46. __go_assert (g != NULL);
  47. --g->ncgo;
  48. if (g->ncgo == 0)
  49. {
  50. /* We are going back to Go, and we are not in a recursive call.
  51. Let the garbage collector clean up any unreferenced
  52. memory. */
  53. g->cgomal = NULL;
  54. }
  55. /* If we are invoked because the C function called _cgo_panic, then
  56. _cgo_panic will already have exited syscall mode. */
  57. if (g->status == Gsyscall)
  58. runtime_exitsyscall ();
  59. }
  60. /* Call back from C/C++ code to Go code. */
  61. void
  62. syscall_cgocallback ()
  63. {
  64. M *mp;
  65. mp = runtime_m ();
  66. if (mp == NULL)
  67. {
  68. runtime_needm ();
  69. mp = runtime_m ();
  70. mp->dropextram = true;
  71. }
  72. runtime_exitsyscall ();
  73. if (runtime_g ()->ncgo == 0)
  74. {
  75. /* The C call to Go came from a thread not currently running any
  76. Go. In the case of -buildmode=c-archive or c-shared, this
  77. call may be coming in before package initialization is
  78. complete. Wait until it is. */
  79. __go_receive (NULL, runtime_main_init_done, NULL);
  80. }
  81. mp = runtime_m ();
  82. if (mp->needextram)
  83. {
  84. mp->needextram = 0;
  85. runtime_newextram ();
  86. }
  87. }
  88. /* Prepare to return to C/C++ code from a callback to Go code. */
  89. void
  90. syscall_cgocallbackdone ()
  91. {
  92. M *mp;
  93. runtime_entersyscall ();
  94. mp = runtime_m ();
  95. if (mp->dropextram && runtime_g ()->ncgo == 0)
  96. {
  97. mp->dropextram = false;
  98. runtime_dropm ();
  99. }
  100. }
  101. /* Allocate memory and save it in a list visible to the Go garbage
  102. collector. */
  103. void *
  104. alloc_saved (size_t n)
  105. {
  106. void *ret;
  107. G *g;
  108. CgoMal *c;
  109. ret = __go_alloc (n);
  110. g = runtime_g ();
  111. c = (CgoMal *) __go_alloc (sizeof (CgoMal));
  112. c->next = g->cgomal;
  113. c->alloc = ret;
  114. g->cgomal = c;
  115. return ret;
  116. }
  117. /* These are routines used by SWIG. The gc runtime library provides
  118. the same routines under the same name, though in that case the code
  119. is required to import runtime/cgo. */
  120. void *
  121. _cgo_allocate (size_t n)
  122. {
  123. void *ret;
  124. runtime_exitsyscall ();
  125. ret = alloc_saved (n);
  126. runtime_entersyscall ();
  127. return ret;
  128. }
  129. extern const struct __go_type_descriptor string_type_descriptor
  130. __asm__ (GOSYM_PREFIX "__go_tdn_string");
  131. void
  132. _cgo_panic (const char *p)
  133. {
  134. intgo len;
  135. unsigned char *data;
  136. String *ps;
  137. struct __go_empty_interface e;
  138. runtime_exitsyscall ();
  139. len = __builtin_strlen (p);
  140. data = alloc_saved (len);
  141. __builtin_memcpy (data, p, len);
  142. ps = alloc_saved (sizeof *ps);
  143. ps->str = data;
  144. ps->len = len;
  145. e.__type_descriptor = &string_type_descriptor;
  146. e.__object = ps;
  147. /* We don't call runtime_entersyscall here, because normally what
  148. will happen is that we will walk up the stack to a Go deferred
  149. function that calls recover. However, this will do the wrong
  150. thing if this panic is recovered and the stack unwinding is
  151. caught by a C++ exception handler. It might be possible to
  152. handle this by calling runtime_entersyscall in the personality
  153. function in go-unwind.c. FIXME. */
  154. __go_panic (e);
  155. }
  156. /* Used for _cgo_wait_runtime_init_done. This is based on code in
  157. runtime/cgo/gcc_libinit.c in the master library. */
  158. static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
  159. static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
  160. static _Bool runtime_init_done;
  161. /* This is called by exported cgo functions to ensure that the runtime
  162. has been initialized before we enter the function. This is needed
  163. when building with -buildmode=c-archive or similar. */
  164. void
  165. _cgo_wait_runtime_init_done (void)
  166. {
  167. int err;
  168. if (__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE))
  169. return;
  170. err = pthread_mutex_lock (&runtime_init_mu);
  171. if (err != 0)
  172. abort ();
  173. while (!__atomic_load_n (&runtime_init_done, __ATOMIC_ACQUIRE))
  174. {
  175. err = pthread_cond_wait (&runtime_init_cond, &runtime_init_mu);
  176. if (err != 0)
  177. abort ();
  178. }
  179. err = pthread_mutex_unlock (&runtime_init_mu);
  180. if (err != 0)
  181. abort ();
  182. }
  183. /* This is called by runtime_main after the Go runtime is
  184. initialized. */
  185. void
  186. _cgo_notify_runtime_init_done (void)
  187. {
  188. int err;
  189. err = pthread_mutex_lock (&runtime_init_mu);
  190. if (err != 0)
  191. abort ();
  192. __atomic_store_n (&runtime_init_done, 1, __ATOMIC_RELEASE);
  193. err = pthread_cond_broadcast (&runtime_init_cond);
  194. if (err != 0)
  195. abort ();
  196. err = pthread_mutex_unlock (&runtime_init_mu);
  197. if (err != 0)
  198. abort ();
  199. }
  200. // runtime_iscgo is set to true if some cgo code is linked in.
  201. // This is done by a constructor in the cgo generated code.
  202. _Bool runtime_iscgo;
  203. // runtime_cgoHasExtraM is set on startup when an extra M is created
  204. // for cgo. The extra M must be created before any C/C++ code calls
  205. // cgocallback.
  206. _Bool runtime_cgoHasExtraM;