Skip to content

🐛 fix(win): eliminate lock file race in threaded usage#484

Merged
gaborbernat merged 1 commit intotox-dev:mainfrom
gaborbernat:fix-flaky-windows-threaded-tests
Feb 14, 2026
Merged

🐛 fix(win): eliminate lock file race in threaded usage#484
gaborbernat merged 1 commit intotox-dev:mainfrom
gaborbernat:fix-flaky-windows-threaded-tests

Conversation

@gaborbernat
Copy link
Member

@gaborbernat gaborbernat commented Feb 14, 2026

The Windows threaded lock tests flake on CI because _release() calls unlink() after close(), but between those two calls another thread has already acquired an open handle via os.open(). Since CPython's _wopen doesn't set FILE_SHARE_DELETE, Windows refuses the deletion — and the suppressed unlink() just widens the race window for no benefit. On top of that, O_TRUNC in _acquire() maps to CREATE_ALWAYS in CreateFileW, which causes EACCES when truncating a file that other threads hold open, pushing contending threads into the retry loop at the os.open level rather than just at msvcrt.locking.

The fix removes unlink() from _release() entirely — the lock file persists on disk, but _acquire() already handles existing files via O_CREAT, and the base class documents that lock files are not automatically deleted. It also drops O_TRUNC from _acquire(), since lock file content is irrelevant; only the msvcrt.locking byte-range lock provides mutual exclusion. Without O_TRUNC, O_RDWR | O_CREAT maps to OPEN_ALWAYS, which opens without truncation and avoids the write-sharing conflict.

With both race conditions eliminated, the threaded tests no longer need reduced iteration counts on Windows and now run at full Unix-equivalent intensity (100×100 and 10×1000).

@gaborbernat gaborbernat force-pushed the fix-flaky-windows-threaded-tests branch from d7b6ed7 to 28546c7 Compare February 14, 2026 05:35
@gaborbernat gaborbernat changed the title 🐛 fix(test): reduce threaded stress on Windows 🐛 fix(win): eliminate lock file race in threaded usage Feb 14, 2026
On Windows, _release() called unlink() after close(), but between those
calls another thread would already hold an open handle via os.open(),
preventing deletion (Windows can't delete files with open handles).
The suppressed unlink added a syscall that widened the race window for
no benefit. Additionally, O_TRUNC in _acquire() mapped to CREATE_ALWAYS
which caused EACCES when truncating a file with open handles from other
threads, pushing them into the retry loop at the os.open level.

Remove unlink() from _release() — the lock file persists on disk but
_acquire() already handles existing files via O_CREAT. Remove O_TRUNC
from _acquire() — lock file content is irrelevant, only the msvcrt
byte-range lock matters. This lets the threaded tests run at full
Unix-equivalent intensity on Windows.
@gaborbernat gaborbernat force-pushed the fix-flaky-windows-threaded-tests branch from 28546c7 to 3dc2db2 Compare February 14, 2026 05:40
@gaborbernat gaborbernat enabled auto-merge (squash) February 14, 2026 05:41
@gaborbernat gaborbernat disabled auto-merge February 14, 2026 05:50
@gaborbernat gaborbernat merged commit 23b797c into tox-dev:main Feb 14, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant