mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-18 19:43:24 +03:00
Requests that hit a connection limit used to wait inside their worker, polling every 10 ms, and an async request's timeout included that wait. On a page with many resources from one origin, later requests timed out while queued, and waiting requests tied up shared thread-pool workers that other origins needed. Connection queue: - Serve blocking and async requests from one first-come, first-served queue per pool. Requests waiting on one origin's limit never block requests to other origins. - In shared thread-pool mode, an async request runs on a worker only after it has been granted a connection. Grants are handed to the executor from a service thread, never from the thread releasing a connection, which could be inside the executor's own lock. - Requests hold their executor only weakly, so a request can never be the last owner of the thread pool running it. - Start an async request's timeout once it holds a connection. A blocking call's timeout still covers the wait plus the transfer, and a resumed download keeps its deadline across the HEAD probe. - Wait on a condition variable instead of polling. Cancelling by ID, shutdown() and Pool::close() release queued requests immediately. - Let running requests and blocking callers take over a slot reserved for queued work that has not started; that work queues again, first in line. Without this, a redirect, retry or resumed download on a busy executor could wait forever on slots reserved behind it. - When queued work starts, switch to a connection that went idle while it waited, instead of opening a new one. - Replace an idle connection the server has closed in place, keeping its slot. Process-wide limit and idle expiry: - Limit open sockets across all pools with Http::setMaxOpenConnections() (default 256). At the limit, close the least recently used idle socket in any pool, then a socket held for queued work, and only wait while every socket is in active use. - Wake waiters on the limit when a socket goes idle, and recheck a change counter so a wake-up just before waiting is never missed. - Only inspect a socket for reclaim once its connection is known to be idle or reserved, never while a request is using it. - Close idle connections from a background timer when idleTimeout elapses, instead of only when a connection is next requested in the same pool. - The budget and its service thread are intentionally never destroyed, so the thread is never joined during static destruction, which would deadlock under the Windows loader lock. Shutdown: - Add Http::cancelAllRequests(), which cancels every queued and running request in every pool and closes idle connections. A per-pool generation counter makes running requests stop at their next check, and the pools stay usable afterwards. - Add Http::waitForConnectionsToClose(). - Engine cancels all requests as it starts shutting down. Once its windows are closed, it waits up to 100 ms for sockets to close before ending TLS. - Check for cancellation every 25 ms instead of 100 ms while reading, so requests stop within that wait. TLS: - SSLSocket::end() now waits while TLS sockets exist: the last socket destroyed releases the backend, and a socket created in the meantime keeps it. - Set up the backend and register a new socket a lock, so a concurrent end() cannot release the backend in between. - Add SSLSocket::isInitialized() and a testing h socket construction.