Repository navigation
Commit 7e47043
committed
fix(tests): make the lock-registry absolute-deadline fixture deterministic
lock_registry_absolute_deadline_survives_repeated_wakes has failed on the
test-unix (macos-15-intel) leg of three unrelated pull requests in one
week -- #1342 (08-28), #1811 (09-02) and #1819 (09-03, run 33799475629,
job 100823626965) -- always with the same signature:
FAIL tests/test_lock_registry.c:1153: ASSERT(tail_queued)
7648 passed / 1 failed
The registry is not racy. cbm_lock_registry_acquire enqueues the waiter
synchronously under the registry mutex before any wait, so waiter_count
and the attempting count are exact. The defect is in the fixture: it
raced two wall-clock windows against each other, both anchored to a
timestamp the observer thread took before the tail thread had even been
scheduled.
deadline_start = cbm_now_ms();
tail.deadline_ms = deadline_start + 200; /* the tail's acquire deadline */
queue_deadline = deadline_start + 100; /* the observer's budget */
Because both windows start before the tail runs, a loaded runner breaks
the fixture two different ways:
* the tail is scheduled inside its deadline but after the observer's
100 ms budget has expired -- the queued state existed and was simply
no longer being looked at; or
* the tail is scheduled more than 200 ms late, in which case its
deadline has already passed when it finally calls acquire, the
pre-registration deadline check in lock_registry_acquire_internal
returns BUSY immediately, and the tail never enqueues at all -- the
asserted state can then never occur, however long the observer waits.
lock_registry is in the parallel wave of run-tests-parallel.sh, not the
serial tail, so on a small CI runner it competes with a full wave of
sanitized suites -- exactly the scheduling delay both paths need.
Widening the observer's budget would only paper over the first path, and
the state it waits for is transient by construction: it exists only
between the tail's enqueue and the tail's own deadline. So the fixture is
rebuilt to observe states that cannot evaporate.
* The tail anchors its absolute deadline itself, in its own thread,
immediately before the acquire it bounds. Scheduling delay can no
longer consume the deadline before the call starts, so the enqueue is
unconditional, and elapsed is measured from the tail's own anchor --
it now times the registry instead of timing the scheduler.
* Enqueue is exposed as a monotonic counter,
cbm_lock_registry_waiter_enqueue_count_for_test, next to the existing
test_condition_wait_calls counter it is modelled on. Because the
count only ever grows, the observer reads it once after the tail has
returned rather than trying to catch a live queue depth: the polling
loop, and with it the window, is gone.
* The fixture's remaining 500 ms and 600 ms budgets become the file's
LOCK_REGISTRY_TEST_TIMEOUT_MS backstop, and each loop exits on the
state it waits for instead of on the clock, so the backstop only
fires when the product is actually broken.
The contract is unchanged: the tail must still return at its absolute
deadline (150 <= elapsed < 350 ms for a 200 ms deadline) despite ~40
unrelated cancel broadcasts, still with BUSY and no lease, with the head
still holding the attempt. The broadcast loop now starts immediately
after the tail is released, so it overlaps the tail's wait at least as
much as it did before.
Verification, all on macOS arm64 with the sanitized runner:
* The mechanism was reproduced locally by delaying only the tail thread
after its start gate, with production untouched. A 120 ms delay (the
state exists, outside the observer's budget) and a 250 ms delay (the
tail never enqueues) each produced exactly one failure,
ASSERT(tail_queued) -- the CI signature.
* After the rebuild the same injections are green at 120, 250, 400 and
900 ms: an arbitrary scheduling delay no longer decides the verdict.
* lock_registry 30/30 green plain and 30/30 green under four CPU hogs;
16/16 inside the saturated 18-job parallel wave.
* private_file_lock, lock_registry, daemon, project_lock and the
daemon_* suites: 222 passed, 1 skipped.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>1 parent ffb5ebe commit 7e47043
3 files changed
Lines changed: 37 additions & 21 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
66 | 66 | | |
67 | 67 | | |
68 | 68 | | |
| 69 | + | |
69 | 70 | | |
70 | 71 | | |
71 | 72 | | |
| |||
228 | 229 | | |
229 | 230 | | |
230 | 231 | | |
| 232 | + | |
231 | 233 | | |
232 | 234 | | |
233 | 235 | | |
| |||
914 | 916 | | |
915 | 917 | | |
916 | 918 | | |
| 919 | + | |
917 | 920 | | |
918 | 921 | | |
919 | 922 | | |
| |||
987 | 990 | | |
988 | 991 | | |
989 | 992 | | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
990 | 1002 | | |
991 | 1003 | | |
992 | 1004 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| 36 | + | |
36 | 37 | | |
37 | 38 | | |
38 | 39 | | |
| |||
1020 | 1021 | | |
1021 | 1022 | | |
1022 | 1023 | | |
1023 | | - | |
| 1024 | + | |
| 1025 | + | |
1024 | 1026 | | |
1025 | 1027 | | |
1026 | 1028 | | |
| |||
1033 | 1035 | | |
1034 | 1036 | | |
1035 | 1037 | | |
1036 | | - | |
1037 | | - | |
1038 | | - | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
1039 | 1046 | | |
1040 | 1047 | | |
1041 | 1048 | | |
| |||
1066 | 1073 | | |
1067 | 1074 | | |
1068 | 1075 | | |
1069 | | - | |
| 1076 | + | |
1070 | 1077 | | |
1071 | 1078 | | |
1072 | 1079 | | |
| |||
1077 | 1084 | | |
1078 | 1085 | | |
1079 | 1086 | | |
| 1087 | + | |
1080 | 1088 | | |
1081 | 1089 | | |
1082 | 1090 | | |
| |||
1086 | 1094 | | |
1087 | 1095 | | |
1088 | 1096 | | |
1089 | | - | |
| 1097 | + | |
1090 | 1098 | | |
1091 | 1099 | | |
1092 | 1100 | | |
1093 | 1101 | | |
1094 | 1102 | | |
1095 | | - | |
1096 | | - | |
| 1103 | + | |
| 1104 | + | |
1097 | 1105 | | |
1098 | 1106 | | |
1099 | | - | |
1100 | | - | |
1101 | | - | |
1102 | | - | |
1103 | | - | |
1104 | | - | |
1105 | | - | |
1106 | | - | |
1107 | | - | |
1108 | | - | |
1109 | | - | |
1110 | 1107 | | |
1111 | 1108 | | |
1112 | 1109 | | |
1113 | | - | |
| 1110 | + | |
1114 | 1111 | | |
1115 | 1112 | | |
1116 | 1113 | | |
| |||
1120 | 1117 | | |
1121 | 1118 | | |
1122 | 1119 | | |
1123 | | - | |
| 1120 | + | |
| 1121 | + | |
| 1122 | + | |
| 1123 | + | |
| 1124 | + | |
| 1125 | + | |
| 1126 | + | |
1124 | 1127 | | |
1125 | 1128 | | |
1126 | 1129 | | |
| |||
0 commit comments