From 38c78e1ba09e97cae9bc1d94a4d3e161bca2ae71 Mon Sep 17 00:00:00 2001 From: Edmond Date: Wed, 12 Aug 2026 19:59:58 +0000 Subject: [PATCH] #221: a test for more lock waiters than the pool has threads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eight coroutines take one lock in turn with UV_THREADPOOL_SIZE=4, each holding it across a suspension point so the waiters really overlap. Against the thread-pool flock the run never finishes; the file ends up with eight lines instead. The lock itself is checked, not only the deadlock: a waiter says so when flock() returns false, and each compares the file size across its own suspension, so a lock granted twice is reported rather than appended over. Removing the flock calls from the body turns the test red — six of eight waiters see another writer. 081 described the locker as blocked in the thread pool, which is no longer where it waits. --- .../io/081-flock_non_blocking_event_loop.phpt | 2 +- .../084-flock_waiters_exceed_threadpool.phpt | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 tests/io/084-flock_waiters_exceed_threadpool.phpt diff --git a/tests/io/081-flock_non_blocking_event_loop.phpt b/tests/io/081-flock_non_blocking_event_loop.phpt index 7951708b..f8c7dc3b 100644 --- a/tests/io/081-flock_non_blocking_event_loop.phpt +++ b/tests/io/081-flock_non_blocking_event_loop.phpt @@ -29,7 +29,7 @@ $worker = spawn(function() { echo "worker: running\n"; }); -// Let coroutines run — worker should complete, locker should be blocked in thread pool +// Let coroutines run — worker should complete, locker should still be waiting for the lock Async\delay(50); echo "main: unlocking\n"; diff --git a/tests/io/084-flock_waiters_exceed_threadpool.phpt b/tests/io/084-flock_waiters_exceed_threadpool.phpt new file mode 100644 index 00000000..a3d472a6 --- /dev/null +++ b/tests/io/084-flock_waiters_exceed_threadpool.phpt @@ -0,0 +1,68 @@ +--TEST-- +More coroutines waiting for one file lock than the thread pool has threads +--DESCRIPTION-- +Eight coroutines lock one file with the libuv thread pool pinned to four threads: each +writes one line while holding the lock, and all eight lines must appear. A waiter must not +occupy a pool thread. Reads and writes of a regular file are uv_fs requests on that same +pool, so waiters that fill it leave the lock holder's own write with no thread to run on, +and the lock is never released. A regression therefore shows as a hang with no output at +all, not as a wrong count of lines. The lock itself is checked too: every waiter fails +loudly if flock() returns false, and each compares the file size across its own suspension +so that a lock granted to two coroutines at once is reported rather than appended over. +true-async/php-async#221. +--ENV-- +UV_THREADPOOL_SIZE=4 +--FILE-- + +--CLEAN-- + +--EXPECT-- +lines: 8 +ok