Skip to content

Commit c1865c7

Browse files
committed
FEATURE-ci-v3-runtime-green: remove PSK fixture scheduling races
1 parent c1b4beb commit c1865c7

4 files changed

Lines changed: 37 additions & 11 deletions

File tree

‎ChangeLog‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
Version 3.0.0 - 2026-10-10
2+
Keep PSK cancellation lookup held until owner release and avoid artificial
3+
per-fragment scheduling delays in the TLS test transport.
24
Avoid Windows DLL shutdown hangs by retaining the default timer service
35
during process termination while preserving ordinary timer cleanup.
46
Report the saved Winsock error code when host WSAPoll fails.

‎specs/tasks/FEATURE-ci-v3-runtime-green.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,24 @@ Integrate the focused repairs and ChangeLog update now. Full CI remains incomple
7070
Groundwork validation has not run and stays deferred until full CI is green.
7171
This integration does not mark the overall CI repair complete or reopen closed
7272
diagnostic batches. Draft PR #382 carries the original working-branch runs.
73+
74+
## Stage 4: PSK test fixture scheduling (2026-10-27)
75+
76+
- [x] Read the completed, previously authorized diagnostic receipts; keep their budgets closed.
77+
- [x] Preserve the native Darwin RED: 14 tests/313 checks, three failures; held TLS1.3 cancellation callback already returned, and certificate-default TLS1.3 handshake timed out.
78+
- [x] Release the held cancellation lookup explicitly after assertions and close; bound the callback wait to five seconds for failure cleanup.
79+
- [x] Drain ready fragmented transport work and yield while waiting for provider work, preserving the original fragments and every deadline/assertion.
80+
- [x] Reproduce the real certificate fixture timeout under coarse scheduling, then pass the same regression and all 14 PSK tests/313 checks.
81+
- [x] Pass changed-file cpplint and diff checks.
82+
- [ ] Native current-source CI, including Darwin selected archive acceptance.
83+
- [ ] Resolve the remaining Windows external-loop failure from supported evidence.
84+
- [ ] Close the FreeBSD selected-archive timeout gate with actual evidence.
85+
86+
Evidence and commands: primary checkout `.debug/v3-ci-native-repairs-PJFEkn/journal.md`.
87+
Current c1 installed matrix passed Linux, Darwin, FreeBSD; Windows failed. Native/fuzz, CodeQL and Verify Build passed. Source-equivalent selected archive remains failed; no current-source green claim.
88+
89+
The diagnostic Windows four-test program failed one of 52 checks in 0.741 seconds with WSAPoll error10038 before stop was requested. Two bounded new socket-only probes on local Windows11 returned POLLNVAL successfully; they do not establish the Server2022 failure cause. No poll error suppression or guessed production fix was applied. Previous capture budgets remain closed.
90+
91+
Fixture root cause: the cancellation rescue unconditionally released after250ms, before the owner could assert cancellation under slower scheduling. The transport also slept after every41/73-byte fragment, charging scheduler delays to real handshake deadlines. A minimal real TLS1.3 certificate fixture with1ms sleeps delayed to15ms failed at2089ms/outcome8(timeout); draining progress first passed at625ms. An intermediate full coarse-scheduling check still failed two held/capacity assertions because idle sleeps could expire the400ms pre-lookup deadline. Yielding while idle preserved that deadline and passed all313 checks in1.029seconds, with zero skips. The100ms owner-responsiveness assertion, cancellation/timeout/capacity/late-result assertions, bounded drains and all protocol settings remain unchanged. Only test source changed; production TLS is unchanged.
92+
93+
Setup evidence is retained honestly: system OpenSSL was rejected before selecting the existing3.5.9 provider; the first suite launch used build-root cwd instead of test cwd and failed fixture path lookup. Correcting cwd, as required by the generated relative TLS_TEST_DIR, produced the meaningful behavioral check. Neither setup failure justifies a source workaround. No broad baseline or Groundwork validation was run.

