mirror of
https://github.com/golang/go.git
synced 2025-10-19 11:03:18 +00:00
os: fix race condition in readdir by atomically initializing dirinfo
This change ensures that dirinfo in the File struct is initialized atomically,
avoiding redundant allocations when multiple goroutines access it concurrently.
Instead of creating separate buffers, we now use CompareAndSwap to guarantee
thread-safe initialization and reduce unnecessary memory usage.
Although this is not a strict race condition, the update enhances efficiency by
eliminating duplicate allocations and ensuring safer concurrent access.
Fixes #71496.
Change-Id: If08699a94afa05611cdf67e82a5957a8d8f9d5c8
GitHub-Last-Rev: 1e1f619143
GitHub-Pull-Request: golang/go#71501
Reviewed-on: https://go-review.googlesource.com/c/go/+/645720
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
parent
a1ea78c470
commit
be2b809e5b
2 changed files with 24 additions and 9 deletions
|
@ -11,12 +11,19 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
|
func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
|
||||||
// If this file has no dirinfo, create one.
|
var d *dirInfo
|
||||||
d := file.dirinfo.Load()
|
for {
|
||||||
if d == nil {
|
d = file.dirinfo.Load()
|
||||||
d = new(dirInfo)
|
if d != nil {
|
||||||
file.dirinfo.Store(d)
|
break
|
||||||
|
}
|
||||||
|
newD := new(dirInfo)
|
||||||
|
if file.dirinfo.CompareAndSwap(nil, newD) {
|
||||||
|
d = newD
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
defer d.mu.Unlock()
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
|
|
@ -46,11 +46,19 @@ func (d *dirInfo) close() {
|
||||||
|
|
||||||
func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
|
func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) {
|
||||||
// If this file has no dirInfo, create one.
|
// If this file has no dirInfo, create one.
|
||||||
d := f.dirinfo.Load()
|
var d *dirInfo
|
||||||
if d == nil {
|
for {
|
||||||
d = new(dirInfo)
|
d = f.dirinfo.Load()
|
||||||
f.dirinfo.Store(d)
|
if d != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
newD := new(dirInfo)
|
||||||
|
if f.dirinfo.CompareAndSwap(nil, newD) {
|
||||||
|
d = newD
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
defer d.mu.Unlock()
|
defer d.mu.Unlock()
|
||||||
if d.buf == nil {
|
if d.buf == nil {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue