ebitengine / purego

Apache License 2.0
2.16k stars 68 forks source link

thread local storage not work #137

Closed calvin2021y closed 1 year ago

calvin2021y commented 1 year ago

when link the dynamic library by cgo (without purego), thread local storage work fine.

when use purego load the dynamic library, thread local storage return 0 at first visit, then return value before assign from other os thread.

confirm the problem from linux, windows, macOS. (go1.20.5)

calvin2021y commented 1 year ago

This cloud related with bring the https://github.com/timandy/routine from purego test. I will do more to confirm.

turn out not related into this project.

calvin2021y commented 1 year ago

test to trigger this:

package main

import "C"
import (
    "fmt"
    "github.com/ebitengine/purego"
    "runtime"
    "time"
    "unsafe"
)

//go:linkname gopark runtime.gopark
func gopark(unlockf func(uintptr, unsafe.Pointer) bool, lock unsafe.Pointer, reason uint8, traceEv byte, traceskip int)

func main() {

    lib1, err := purego.Dlopen("printTls.dylib", purego.RTLD_NOW|purego.RTLD_GLOBAL)
    if err != nil {
        panic(err)
    }
    var printTls func(v1 uintptr, d uint32)
    purego.RegisterLibFunc(&printTls, uintptr(lib1), "printTls")

    go func() {
        for {
            time.Sleep(10 * time.Millisecond)
            printTls(0, 211)
        }
    }()

    var max uintptr = 1024 * 8
    var show_at uintptr = 211

    var i uintptr
    for i = 0; i < max; i++ {
        go func(i uintptr) {
            if i%show_at == 0 {
                fmt.Printf("inside %v\n", i)
            }
            gopark(nil, nil, 0, 0, 1)
        }(i)
    }

    time.Sleep(1000 * time.Millisecond)
}

printTls just some simple code to use tls and print it.

If remove fmt.Printf("inside %v\n", i), then the bug not triggered.

If reduce max number it also work, so could be some kind stack overflow.

TLS show wrong var some time correct some time not.

hajimehoshi commented 1 year ago

I think you need to use runtime.LockOSThread to use TLS correctly on a groutine.

calvin2021y commented 1 year ago

the tls only used from c and not related into go. to create a object for each os thread. (I am not sure how to free this object yet, maybe some code like on_thread_exit)

I will do more test to confirm

hajimehoshi commented 1 year ago

printTls should be called in an appropriate OS thread, right?

calvin2021y commented 1 year ago

yes.

I will call from a random go thread, which run inside a random go M, it will do it work inside c world.

calvin2021y commented 1 year ago

I guess this should be my code bugs, not related into purego. I will do more test to confirm

calvin2021y commented 1 year ago

should be my code problem