‎test/unit/tls_psk_fixture.hpp‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,17 +135,20 @@ struct connection : mtls_test::adapter_connection {
135135
if (host) SSL_set_tlsext_host_name(peer.get(), host);
136136
handshake = hd::tls_handshake_operation(owner, 1, std::chrono::steady_clock::now() + timeout);
137137
}
138-
void tick() {
139-
ex.run_pending();
140-
for (const auto& op : raw.pending_ops()) transfer(op);
138+
bool tick() {
139+
bool progressed = ex.run_pending() != 0;
140+
for (const auto& op : raw.pending_ops()) progressed = transfer(op) || progressed;
141141
advance_peer();
142+
return progressed || ex.pending() != 0;
142143
}
143144
template<class Predicate> bool until(Predicate predicate, std::chrono::milliseconds timeout = std::chrono::seconds(3)) {
144145
const auto deadline = std::chrono::steady_clock::now() + timeout;
145146
while (std::chrono::steady_clock::now() < deadline) {
146-
tick();
147+
const bool progressed = tick();
147148
if (predicate()) return true;
148-
std::this_thread::sleep_for(std::chrono::milliseconds(1));
149+
// Fragmentation is deliberate; adding a scheduling delay to every
150+
// ready fragment can consume the real handshake deadline.
151+
if (!progressed) std::this_thread::yield();
149152
}
150153
return false;
151154
}

‎test/unit/tls_psk_test.cpp‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,23 +119,23 @@ LT_BEGIN_AUTO_TEST(psk_suite, blocking_lookup_leaves_owner_responsive_and_cancel
119119
auto released = release.get_future().share();
120120
auto config = psk_test::credentials(runtime, [&](auto, const auto&) {
121121
entered = true;
122-
released.wait();
122+
// The owner releases lookup only after checking cancellation.
123+
// A broken blocking implementation must still unwind the fixture.
124+
released.wait_for(5s);
123125
returned = true;
124126
return hd::psk_lookup_result{hd::psk_lookup_status::accepted, hd::secure_bytes(psk_test::bytes("secret"))};
125127
});
126128
hd::tls_credentials_registry registry;
127129
LT_ASSERT(registry.replace(config).ok());
128130
psk_test::connection peer(registry.acquire()->select_default(), version, "identity", psk_test::bytes("secret"));
129-
// Bounded rescue ensures RED cannot leave a fixture hanging in lookup.
130-
auto rescue = std::async(std::launch::async, [&] { std::this_thread::sleep_for(250ms); release.set_value(); });
131131
peer.handshake.submit(*peer.tls);
132132
std::chrono::steady_clock::duration longest{};
133133
const auto until = std::chrono::steady_clock::now() + 1s;
134134
while (!entered && std::chrono::steady_clock::now() < until) {
135135
const auto before = std::chrono::steady_clock::now();
136-
peer.tick();
136+
const bool progressed = peer.tick();
137137
longest = std::max(longest, std::chrono::steady_clock::now() - before);
138-
std::this_thread::sleep_for(1ms);
138+
if (!progressed) std::this_thread::yield();
139139
}
140140
const auto cancelled = peer.tls->request_cancel(*peer.handshake.state());
141141
peer.ex.run_pending();
@@ -147,7 +147,7 @@ LT_BEGIN_AUTO_TEST(psk_suite, blocking_lookup_leaves_owner_responsive_and_cancel
147147
LT_CHECK(peer.handshake.state()->stored_result().code == hh::outcome_code::cancelled);
148148
LT_CHECK(!peer.tls->peer_metadata());
149149
peer.close();
150-
rescue.get();
150+
release.set_value();
151151
runtime->stop();
152152
LT_CHECK(runtime->drain(std::chrono::steady_clock::now() + 1s));
153153
peer.ex.run_pending();

0 commit comments

Comments
 (0)