Fixes #2548 - Possible deadlock failing HTTP/2 stream creation.
Now failing the callback outside of the synchronized block. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
01f7aecc4e
commit
16b7359ae5
|
@ -471,6 +471,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void newStream(HeadersFrame frame, Promise<Stream> promise, Stream.Listener listener)
|
public void newStream(HeadersFrame frame, Promise<Stream> promise, Stream.Listener listener)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// Synchronization is necessary to atomically create
|
// Synchronization is necessary to atomically create
|
||||||
// the stream id and enqueue the frame to be sent.
|
// the stream id and enqueue the frame to be sent.
|
||||||
|
@ -486,9 +488,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
priority.getWeight(), priority.isExclusive());
|
priority.getWeight(), priority.isExclusive());
|
||||||
frame = new HeadersFrame(streamId, frame.getMetaData(), priority, frame.isEndStream());
|
frame = new HeadersFrame(streamId, frame.getMetaData(), priority, frame.isEndStream());
|
||||||
}
|
}
|
||||||
final IStream stream = createLocalStream(streamId, promise);
|
IStream stream = createLocalStream(streamId);
|
||||||
if (stream == null)
|
|
||||||
return;
|
|
||||||
stream.setListener(listener);
|
stream.setListener(listener);
|
||||||
|
|
||||||
ControlEntry entry = new ControlEntry(frame, stream, new PromiseCallback<>(promise, stream));
|
ControlEntry entry = new ControlEntry(frame, stream, new PromiseCallback<>(promise, stream));
|
||||||
|
@ -498,6 +498,11 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
if (queued)
|
if (queued)
|
||||||
flusher.iterate();
|
flusher.iterate();
|
||||||
}
|
}
|
||||||
|
catch (Throwable x)
|
||||||
|
{
|
||||||
|
promise.failed(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int priority(PriorityFrame frame, Callback callback)
|
public int priority(PriorityFrame frame, Callback callback)
|
||||||
|
@ -516,6 +521,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void push(IStream stream, Promise<Stream> promise, PushPromiseFrame frame, Stream.Listener listener)
|
public void push(IStream stream, Promise<Stream> promise, PushPromiseFrame frame, Stream.Listener listener)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// Synchronization is necessary to atomically create
|
// Synchronization is necessary to atomically create
|
||||||
// the stream id and enqueue the frame to be sent.
|
// the stream id and enqueue the frame to be sent.
|
||||||
|
@ -525,9 +532,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
int streamId = streamIds.getAndAdd(2);
|
int streamId = streamIds.getAndAdd(2);
|
||||||
frame = new PushPromiseFrame(frame.getStreamId(), streamId, frame.getMetaData());
|
frame = new PushPromiseFrame(frame.getStreamId(), streamId, frame.getMetaData());
|
||||||
|
|
||||||
final IStream pushStream = createLocalStream(streamId, promise);
|
IStream pushStream = createLocalStream(streamId);
|
||||||
if (pushStream == null)
|
|
||||||
return;
|
|
||||||
pushStream.setListener(listener);
|
pushStream.setListener(listener);
|
||||||
|
|
||||||
ControlEntry entry = new ControlEntry(frame, pushStream, new PromiseCallback<>(promise, pushStream));
|
ControlEntry entry = new ControlEntry(frame, pushStream, new PromiseCallback<>(promise, pushStream));
|
||||||
|
@ -537,6 +542,11 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
if (queued)
|
if (queued)
|
||||||
flusher.iterate();
|
flusher.iterate();
|
||||||
}
|
}
|
||||||
|
catch (Throwable x)
|
||||||
|
{
|
||||||
|
promise.failed(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void settings(SettingsFrame frame, Callback callback)
|
public void settings(SettingsFrame frame, Callback callback)
|
||||||
|
@ -676,17 +686,14 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IStream createLocalStream(int streamId, Promise<Stream> promise)
|
protected IStream createLocalStream(int streamId)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int localCount = localStreamCount.get();
|
int localCount = localStreamCount.get();
|
||||||
int maxCount = getMaxLocalStreams();
|
int maxCount = getMaxLocalStreams();
|
||||||
if (maxCount >= 0 && localCount >= maxCount)
|
if (maxCount >= 0 && localCount >= maxCount)
|
||||||
{
|
throw new IllegalStateException("Max local stream count " + maxCount + " exceeded");
|
||||||
promise.failed(new IllegalStateException("Max local stream count " + maxCount + " exceeded"));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (localStreamCount.compareAndSet(localCount, localCount + 1))
|
if (localStreamCount.compareAndSet(localCount, localCount + 1))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -702,8 +709,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
promise.failed(new IllegalStateException("Duplicate stream " + streamId));
|
throw new IllegalStateException("Duplicate stream " + streamId);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue