From 898493b3b3c2bb577f27d5f60a0ca87b9a285781 Mon Sep 17 00:00:00 2001 From: "duanyi.aster" Date: Wed, 30 Oct 2024 12:00:14 +0800 Subject: [PATCH 1/2] feat: register plugin use tango --- go.work.sum | 3 +- loader/register.go | 55 ++++++++++++++++++++++ loader/register_tango.go | 33 +++++++++++++ loader/{stubs_test.go => register_test.go} | 2 + loader/stubs.go | 32 ------------- 5 files changed, 92 insertions(+), 33 deletions(-) create mode 100644 loader/register.go create mode 100644 loader/register_tango.go rename loader/{stubs_test.go => register_test.go} (97%) diff --git a/go.work.sum b/go.work.sum index d59625879..8ee8d8cc5 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1 +1,2 @@ -github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cIyEbeXLBhy5Ha4nevyc= diff --git a/loader/register.go b/loader/register.go new file mode 100644 index 000000000..d32f9fa50 --- /dev/null +++ b/loader/register.go @@ -0,0 +1,55 @@ +// +build !bytedance_tango + +/** + * Copyright 2024 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package loader + +import ( + "sync/atomic" + "unsafe" +) + +func registerModule(mod *moduledata) { + registerModuleLockFree(&lastmoduledatap, mod) +} + +func registerModuleLockFree(tail **moduledata, mod *moduledata) { + for { + oldTail := loadModule(tail) + if casModule(tail, oldTail, mod) { + storeModule(&oldTail.next, mod) + break + } + } +} + +func loadModule(p **moduledata) *moduledata { + return (*moduledata)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) +} + +func storeModule(p **moduledata, value *moduledata) { + atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(value)) +} + +func casModule(p **moduledata, oldValue *moduledata, newValue *moduledata) bool { + return atomic.CompareAndSwapPointer( + (*unsafe.Pointer)(unsafe.Pointer(p)), + unsafe.Pointer(oldValue), + unsafe.Pointer(newValue), + ) +} + diff --git a/loader/register_tango.go b/loader/register_tango.go new file mode 100644 index 000000000..1c1c14fce --- /dev/null +++ b/loader/register_tango.go @@ -0,0 +1,33 @@ +// +build bytedance_tango + +/** + * Copyright 2024 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package loader + +import ( + "sync" + _ "unsafe" +) + +//go:linkname pluginsMu plugin.pluginsMu +var pluginsMu sync.Mutex + +func registerModule(mod *moduledata) { + pluginsMu.Lock() + defer pluginsMu.Unlock() + lastmoduledatap = mod +} diff --git a/loader/stubs_test.go b/loader/register_test.go similarity index 97% rename from loader/stubs_test.go rename to loader/register_test.go index 45bc6e35b..eb9b964a9 100644 --- a/loader/stubs_test.go +++ b/loader/register_test.go @@ -1,3 +1,5 @@ +// +build !bytedance_tango + /* * Copyright 2023 ByteDance Inc. * diff --git a/loader/stubs.go b/loader/stubs.go index 80f8de836..28aebd60b 100644 --- a/loader/stubs.go +++ b/loader/stubs.go @@ -17,8 +17,6 @@ package loader import ( - "sync/atomic" - "unsafe" _ `unsafe` ) @@ -26,35 +24,5 @@ import ( //goland:noinspection GoUnusedGlobalVariable var lastmoduledatap *moduledata -func registerModule(mod *moduledata) { - registerModuleLockFree(&lastmoduledatap, mod) -} - //go:linkname moduledataverify1 runtime.moduledataverify1 func moduledataverify1(_ *moduledata) - -func registerModuleLockFree(tail **moduledata, mod *moduledata) { - for { - oldTail := loadModule(tail) - if casModule(tail, oldTail, mod) { - storeModule(&oldTail.next, mod) - break - } - } -} - -func loadModule(p **moduledata) *moduledata { - return (*moduledata)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) -} - -func storeModule(p **moduledata, value *moduledata) { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(value)) -} - -func casModule(p **moduledata, oldValue *moduledata, newValue *moduledata) bool { - return atomic.CompareAndSwapPointer( - (*unsafe.Pointer)(unsafe.Pointer(p)), - unsafe.Pointer(oldValue), - unsafe.Pointer(newValue), - ) -} From 8b7c7b6de39adb21d09b4c24b8ed0fd1288e8924 Mon Sep 17 00:00:00 2001 From: "duanyi.aster" Date: Wed, 30 Oct 2024 12:18:17 +0800 Subject: [PATCH 2/2] test --- loader/register_tango.go | 1 + loader/register_test.go | 15 ++++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/loader/register_tango.go b/loader/register_tango.go index 1c1c14fce..08abfb5a8 100644 --- a/loader/register_tango.go +++ b/loader/register_tango.go @@ -29,5 +29,6 @@ var pluginsMu sync.Mutex func registerModule(mod *moduledata) { pluginsMu.Lock() defer pluginsMu.Unlock() + lastmoduledatap.next = mod lastmoduledatap = mod } diff --git a/loader/register_test.go b/loader/register_test.go index eb9b964a9..fcf63d5eb 100644 --- a/loader/register_test.go +++ b/loader/register_test.go @@ -1,5 +1,3 @@ -// +build !bytedance_tango - /* * Copyright 2023 ByteDance Inc. * @@ -23,17 +21,16 @@ import ( "sync" ) -func Test_registerModuleLockFree(t *testing.T) { - n, parallel := 1000, 8 - head := moduledata{} - tail := &head +func Test_registerModuleRace(t *testing.T) { + n, parallel := 100, 8 + s := &moduledata{} + registerModule(s) wg := sync.WaitGroup{} wg.Add(parallel) filler := func(n int) { defer wg.Done() for i := 0; i < n; i++ { - m := &moduledata{} - registerModuleLockFree(&tail, m) + registerModule(&moduledata{}) } } for i := 0; i < parallel; i++ { @@ -41,7 +38,7 @@ func Test_registerModuleLockFree(t *testing.T) { } wg.Wait() i := 0 - for p := head.next; p != nil; p = p.next { + for p := s.next; p != nil; p = p.next { i += 1 } if i != parallel * n {