From 4fe1971b2dff1fa14cb8f5be47aed7fda76c0f7c Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 4 Oct 2022 14:35:39 -0700 Subject: os: use poll.fdMutex for Plan 9 files This permits us to safely support concurrent access to files on Plan 9. Concurrent access was already safe on other systems. This does introduce a change: if one goroutine calls a blocking read on a pipe, and another goroutine closes the pipe, then before this CL the close would occur. Now the close will be delayed until the blocking read completes. Also add tests that concurrent I/O and Close on a pipe are OK. For #50436 For #56043 Change-Id: I969c869ea3b8c5c2f2ef319e441a56a3c64e7bf5 Reviewed-on: https://go-review.googlesource.com/c/go/+/438347 Reviewed-by: Bryan Mills Reviewed-by: Ian Lance Taylor Reviewed-by: David du Colombier <0intro@gmail.com> Run-TryBot: Ian Lance Taylor Auto-Submit: Ian Lance Taylor TryBot-Result: Gopher Robot Reviewed-by: Rob Pike --- src/internal/poll/export_test.go | 12 +++++------ src/internal/poll/fd_mutex_test.go | 12 +++++------ src/internal/poll/file_plan9.go | 42 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 src/internal/poll/file_plan9.go (limited to 'src/internal') diff --git a/src/internal/poll/export_test.go b/src/internal/poll/export_test.go index 02664d9ea3..66d7c3274b 100644 --- a/src/internal/poll/export_test.go +++ b/src/internal/poll/export_test.go @@ -10,26 +10,26 @@ package poll var Consume = consume -type FDMutex struct { +type XFDMutex struct { fdMutex } -func (mu *FDMutex) Incref() bool { +func (mu *XFDMutex) Incref() bool { return mu.incref() } -func (mu *FDMutex) IncrefAndClose() bool { +func (mu *XFDMutex) IncrefAndClose() bool { return mu.increfAndClose() } -func (mu *FDMutex) Decref() bool { +func (mu *XFDMutex) Decref() bool { return mu.decref() } -func (mu *FDMutex) RWLock(read bool) bool { +func (mu *XFDMutex) RWLock(read bool) bool { return mu.rwlock(read) } -func (mu *FDMutex) RWUnlock(read bool) bool { +func (mu *XFDMutex) RWUnlock(read bool) bool { return mu.rwunlock(read) } diff --git a/src/internal/poll/fd_mutex_test.go b/src/internal/poll/fd_mutex_test.go index 3029b9a681..62f953192d 100644 --- a/src/internal/poll/fd_mutex_test.go +++ b/src/internal/poll/fd_mutex_test.go @@ -14,7 +14,7 @@ import ( ) func TestMutexLock(t *testing.T) { - var mu FDMutex + var mu XFDMutex if !mu.Incref() { t.Fatal("broken") @@ -39,7 +39,7 @@ func TestMutexLock(t *testing.T) { } func TestMutexClose(t *testing.T) { - var mu FDMutex + var mu XFDMutex if !mu.IncrefAndClose() { t.Fatal("broken") } @@ -60,7 +60,7 @@ func TestMutexClose(t *testing.T) { func TestMutexCloseUnblock(t *testing.T) { c := make(chan bool, 4) - var mu FDMutex + var mu XFDMutex mu.RWLock(true) for i := 0; i < 4; i++ { go func() { @@ -104,7 +104,7 @@ func TestMutexPanic(t *testing.T) { f() } - var mu FDMutex + var mu XFDMutex ensurePanics(func() { mu.Decref() }) ensurePanics(func() { mu.RWUnlock(true) }) ensurePanics(func() { mu.RWUnlock(false) }) @@ -137,7 +137,7 @@ func TestMutexOverflowPanic(t *testing.T) { } }() - var mu1 FDMutex + var mu1 XFDMutex for i := 0; i < 1<<21; i++ { mu1.Incref() } @@ -152,7 +152,7 @@ func TestMutexStress(t *testing.T) { } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P)) done := make(chan bool, P) - var mu FDMutex + var mu XFDMutex var readState [2]uint64 var writeState [2]uint64 for p := 0; p < P; p++ { diff --git a/src/internal/poll/file_plan9.go b/src/internal/poll/file_plan9.go new file mode 100644 index 0000000000..57dc0c668f --- /dev/null +++ b/src/internal/poll/file_plan9.go @@ -0,0 +1,42 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package poll + +// Expose fdMutex for use by the os package on Plan 9. +// On Plan 9 we don't want to use async I/O for file operations, +// but we still want the locking semantics that fdMutex provides. + +// FDMutex is an exported fdMutex, only for Plan 9. +type FDMutex struct { + fdmu fdMutex +} + +func (fdmu *FDMutex) Incref() bool { + return fdmu.fdmu.incref() +} + +func (fdmu *FDMutex) Decref() bool { + return fdmu.fdmu.decref() +} + +func (fdmu *FDMutex) IncrefAndClose() bool { + return fdmu.fdmu.increfAndClose() +} + +func (fdmu *FDMutex) ReadLock() bool { + return fdmu.fdmu.rwlock(true) +} + +func (fdmu *FDMutex) ReadUnlock() bool { + return fdmu.fdmu.rwunlock(true) +} + +func (fdmu *FDMutex) WriteLock() bool { + return fdmu.fdmu.rwlock(false) +} + +func (fdmu *FDMutex) WriteUnlock() bool { + return fdmu.fdmu.rwunlock(false) +} -- cgit v1.3