RFR: 8376479: Http3 test server thread deadlock in ThrowingPublishersInRequest [v3]

Volkan Yazici vyazici at openjdk.org
Thu Jan 29 18:16:47 UTC 2026


On Thu, 29 Jan 2026 14:53:18 GMT, Daniel Jeliński <djelinski at openjdk.org> wrote:

>> This fixes a deadlock between the thread that reads from the RequestBodyInputStream and the thread that tries to close it in response to a stream reset. See the linked JBS ticket for details.
>> 
>> Tier1 and tier2 tests continue to pass. I verified that with this change there are no busy threads at the end of the test.
>
> Daniel Jeliński has updated the pull request incrementally with two additional commits since the last revision:
> 
>  - Send stop_sending if the InputStream is closed
>  - Close the stream atomically

test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerStreamImpl.java line 336:

> 334:                     Thread.currentThread().interrupt();
> 335:                     io.initCause(e);
> 336:                     throw io;

Can we simplify this loop as follows?

Suggestion:

            while (true) {
                Object reason = closeReason.get();
                if (reason == Boolean.TRUE) {
                    throw new IOException("Stream is closed");
                } else if (reason instanceof IOException ioe) {
                    throw new IOException(ioe);
                }
                if (current != null && (current.hasRemaining() || current == QuicStreamReader.EOF)) {
                    return current;
                }
                try {
                    if (debug.on())
                        debug.log("Taking buffer from queue");
                    // Blocking call
                    current = requestBodyQueue.take();
                } catch (InterruptedException e) {
                    var io = new InterruptedIOException();
                    Thread.currentThread().interrupt();
                    io.initCause(e);
                    throw io;

test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerStreamImpl.java line 368:

> 366:         @Override
> 367:         public void close() throws IOException {
> 368:             if (closeReason.getAndSet(Boolean.TRUE) == Boolean.TRUE) return;

Shouldn't this be `!compareAndSet(null, TRUE)`? Otherwise we allow changing the state from `FAILED` to `CLOSED`, which, AFAICT, is not intended.

test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3ServerStreamImpl.java line 371:

> 369:             if (debug.on())
> 370:                 debug.log("Closing request body input stream");
> 371:             requestBodyQueue.add(QuicStreamReader.EOF);

Do we need `requestBodyQueue.add(QuicStreamReader.EOF)` here and in `resetStream`, given `read()` will propagate the non-null `closeReason` thrown by `current()` anyway, and `current()` is the only reader of `requestBodyQueue`?

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/29448#discussion_r2742919788
PR Review Comment: https://git.openjdk.org/jdk/pull/29448#discussion_r2742812024
PR Review Comment: https://git.openjdk.org/jdk/pull/29448#discussion_r2742823607


More information about the net-dev mailing list