go_libinit.go raw

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