diff --git a/c/pthread/sync/_pthd/pthd.c b/c/pthread/sync/_pthd/pthd.c index 453bbe4d..e8275a54 100644 --- a/c/pthread/sync/_pthd/pthd.c +++ b/c/pthread/sync/_pthd/pthd.c @@ -1,6 +1,7 @@ #include -pthread_once_t llgoSyncOnceInitVal() { - pthread_once_t initVal = PTHREAD_ONCE_INIT; - return initVal; -} +// ----------------------------------------------------------------------------- + +pthread_once_t llgoSyncOnceInitVal = PTHREAD_ONCE_INIT; + +// ----------------------------------------------------------------------------- diff --git a/c/pthread/sync/sync.go b/c/pthread/sync/sync.go index 2ddf2ee9..9fd3dd03 100644 --- a/c/pthread/sync/sync.go +++ b/c/pthread/sync/sync.go @@ -30,12 +30,15 @@ const ( LLGoPackage = "link" ) +// ----------------------------------------------------------------------------- + +// Once is an object that will perform exactly one action. type Once C.pthread_once_t -//go:linkname onceInitVal C.llgoSyncOnceInitVal -func onceInitVal() Once - -var OnceInit = onceInitVal() +//go:linkname OnceInit llgoSyncOnceInitVal +var OnceInit Once // llgo:link (*Once).Do C.pthread_once func (o *Once) Do(f func()) c.Int { return 0 } + +// ----------------------------------------------------------------------------- diff --git a/cl/_testlibgo/sync/in.go b/cl/_testlibgo/sync/in.go new file mode 100644 index 00000000..1442dbbd --- /dev/null +++ b/cl/_testlibgo/sync/in.go @@ -0,0 +1,18 @@ +package main + +import ( + "sync" +) + +var once sync.Once + +func f(s string) { + once.Do(func() { + println(s) + }) +} + +func main() { + f("Do once") + f("Do twice") +} diff --git a/cl/compile.go b/cl/compile.go index ec18c06f..dbfe8fa1 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -279,6 +279,9 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun } b.EndBuild() }) + for _, af := range f.AnonFuncs { + p.compileFuncDecl(pkg, af) + } } return fn, nil, goFunc } diff --git a/cl/import.go b/cl/import.go index fbbf4408..fc1bc46d 100644 --- a/cl/import.go +++ b/cl/import.go @@ -336,8 +336,14 @@ func typesFuncName(pkgPath string, fn *types.Func) (fullName, inPkgName string) // - func: pkg.name // - method: pkg.(T).name, pkg.(*T).name func funcName(pkg *types.Package, fn *ssa.Function) string { - sig := fn.Signature - return llssa.FuncName(pkg, fn.Name(), sig.Recv()) + var recv *types.Var + parent := fn.Parent() + if parent != nil { // closure in method + recv = parent.Signature.Recv() + } else { + recv = fn.Signature.Recv() + } + return llssa.FuncName(pkg, fn.Name(), recv) } func checkCgo(fnName string) bool { diff --git a/internal/lib/sync/sync.go b/internal/lib/sync/sync.go index 56822964..63f22d78 100644 --- a/internal/lib/sync/sync.go +++ b/internal/lib/sync/sync.go @@ -18,5 +18,39 @@ package sync // llgo:skipall import ( - _ "unsafe" + "unsafe" + + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/pthread" + "github.com/goplus/llgo/c/pthread/sync" ) + +const ( + LLGoPackage = "link" +) + +// ----------------------------------------------------------------------------- + +var onceParam pthread.Key + +func init() { + onceParam.Create(nil) +} + +type Once sync.Once + +func (o *Once) Do(f func()) { + ptr := c.Malloc(unsafe.Sizeof(f)) + *(*func())(ptr) = f + onceParam.Set(ptr) + if *(*c.Long)(unsafe.Pointer(o)) == 0 { // try init + *(*sync.Once)(o) = sync.OnceInit + } + (*sync.Once)(o).Do(func() { + ptr := onceParam.Get() + (*(*func())(ptr))() + c.Free(ptr) + }) +} + +// -----------------------------------------------------------------------------