summaryrefslogtreecommitdiff
path: root/vendor/github.com/ebitengine/purego/internal/fakecgo/go_util.go
blob: 0ac10d1f1578d411053b50a8754a3ee768ebf1f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors

//go:build !cgo && (darwin || freebsd || linux)

package fakecgo

import "unsafe"

// _cgo_thread_start is split into three parts in cgo since only one part is system dependent (keep it here for easier handling)

// _cgo_thread_start(ThreadStart *arg) (runtime/cgo/gcc_util.c)
// This get's called instead of the go code for creating new threads
// -> pthread_* stuff is used, so threads are setup correctly for C
// If this is missing, TLS is only setup correctly on thread 1!
// This function should be go:systemstack instead of go:nosplit (but that requires runtime)
//
//go:nosplit
//go:norace
func x_cgo_thread_start(arg *ThreadStart) {
	var ts *ThreadStart
	// Make our own copy that can persist after we return.
	//	_cgo_tsan_acquire();
	ts = (*ThreadStart)(malloc(unsafe.Sizeof(*ts)))
	//	_cgo_tsan_release();
	if ts == nil {
		println("fakecgo: out of memory in thread_start")
		abort()
	}
	// *ts = *arg would cause a writebarrier so copy using slices
	s1 := unsafe.Slice((*uintptr)(unsafe.Pointer(ts)), unsafe.Sizeof(*ts)/8)
	s2 := unsafe.Slice((*uintptr)(unsafe.Pointer(arg)), unsafe.Sizeof(*arg)/8)
	for i := range s2 {
		s1[i] = s2[i]
	}
	_cgo_sys_thread_start(ts) // OS-dependent half
}