mirror of
https://github.com/golang/go
synced 2024-11-26 02:57:57 -07:00
sync: use atomic.Pointer for entry
Change-Id: Ie3b4bfe483d7ef43da29ea1dd73d423dac36cf39 Reviewed-on: https://go-review.googlesource.com/c/go/+/432055 Auto-Submit: Bryan Mills <bcmills@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Changkun Ou <mail@changkun.de>
This commit is contained in:
parent
3aebf682e4
commit
7366b199c5
@ -6,7 +6,6 @@ package sync
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Map is like a Go map[interface{}]interface{} but is safe for concurrent use
|
||||
@ -74,7 +73,7 @@ type readOnly struct {
|
||||
|
||||
// expunged is an arbitrary pointer that marks entries which have been deleted
|
||||
// from the dirty map.
|
||||
var expunged = unsafe.Pointer(new(any))
|
||||
var expunged = new(any)
|
||||
|
||||
// An entry is a slot in the map corresponding to a particular key.
|
||||
type entry struct {
|
||||
@ -97,11 +96,13 @@ type entry struct {
|
||||
// p != expunged. If p == expunged, an entry's associated value can be updated
|
||||
// only after first setting m.dirty[key] = e so that lookups using the dirty
|
||||
// map find the entry.
|
||||
p unsafe.Pointer // *interface{}
|
||||
p atomic.Pointer[any]
|
||||
}
|
||||
|
||||
func newEntry(i any) *entry {
|
||||
return &entry{p: unsafe.Pointer(&i)}
|
||||
e := &entry{}
|
||||
e.p.Store(&i)
|
||||
return e
|
||||
}
|
||||
|
||||
func (m *Map) loadReadOnly() readOnly {
|
||||
@ -140,11 +141,11 @@ func (m *Map) Load(key any) (value any, ok bool) {
|
||||
}
|
||||
|
||||
func (e *entry) load() (value any, ok bool) {
|
||||
p := atomic.LoadPointer(&e.p)
|
||||
p := e.p.Load()
|
||||
if p == nil || p == expunged {
|
||||
return nil, false
|
||||
}
|
||||
return *(*any)(p), true
|
||||
return *p, true
|
||||
}
|
||||
|
||||
// Store sets the value for a key.
|
||||
@ -183,11 +184,11 @@ func (m *Map) Store(key, value any) {
|
||||
// unchanged.
|
||||
func (e *entry) tryStore(i *any) bool {
|
||||
for {
|
||||
p := atomic.LoadPointer(&e.p)
|
||||
p := e.p.Load()
|
||||
if p == expunged {
|
||||
return false
|
||||
}
|
||||
if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) {
|
||||
if e.p.CompareAndSwap(p, i) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -198,14 +199,14 @@ func (e *entry) tryStore(i *any) bool {
|
||||
// If the entry was previously expunged, it must be added to the dirty map
|
||||
// before m.mu is unlocked.
|
||||
func (e *entry) unexpungeLocked() (wasExpunged bool) {
|
||||
return atomic.CompareAndSwapPointer(&e.p, expunged, nil)
|
||||
return e.p.CompareAndSwap(expunged, nil)
|
||||
}
|
||||
|
||||
// storeLocked unconditionally stores a value to the entry.
|
||||
//
|
||||
// The entry must be known not to be expunged.
|
||||
func (e *entry) storeLocked(i *any) {
|
||||
atomic.StorePointer(&e.p, unsafe.Pointer(i))
|
||||
e.p.Store(i)
|
||||
}
|
||||
|
||||
// LoadOrStore returns the existing value for the key if present.
|
||||
@ -252,12 +253,12 @@ func (m *Map) LoadOrStore(key, value any) (actual any, loaded bool) {
|
||||
// If the entry is expunged, tryLoadOrStore leaves the entry unchanged and
|
||||
// returns with ok==false.
|
||||
func (e *entry) tryLoadOrStore(i any) (actual any, loaded, ok bool) {
|
||||
p := atomic.LoadPointer(&e.p)
|
||||
p := e.p.Load()
|
||||
if p == expunged {
|
||||
return nil, false, false
|
||||
}
|
||||
if p != nil {
|
||||
return *(*any)(p), true, true
|
||||
return *p, true, true
|
||||
}
|
||||
|
||||
// Copy the interface after the first load to make this method more amenable
|
||||
@ -265,15 +266,15 @@ func (e *entry) tryLoadOrStore(i any) (actual any, loaded, ok bool) {
|
||||
// shouldn't bother heap-allocating.
|
||||
ic := i
|
||||
for {
|
||||
if atomic.CompareAndSwapPointer(&e.p, nil, unsafe.Pointer(&ic)) {
|
||||
if e.p.CompareAndSwap(nil, &ic) {
|
||||
return i, false, true
|
||||
}
|
||||
p = atomic.LoadPointer(&e.p)
|
||||
p = e.p.Load()
|
||||
if p == expunged {
|
||||
return nil, false, false
|
||||
}
|
||||
if p != nil {
|
||||
return *(*any)(p), true, true
|
||||
return *p, true, true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -310,12 +311,12 @@ func (m *Map) Delete(key any) {
|
||||
|
||||
func (e *entry) delete() (value any, ok bool) {
|
||||
for {
|
||||
p := atomic.LoadPointer(&e.p)
|
||||
p := e.p.Load()
|
||||
if p == nil || p == expunged {
|
||||
return nil, false
|
||||
}
|
||||
if atomic.CompareAndSwapPointer(&e.p, p, nil) {
|
||||
return *(*any)(p), true
|
||||
if e.p.CompareAndSwap(p, nil) {
|
||||
return *p, true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -389,12 +390,12 @@ func (m *Map) dirtyLocked() {
|
||||
}
|
||||
|
||||
func (e *entry) tryExpungeLocked() (isExpunged bool) {
|
||||
p := atomic.LoadPointer(&e.p)
|
||||
p := e.p.Load()
|
||||
for p == nil {
|
||||
if atomic.CompareAndSwapPointer(&e.p, nil, expunged) {
|
||||
if e.p.CompareAndSwap(nil, expunged) {
|
||||
return true
|
||||
}
|
||||
p = atomic.LoadPointer(&e.p)
|
||||
p = e.p.Load()
|
||||
}
|
||||
return p == expunged
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user