Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions c/pthread/generated_native_darwin_arm64_llgo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build llgo && darwin && arm64 && !ios

package pthread_test

import (
"github.com/goplus/lib/c"
"github.com/goplus/lib/c/pthread"
"unsafe"
)

// nativeJoin follows the platform-specific method/global shape emitted for pthread_t.
func nativeJoin(thread pthread.Thread, result *unsafe.Pointer) c.Int {
return thread.NativeJoin(result)
}
14 changes: 14 additions & 0 deletions c/pthread/generated_native_linux_llgo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build llgo && linux && (amd64 || arm64) && !android

package pthread_test

import (
"github.com/goplus/lib/c"
"github.com/goplus/lib/c/pthread"
"unsafe"
)

// nativeJoin follows the platform-specific method/global shape emitted for pthread_t.
func nativeJoin(thread pthread.Thread, result *unsafe.Pointer) c.Int {
return pthread.NativeJoin(thread, result)
}
109 changes: 109 additions & 0 deletions c/pthread/generated_native_llgo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//go:build llgo && ((darwin && arm64 && !ios) || (linux && (amd64 || arm64) && !android))

package pthread_test

import (
"github.com/goplus/lib/c"
"github.com/goplus/lib/c/pthread"
"runtime"
"testing"
"unsafe"
)

func TestGeneratedThreadAttributeLayout(t *testing.T) {
size := uintptr(64)
keySize := uintptr(4)
if runtime.GOOS == "linux" && runtime.GOARCH == "amd64" {
size = 56
}
if runtime.GOOS == "darwin" {
keySize = 8
}
var attr pthread.Attr
var key pthread.Key
if unsafe.Sizeof(attr) != size || unsafe.Alignof(attr) != 8 {
t.Fatalf("pthread_attr_t = %d/%d, want %d/8", unsafe.Sizeof(attr), unsafe.Alignof(attr), size)
}
if unsafe.Sizeof(key) != keySize {
t.Fatalf("pthread_key_t = %d, want %d", unsafe.Sizeof(key), keySize)
}
}
func TestGeneratedThreadAttributes(t *testing.T) {
t.Run("thread local storage", func(t *testing.T) {
var key pthread.Key
if result := key.Create(nil); result != 0 {
t.Fatalf("pthread_key_create = %d", result)
}
defer func() {
if result := key.Delete(); result != 0 {
t.Errorf("pthread_key_delete = %d", result)
}
}()
if got := key.Get(); got != nil {
t.Fatalf("pthread_getspecific initial value = %p, want nil", got)
}
var value c.Int = 123
expected := unsafe.Pointer(&value)
if result := key.Set(expected); result != 0 {
t.Fatalf("pthread_setspecific = %d", result)
}
if got := key.Get(); got != expected {
t.Fatalf("pthread_getspecific = %p, want %p", got, expected)
}
if result := key.Set(nil); result != 0 {
t.Fatalf("pthread_setspecific reset = %d", result)
}
})
var probe struct {
before [8]byte
attr pthread.Attr
after [8]byte
}
for i := range probe.before {
probe.before[i] = 0xa5
probe.after[i] = 0xa5
}
if result := probe.attr.Init(); result != 0 {
t.Fatalf("attr_init = %d", result)
}
defer func() {
if result := probe.attr.Destroy(); result != 0 {
t.Errorf("attr_destroy = %d", result)
}
}()
var size c.SizeT
if result := probe.attr.GetStackSize(&size); result != 0 || size == 0 {
t.Fatalf("attr_getstacksize = %d, value %d", result, size)
}
const requested = 1 << 20
if result := probe.attr.SetStackSize(requested); result != 0 {
t.Fatalf("attr_setstacksize = %d", result)
}
if result := probe.attr.GetStackSize(&size); result != 0 || size != requested {
t.Fatalf("stack size = %d, result %d", size, result)
}
for i := range probe.before {
if probe.before[i] != 0xa5 || probe.after[i] != 0xa5 {
t.Fatal("attribute operation overwrote a buffer boundary")
}
}
}

//llgo:type C
type nativeThreadStart func(unsafe.Pointer) unsafe.Pointer

func TestGeneratedNativeThreadRoundtrip(t *testing.T) {
var thread pthread.Thread
var marker uintptr = 123
start := nativeThreadStart(func(argument unsafe.Pointer) unsafe.Pointer { return argument })
if result := pthread.NativeCreate(&thread, nil, start, unsafe.Pointer(&marker)); result != 0 {
t.Fatalf("pthread_create = %d", result)
}
var returned unsafe.Pointer
if result := nativeJoin(thread, &returned); result != 0 {
t.Fatalf("pthread_join = %d", result)
}
if returned != unsafe.Pointer(&marker) {
t.Fatalf("thread result = %p, want %p", returned, &marker)
}
}
62 changes: 62 additions & 0 deletions c/pthread/legacy_functions_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//go:build !windows && !((darwin && arm64 && !ios) || (linux && (amd64 || arm64) && !android))

package pthread

import (
"github.com/goplus/lib/c"
_ "unsafe"
)

// The pthread_exit() function terminates the calling thread and
// returns a value via retval that (if the thread is joinable) is
// available to another thread in the same process that calls
// pthread_join(3).
//
// See https://man7.org/linux/man-pages/man3/pthread_exit.3.html
//
//go:linkname Exit C.pthread_exit
func Exit(retval c.Pointer)

// The pthread_cancel() function sends a cancelation request to the
// thread thread.
//
// See https://man7.org/linux/man-pages/man3/pthread_cancel.3.html
//
//go:linkname Cancel C.pthread_cancel
func Cancel(thread Thread) c.Int

// llgo:link (*Attr).Init C.pthread_attr_init
func (attr *Attr) Init() c.Int { return 0 }

// llgo:link (*Attr).Destroy C.pthread_attr_destroy
func (attr *Attr) Destroy() c.Int { return 0 }

// llgo:link (*Attr).GetDetached C.pthread_attr_getdetachstate
func (attr *Attr) GetDetached(detached *c.Int) c.Int { return 0 }

// llgo:link (*Attr).SetDetached C.pthread_attr_setdetachstate
func (attr *Attr) SetDetached(detached c.Int) c.Int { return 0 }

// llgo:link (*Attr).GetStackSize C.pthread_attr_getstacksize
func (attr *Attr) GetStackSize(stackSize *uintptr) c.Int { return 0 }

// llgo:link (*Attr).SetStackSize C.pthread_attr_setstacksize
func (attr *Attr) SetStackSize(stackSize uintptr) c.Int { return 0 }

// llgo:link (*Attr).GetStackAddr C.pthread_attr_getstackaddr
func (attr *Attr) GetStackAddr(stackAddr *c.Pointer) c.Int { return 0 }

// llgo:link (*Attr).SetStackAddr C.pthread_attr_setstackaddr
func (attr *Attr) SetStackAddr(stackAddr c.Pointer) c.Int { return 0 }

// llgo:link (*Key).Create C.pthread_key_create
func (key *Key) Create(destructor func(c.Pointer)) c.Int { return 0 }

// llgo:link Key.Delete C.pthread_key_delete
func (key Key) Delete() c.Int { return 0 }

// llgo:link Key.Get C.pthread_getspecific
func (key Key) Get() c.Pointer { return nil }

// llgo:link Key.Set C.pthread_setspecific
func (key Key) Set(value c.Pointer) c.Int { return __noop__() }
Loading
Loading