diff --git a/vfs/lock.go b/vfs/lock.go index d8450d7..1b70549 100644 --- a/vfs/lock.go +++ b/vfs/lock.go @@ -65,14 +65,20 @@ func (f *vfsFile) Lock(lock LockLevel) error { if f.lock <= LOCK_NONE || f.lock >= LOCK_EXCLUSIVE { panic(util.AssertErr()) } + reserved := f.lock == LOCK_RESERVED // A PENDING lock is needed before acquiring an EXCLUSIVE lock. if f.lock < LOCK_PENDING { - if rc := osGetPendingLock(f.File, f.lock); rc != _OK { + // If we're already RESERVED, we can block indefinitely, + // since only new readers may briefly hold the PENDING lock. + if rc := osGetPendingLock(f.File, reserved /* block */); rc != _OK { return rc } f.lock = LOCK_PENDING } - if rc := osGetExclusiveLock(f.File); rc != _OK { + // We already have PENDING, so we're just waiting for readers to leave. + // If we were RESERVED, we can wait for a little while, before invoking + // the busy handler; we will only do this once. + if rc := osGetExclusiveLock(f.File, reserved /* wait */); rc != _OK { return rc } f.lock = LOCK_EXCLUSIVE diff --git a/vfs/os_nolock.go b/vfs/os_nolock.go index 7a38737..4bceefe 100644 --- a/vfs/os_nolock.go +++ b/vfs/os_nolock.go @@ -20,11 +20,11 @@ func osGetReservedLock(_ *os.File) _ErrorCode { return _IOERR_LOCK } -func osGetPendingLock(_ *os.File, _ LockLevel) _ErrorCode { +func osGetPendingLock(_ *os.File, _ bool) _ErrorCode { return _IOERR_LOCK } -func osGetExclusiveLock(_ *os.File) _ErrorCode { +func osGetExclusiveLock(_ *os.File, _ bool) _ErrorCode { return _IOERR_LOCK } diff --git a/vfs/os_unix_lock.go b/vfs/os_unix_lock.go index 254bde8..15db23f 100644 --- a/vfs/os_unix_lock.go +++ b/vfs/os_unix_lock.go @@ -31,18 +31,22 @@ func osGetReservedLock(file *os.File) _ErrorCode { return osWriteLock(file, _RESERVED_BYTE, 1, 0) } -func osGetPendingLock(file *os.File, state LockLevel) _ErrorCode { - // Acquire the PENDING lock. +func osGetPendingLock(file *os.File, block bool) _ErrorCode { var timeout time.Duration - if state >= LOCK_RESERVED { + if block { timeout = -1 } + // Acquire the PENDING lock. return osWriteLock(file, _PENDING_BYTE, 1, timeout) } -func osGetExclusiveLock(file *os.File) _ErrorCode { +func osGetExclusiveLock(file *os.File, wait bool) _ErrorCode { + var timeout time.Duration + if wait { + timeout = time.Millisecond + } // Acquire the EXCLUSIVE lock. - return osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, time.Millisecond) + return osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, timeout) } func osDowngradeLock(file *os.File, state LockLevel) _ErrorCode { diff --git a/vfs/os_windows.go b/vfs/os_windows.go index 1c90c73..abc6c4b 100644 --- a/vfs/os_windows.go +++ b/vfs/os_windows.go @@ -36,21 +36,27 @@ func osGetReservedLock(file *os.File) _ErrorCode { return osWriteLock(file, _RESERVED_BYTE, 1, 0) } -func osGetPendingLock(file *os.File, state LockLevel) _ErrorCode { - // Acquire the PENDING lock. +func osGetPendingLock(file *os.File, block bool) _ErrorCode { var timeout time.Duration - if state >= LOCK_RESERVED { + if block { timeout = -1 } + + // Acquire the PENDING lock. return osWriteLock(file, _PENDING_BYTE, 1, timeout) } -func osGetExclusiveLock(file *os.File) _ErrorCode { +func osGetExclusiveLock(file *os.File, wait bool) _ErrorCode { + var timeout time.Duration + if wait { + timeout = time.Millisecond + } + // Release the SHARED lock. osUnlock(file, _SHARED_FIRST, _SHARED_SIZE) // Acquire the EXCLUSIVE lock. - rc := osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, time.Millisecond) + rc := osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, timeout) if rc != _OK { // Reacquire the SHARED lock. @@ -179,9 +185,13 @@ func osLockErrorCode(err error, def _ErrorCode) _ErrorCode { func osSleep(d time.Duration) { if d > 0 { - period := uint32(max(1, min(d/(2*time.Millisecond), 16))) - windows.TimeBeginPeriod(period) + period := max(1, d/(5*time.Millisecond)) + if period < 16 { + windows.TimeBeginPeriod(uint32(period)) + } time.Sleep(d) - windows.TimeEndPeriod(period) + if period < 16 { + windows.TimeEndPeriod(uint32(period)) + } } }