]> Cypherpunks.ru repositories - gostls13.git/commitdiff
Revert "sync: convert Once.done to atomic type"
authorIan Lance Taylor <iant@golang.org>
Wed, 7 Sep 2022 01:14:31 +0000 (01:14 +0000)
committerGopher Robot <gobot@golang.org>
Wed, 7 Sep 2022 13:22:04 +0000 (13:22 +0000)
This reverts commit CL 427140.

Reason for revert: Comments say that done should be the first field.

Change-Id: Id131da064146b44e1182289546aeb877867e63cc
Reviewed-on: https://go-review.googlesource.com/c/go/+/428638
Run-TryBot: Ian Lance Taylor <iant@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/sync/once.go
test/inline_sync.go

index 587eab0af9d471ece45d5633d726995fec6d7fa7..b6399cfc3d100a657f545000cf651e4a95ccd737 100644 (file)
@@ -16,13 +16,13 @@ import (
 // the return from f “synchronizes before”
 // the return from any call of once.Do(f).
 type Once struct {
-       m Mutex
        // done indicates whether the action has been performed.
        // It is first in the struct because it is used in the hot path.
        // The hot path is inlined at every call site.
        // Placing done first allows more compact instructions on some architectures (amd64/386),
        // and fewer instructions (to calculate offset) on other architectures.
-       done atomic.Bool
+       done uint32
+       m    Mutex
 }
 
 // Do calls the function f if and only if Do is being called for the
@@ -48,7 +48,7 @@ type Once struct {
 func (o *Once) Do(f func()) {
        // Note: Here is an incorrect implementation of Do:
        //
-       //      if o.done.CompareAndSwap(false, true) {
+       //      if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
        //              f()
        //      }
        //
@@ -58,9 +58,9 @@ func (o *Once) Do(f func()) {
        // call f, and the second would return immediately, without
        // waiting for the first's call to f to complete.
        // This is why the slow path falls back to a mutex, and why
-       // the o.done.Store must be delayed until after f returns.
+       // the atomic.StoreUint32 must be delayed until after f returns.
 
-       if !o.done.Load() {
+       if atomic.LoadUint32(&o.done) == 0 {
                // Outlined slow-path to allow inlining of the fast-path.
                o.doSlow(f)
        }
@@ -69,8 +69,8 @@ func (o *Once) Do(f func()) {
 func (o *Once) doSlow(f func()) {
        o.m.Lock()
        defer o.m.Unlock()
-       if !o.done.Load() {
-               defer o.done.Store(true)
+       if o.done == 0 {
+               defer atomic.StoreUint32(&o.done, 1)
                f()
        }
 }
index d1ce5f521cf0bb7e8733bb12050cf5d38efa69a2..30b436af41289cb4b016bc34b401dd9e1a9880a2 100644 (file)
@@ -36,7 +36,7 @@ var once *sync.Once
 
 func small7() { // ERROR "can inline small7"
         // the Do fast path should be inlined
-        once.Do(small5) // ERROR "(inlining call to sync\.\(\*Once\)\.Do|inlining call to atomic\.\(\*Bool\)\.Load)"
+        once.Do(small5) // ERROR "inlining call to sync\.\(\*Once\)\.Do"
 }
 
 var rwmutex *sync.RWMutex