go_libinit.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. // SPDX-License-Identifier: Apache-2.0
  2. // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
  3. //go:build !cgo && (darwin || freebsd || linux)
  4. package fakecgo
  5. import (
  6. "syscall"
  7. "unsafe"
  8. )
  9. var (
  10. pthread_g pthread_key_t
  11. runtime_init_cond = PTHREAD_COND_INITIALIZER
  12. runtime_init_mu = PTHREAD_MUTEX_INITIALIZER
  13. runtime_init_done int
  14. )
  15. //go:nosplit
  16. //go:norace
  17. func x_cgo_notify_runtime_init_done() {
  18. pthread_mutex_lock(&runtime_init_mu)
  19. runtime_init_done = 1
  20. pthread_cond_broadcast(&runtime_init_cond)
  21. pthread_mutex_unlock(&runtime_init_mu)
  22. }
  23. // Store the g into a thread-specific value associated with the pthread key pthread_g.
  24. // And pthread_key_destructor will dropm when the thread is exiting.
  25. //
  26. //go:norace
  27. func x_cgo_bindm(g unsafe.Pointer) {
  28. // We assume this will always succeed, otherwise, there might be extra M leaking,
  29. // when a C thread exits after a cgo call.
  30. // We only invoke this function once per thread in runtime.needAndBindM,
  31. // and the next calls just reuse the bound m.
  32. pthread_setspecific(pthread_g, g)
  33. }
  34. // _cgo_try_pthread_create retries pthread_create if it fails with
  35. // EAGAIN.
  36. //
  37. //go:nosplit
  38. //go:norace
  39. func _cgo_try_pthread_create(thread *pthread_t, attr *pthread_attr_t, pfn unsafe.Pointer, arg *ThreadStart) int {
  40. var ts syscall.Timespec
  41. // tries needs to be the same type as syscall.Timespec.Nsec
  42. // but the fields are int32 on 32bit and int64 on 64bit.
  43. // tries is assigned to syscall.Timespec.Nsec in order to match its type.
  44. tries := ts.Nsec
  45. var err int
  46. for tries = 0; tries < 20; tries++ {
  47. // inlined this call because it ran out of stack when inlining was disabled
  48. err = int(call5(pthread_createABI0, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(pfn), uintptr(unsafe.Pointer(arg)), 0))
  49. if err == 0 {
  50. // inlined this call because it ran out of stack when inlining was disabled
  51. call5(pthread_detachABI0, uintptr(*thread), 0, 0, 0, 0)
  52. return 0
  53. }
  54. if err != int(syscall.EAGAIN) {
  55. return err
  56. }
  57. ts.Sec = 0
  58. ts.Nsec = (tries + 1) * 1000 * 1000 // Milliseconds.
  59. // inlined this call because it ran out of stack when inlining was disabled
  60. call5(nanosleepABI0, uintptr(unsafe.Pointer(&ts)), 0, 0, 0, 0)
  61. }
  62. return int(syscall.EAGAIN)
  63. }