From f34bf4ca38af8b5adcf36b67de5ea6fb853e4823 Mon Sep 17 00:00:00 2001 From: xhd2015 Date: Wed, 10 Apr 2024 14:55:14 +0800 Subject: [PATCH] add tls --- cmd/xgo/version.go | 6 +-- runtime/core/version.go | 6 +-- runtime/tls/hook.go | 50 ++++++++++++++++++++++++ runtime/tls/tls.go | 85 +++++++++++++++++++++++++++++++++++++++++ runtime/tls/tls_test.go | 56 +++++++++++++++++++++++++++ 5 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 runtime/tls/hook.go create mode 100644 runtime/tls/tls.go create mode 100644 runtime/tls/tls_test.go diff --git a/cmd/xgo/version.go b/cmd/xgo/version.go index 5bc5517b..cce7fce5 100644 --- a/cmd/xgo/version.go +++ b/cmd/xgo/version.go @@ -2,9 +2,9 @@ package main import "fmt" -const VERSION = "1.0.20" -const REVISION = "7ab84d83e8d847f0c2307a44866705581ba5cbbe+1" -const NUMBER = 172 +const VERSION = "1.0.21" +const REVISION = "60d0e314753d95e7d630a307ef991ac7bc21807e+1" +const NUMBER = 173 func getRevision() string { revSuffix := "" diff --git a/runtime/core/version.go b/runtime/core/version.go index b6ac297e..767b39a1 100644 --- a/runtime/core/version.go +++ b/runtime/core/version.go @@ -6,9 +6,9 @@ import ( "os" ) -const VERSION = "1.0.20" -const REVISION = "7ab84d83e8d847f0c2307a44866705581ba5cbbe+1" -const NUMBER = 172 +const VERSION = "1.0.21" +const REVISION = "60d0e314753d95e7d630a307ef991ac7bc21807e+1" +const NUMBER = 173 // these fields will be filled by compiler const XGO_VERSION = "" diff --git a/runtime/tls/hook.go b/runtime/tls/hook.go new file mode 100644 index 00000000..e3235e11 --- /dev/null +++ b/runtime/tls/hook.go @@ -0,0 +1,50 @@ +package tls + +import ( + "fmt" + "os" + "unsafe" +) + +func __xgo_link_on_gonewproc(f func(g uintptr)) { + fmt.Fprintln(os.Stderr, "WARNING: failed to link __xgo_link_on_gonewproc(requires xgo).") +} + +func __xgo_link_getcurg() unsafe.Pointer { + fmt.Fprintln(os.Stderr, "WARNING: failed to link __xgo_link_getcurg(requires xgo).") + return nil +} + +func __xgo_link_on_goexit(fn func()) { + fmt.Fprintln(os.Stderr, "WARNING: failed to link __xgo_link_on_goexit(requires xgo).") +} + +func init() { + __xgo_link_on_goexit(func() { + // clear when exit + g := uintptr(__xgo_link_getcurg()) + mut.Lock() + localKeys := keys + mut.Unlock() + for _, loc := range localKeys { + loc.store.Delete(g) + } + }) + __xgo_link_on_gonewproc(func(newg uintptr) { + // inherit when new goroutine + g := uintptr(__xgo_link_getcurg()) + mut.Lock() + localKeys := keys + mut.Unlock() + for _, loc := range localKeys { + if !loc.inherit { + continue + } + val, ok := loc.store.Load(g) + if !ok { + continue + } + loc.store.Store(newg, val) + } + }) +} diff --git a/runtime/tls/tls.go b/runtime/tls/tls.go new file mode 100644 index 00000000..db0ebf14 --- /dev/null +++ b/runtime/tls/tls.go @@ -0,0 +1,85 @@ +package tls + +import ( + "sync" +) + +var mut sync.Mutex +var keys []*tlsKey + +type TLSKey interface { + Get() interface{} + GetOK() (interface{}, bool) + Set(v interface{}) +} + +type tlsKey struct { + name string // for debugging purepose + inherit bool + store sync.Map // -> interface{} +} + +var _ TLSKey = (*tlsKey)(nil) + +func Declare(name string) TLSKey { + b := &TLSBuilder{ + name: name, + } + return b.Declare() +} +func DeclareInherit(name string) TLSKey { + b := &TLSBuilder{ + name: name, + inherit: true, + } + return b.Declare() +} + +type TLSBuilder struct { + name string + inherit bool +} + +func New() *TLSBuilder { + return &TLSBuilder{} +} + +func (c *TLSBuilder) Name(name string) *TLSBuilder { + c.name = name + return c +} + +func (c *TLSBuilder) Inherit() *TLSBuilder { + c.inherit = true + return c +} + +func (c *TLSBuilder) Declare() TLSKey { + key := &tlsKey{ + name: c.name, + inherit: c.inherit, + } + mut.Lock() + keys = append(keys, key) + mut.Unlock() + return key +} + +func (c *tlsKey) Get() interface{} { + key := uintptr(__xgo_link_getcurg()) + val, ok := c.store.Load(key) + if !ok { + return nil + } + return val +} + +func (c *tlsKey) GetOK() (interface{}, bool) { + key := uintptr(__xgo_link_getcurg()) + return c.store.Load(key) +} + +func (c *tlsKey) Set(v interface{}) { + key := uintptr(__xgo_link_getcurg()) + c.store.Store(key, v) +} diff --git a/runtime/tls/tls_test.go b/runtime/tls/tls_test.go new file mode 100644 index 00000000..898463bc --- /dev/null +++ b/runtime/tls/tls_test.go @@ -0,0 +1,56 @@ +package tls_test + +import ( + "testing" + + "github.com/xhd2015/xgo/runtime/tls" +) + +var a = tls.Declare("a") +var b = tls.DeclareInherit("b") + +func TestDeclareLocal(t *testing.T) { + a.Set(1) + + var v1 interface{} + done := make(chan struct{}) + go func() { + v1 = a.Get() + close(done) + }() + <-done + + v2 := a.Get() + + if v1 != nil { + t.Fatalf("expect sub goroutine get nil, actual: %v", v1) + } + + if i := v2.(int); i != 1 { + t.Fatalf("expect current goroutine get %d, actual: %d", 1, i) + } +} + +func TestInerhitLocal(t *testing.T) { + b.Set(1) + + var v1 interface{} + done := make(chan struct{}) + go func() { + v1 = b.Get() + close(done) + }() + <-done + + v2 := b.Get() + + if v1 == nil { + t.Fatalf("expect sub goroutine inherit b, actual: %v", v1) + } + if i := v1.(int); i != 1 { + t.Fatalf("expect sub goroutine get %d, actual: %d", 1, i) + } + if i := v2.(int); i != 1 { + t.Fatalf("expect current goroutine get %d, actual: %d", 1, i) + } +}