maskit opened a new pull request, #13952: URL: https://github.com/apache/trafficserver/pull/13952
## Why On kqueue platforms (macOS, FreeBSD), a plugin that pauses `TS_VCONN_OUTBOUND_START_HOOK` and calls `TSVConnReenable()` later wedges the net thread that owns the connection. The thread spins at full CPU inside `NetHandler::process_ready_list()`, every other connection on that thread stalls, and the paused connection never resumes. `test_tls_hook_combination[outbound-delayed-start]`, whose test plugin reenables two seconds after the hook, hangs on macOS for this reason. The loop: 1. While the hook is pending, `sslClientHandShakeEvent()` returns `SSL_WAIT_FOR_HOOK`. In `SSLNetVConnection::_beReadyToTransferData()` that falls into the final `else`, which calls `writeReschedule()`. 2. On kqueue, `write_reschedule()` re-registers the write filter with `EV_ADD`. The socket is writable, so the next poll reports it again and sets `write.triggered`. 3. From then on, each pass through `_beReadyToTransferData()` reschedules with `write.triggered` and `write.enabled` both set. That puts the VC straight back on the `write_ready_list` that `process_ready_list()` is draining, so the loop never ends. 4. The thread never returns to its event loop, so its scheduled events never run. A `TSVConnReenable()` from another thread can't help either: it fails to take the NetHandler mutex the spinning thread holds, and hands the reenable to that same thread. On epoll, `EventIO::refresh()` does nothing and edge-triggered polling doesn't report the socket again, so `write.triggered` stays cleared and the handshake waits for the reenable. That is why Linux CI does not show the hang. ## Change When `_beReadyToTransferData()` gets `SSL_WAIT_FOR_HOOK` and a hook is actually pending (`is_invoked_state()`), skip the reschedule. `reenable()` resumes the handshake: after the last outbound start hook it re-arms the write side itself. `net_read_io()` already skips rescheduling for `SSL_WAIT_FOR_HOOK`. The `is_invoked_state()` check is needed because `SSL_WAIT_FOR_HOOK` also covers two cases that still rely on the reschedule: - The outbound PROXY protocol header write returns it for a partial write or an unconnected or unwritable socket, before any hook runs. - When a plugin reenables inside the hook, the nested `reenable()` has already moved the state back out of the invoked state and re-queued the VC, but `sslClientHandShakeEvent()` still returns `SSL_WAIT_FOR_HOOK`. `SSL_WAIT_FOR_ASYNC` is left unchanged. ## Validation On macOS with a BoringSSL build: - `test_tls_hook_combination[outbound-delayed-start]` passes; it hung on every run before this change. - All 18 `test_tls_hooks.py` cases, `test_tls_hooks_cert_resume`, `test_tls_hooks_client_verify`, `test_tls_hooks_verify`, and all 8 `proxy_protocol_out` cases (including the https-origin ones that go through the PROXY protocol header path) pass serially. - The TLS, SSL and PROXY protocol urtests pass with 8 workers, apart from `test_tls_partial_blind_tunnel`, which fails the same way without this change and is a separate problem. The existing test reproduces the hang only on kqueue platforms, so Linux CI does not cover it. The changed path does not depend on the TLS library, but an OpenSSL build was not tested. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
