github.com/ebitengine/purego@v0.8.0-alpha.2.0.20240512170805-6cd12240d332/internal/fakecgo/go_libinit.go (about)

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