Merge pull request #3938 from eclipse/jetty-9.4.x-3929-http2_deadlock_stopping_server
Fixes #3929 - Deadlock between new HTTP2Connection() and Server.stop().
This commit is contained in:
commit
fa0e7850be
|
@ -106,18 +106,20 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
|
|||
switch (b._managed)
|
||||
{
|
||||
case MANAGED:
|
||||
if (!l.isRunning())
|
||||
if (l.isStopped() || l.isFailed())
|
||||
start(l);
|
||||
break;
|
||||
|
||||
case AUTO:
|
||||
if (l.isRunning())
|
||||
unmanage(b);
|
||||
else
|
||||
if (l.isStopped())
|
||||
{
|
||||
manage(b);
|
||||
start(l);
|
||||
}
|
||||
else
|
||||
{
|
||||
unmanage(b);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -142,7 +144,7 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
|
|||
{
|
||||
try
|
||||
{
|
||||
l.stop();
|
||||
stop(l);
|
||||
}
|
||||
catch (Throwable cause2)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.io.IOException;
|
|||
import java.io.StringReader;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
|
@ -129,10 +130,7 @@ public class ContainerLifeCycleTest
|
|||
container.stop();
|
||||
container.destroy();
|
||||
|
||||
assertThrows(IllegalStateException.class, () ->
|
||||
{
|
||||
container.start();
|
||||
});
|
||||
assertThrows(IllegalStateException.class, container::start);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -210,13 +208,13 @@ public class ContainerLifeCycleTest
|
|||
{
|
||||
ContainerLifeCycle a0 = new ContainerLifeCycle();
|
||||
String dump = trim(a0.dump());
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
check(dump, "ContainerLifeCycl");
|
||||
|
||||
ContainerLifeCycle aa0 = new ContainerLifeCycle();
|
||||
a0.addBean(aa0);
|
||||
dump = trim(a0.dump());
|
||||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, "+? ContainerLife");
|
||||
check(dump, "+? ContainerLife");
|
||||
|
||||
ContainerLifeCycle aa1 = new ContainerLifeCycle();
|
||||
a0.addBean(aa1);
|
||||
|
@ -224,7 +222,7 @@ public class ContainerLifeCycleTest
|
|||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, "+? ContainerLife");
|
||||
dump = check(dump, "+? ContainerLife");
|
||||
dump = check(dump, "");
|
||||
check(dump, "");
|
||||
|
||||
ContainerLifeCycle aa2 = new ContainerLifeCycle();
|
||||
a0.addBean(aa2, false);
|
||||
|
@ -233,7 +231,7 @@ public class ContainerLifeCycleTest
|
|||
dump = check(dump, "+? ContainerLife");
|
||||
dump = check(dump, "+? ContainerLife");
|
||||
dump = check(dump, "+~ ContainerLife");
|
||||
dump = check(dump, "");
|
||||
check(dump, "");
|
||||
|
||||
aa1.start();
|
||||
a0.start();
|
||||
|
@ -242,7 +240,7 @@ public class ContainerLifeCycleTest
|
|||
dump = check(dump, "+= ContainerLife");
|
||||
dump = check(dump, "+~ ContainerLife");
|
||||
dump = check(dump, "+~ ContainerLife");
|
||||
dump = check(dump, "");
|
||||
check(dump, "");
|
||||
|
||||
a0.manage(aa1);
|
||||
a0.removeBean(aa2);
|
||||
|
@ -250,7 +248,7 @@ public class ContainerLifeCycleTest
|
|||
dump = check(dump, "ContainerLifeCycl");
|
||||
dump = check(dump, "+= ContainerLife");
|
||||
dump = check(dump, "+= ContainerLife");
|
||||
dump = check(dump, "");
|
||||
check(dump, "");
|
||||
|
||||
ContainerLifeCycle aaa0 = new ContainerLifeCycle();
|
||||
aa0.addBean(aaa0);
|
||||
|
@ -259,7 +257,7 @@ public class ContainerLifeCycleTest
|
|||
dump = check(dump, "+= ContainerLife");
|
||||
dump = check(dump, "| +~ Container");
|
||||
dump = check(dump, "+= ContainerLife");
|
||||
dump = check(dump, "");
|
||||
check(dump, "");
|
||||
|
||||
ContainerLifeCycle aa10 = new ContainerLifeCycle();
|
||||
aa1.addBean(aa10, true);
|
||||
|
@ -269,7 +267,7 @@ public class ContainerLifeCycleTest
|
|||
dump = check(dump, "| +~ Container");
|
||||
dump = check(dump, "+= ContainerLife");
|
||||
dump = check(dump, " += Container");
|
||||
dump = check(dump, "");
|
||||
check(dump, "");
|
||||
|
||||
final ContainerLifeCycle a1 = new ContainerLifeCycle();
|
||||
final ContainerLifeCycle a2 = new ContainerLifeCycle();
|
||||
|
@ -301,7 +299,7 @@ public class ContainerLifeCycleTest
|
|||
dump = check(dump, " +> java.util.Arrays$ArrayList");
|
||||
dump = check(dump, " +: ContainerLifeCycle");
|
||||
dump = check(dump, " +: ContainerLifeCycle");
|
||||
dump = check(dump, "");
|
||||
check(dump, "");
|
||||
|
||||
a2.addBean(aa0, true);
|
||||
dump = trim(a0.dump());
|
||||
|
@ -319,7 +317,7 @@ public class ContainerLifeCycleTest
|
|||
dump = check(dump, " +> java.util.Arrays$ArrayList");
|
||||
dump = check(dump, " +: ContainerLifeCycle");
|
||||
dump = check(dump, " +: ContainerLifeCycle");
|
||||
dump = check(dump, "");
|
||||
check(dump, "");
|
||||
|
||||
a2.unmanage(aa0);
|
||||
dump = trim(a0.dump());
|
||||
|
@ -336,7 +334,7 @@ public class ContainerLifeCycleTest
|
|||
dump = check(dump, " +> java.util.Arrays$ArrayList");
|
||||
dump = check(dump, " +: ContainerLifeCycle");
|
||||
dump = check(dump, " +: ContainerLifeCycle");
|
||||
dump = check(dump, "");
|
||||
check(dump, "");
|
||||
|
||||
a0.unmanage(aa);
|
||||
dump = trim(a0.dump());
|
||||
|
@ -346,7 +344,7 @@ public class ContainerLifeCycleTest
|
|||
dump = check(dump, "+= ContainerLife");
|
||||
dump = check(dump, "| += Container");
|
||||
dump = check(dump, "+~ ContainerLife");
|
||||
dump = check(dump, "");
|
||||
check(dump, "");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -504,7 +502,7 @@ public class ContainerLifeCycleTest
|
|||
assertEquals(c00, child.poll());
|
||||
}
|
||||
|
||||
private final class InheritedListenerLifeCycle extends AbstractLifeCycle implements Container.InheritedListener
|
||||
private static final class InheritedListenerLifeCycle extends AbstractLifeCycle implements Container.InheritedListener
|
||||
{
|
||||
@Override
|
||||
public void beanRemoved(Container p, Object c)
|
||||
|
@ -627,7 +625,7 @@ public class ContainerLifeCycleTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGetBeans() throws Exception
|
||||
public void testGetBeans()
|
||||
{
|
||||
TestContainerLifeCycle root = new TestContainerLifeCycle();
|
||||
TestContainerLifeCycle left = new TestContainerLifeCycle();
|
||||
|
@ -637,19 +635,114 @@ public class ContainerLifeCycleTest
|
|||
TestContainerLifeCycle leaf = new TestContainerLifeCycle();
|
||||
right.addBean(leaf);
|
||||
|
||||
root.addBean(Integer.valueOf(0));
|
||||
root.addBean(Integer.valueOf(1));
|
||||
left.addBean(Integer.valueOf(2));
|
||||
right.addBean(Integer.valueOf(3));
|
||||
leaf.addBean(Integer.valueOf(4));
|
||||
Integer zero = 0;
|
||||
Integer one = 1;
|
||||
Integer two = 2;
|
||||
Integer three = 3;
|
||||
Integer four = 4;
|
||||
root.addBean(zero);
|
||||
root.addBean(one);
|
||||
left.addBean(two);
|
||||
right.addBean(three);
|
||||
leaf.addBean(four);
|
||||
leaf.addBean("leaf");
|
||||
|
||||
assertThat(root.getBeans(Container.class), containsInAnyOrder(left, right));
|
||||
assertThat(root.getBeans(Integer.class), containsInAnyOrder(Integer.valueOf(0), Integer.valueOf(1)));
|
||||
assertThat(root.getBeans(Integer.class), containsInAnyOrder(zero, one));
|
||||
assertThat(root.getBeans(String.class), containsInAnyOrder());
|
||||
|
||||
assertThat(root.getContainedBeans(Container.class), containsInAnyOrder(left, right, leaf));
|
||||
assertThat(root.getContainedBeans(Integer.class), containsInAnyOrder(Integer.valueOf(0), Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4)));
|
||||
assertThat(root.getContainedBeans(Integer.class), containsInAnyOrder(zero, one, two, three, four));
|
||||
assertThat(root.getContainedBeans(String.class), containsInAnyOrder("leaf"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeanStoppingAddedToStartingBean() throws Exception
|
||||
{
|
||||
ContainerLifeCycle longLived = new ContainerLifeCycle()
|
||||
{
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
super.doStop();
|
||||
|
||||
ContainerLifeCycle shortLived = new ContainerLifeCycle();
|
||||
shortLived.addBean(this);
|
||||
shortLived.start();
|
||||
|
||||
assertTrue(shortLived.isStarted());
|
||||
assertTrue(isStopping());
|
||||
assertFalse(shortLived.isManaged(this));
|
||||
}
|
||||
};
|
||||
longLived.start();
|
||||
longLived.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailedManagedBeanCanBeRestarted() throws Exception
|
||||
{
|
||||
AtomicBoolean fail = new AtomicBoolean();
|
||||
ContainerLifeCycle container = new ContainerLifeCycle();
|
||||
ContainerLifeCycle bean1 = new ContainerLifeCycle();
|
||||
ContainerLifeCycle bean2 = new ContainerLifeCycle()
|
||||
{
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
// Fail only the first time.
|
||||
if (fail.compareAndSet(false, true))
|
||||
throw new RuntimeException();
|
||||
}
|
||||
};
|
||||
ContainerLifeCycle bean3 = new ContainerLifeCycle();
|
||||
container.addBean(bean1);
|
||||
container.addBean(bean2);
|
||||
container.addBean(bean3);
|
||||
|
||||
// Start the first time, it should fail.
|
||||
assertThrows(RuntimeException.class, container::start);
|
||||
assertTrue(container.isFailed());
|
||||
assertTrue(bean1.isStopped());
|
||||
assertTrue(bean2.isFailed());
|
||||
assertTrue(bean3.isStopped());
|
||||
|
||||
// Re-start, it should succeed.
|
||||
container.start();
|
||||
assertTrue(container.isStarted());
|
||||
assertTrue(bean1.isStarted());
|
||||
assertTrue(bean2.isStarted());
|
||||
assertTrue(bean3.isStarted());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailedAutoBeanIsNotRestarted() throws Exception
|
||||
{
|
||||
AtomicBoolean fail = new AtomicBoolean();
|
||||
ContainerLifeCycle bean = new ContainerLifeCycle()
|
||||
{
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
// Fail only the first time.
|
||||
if (fail.compareAndSet(false, true))
|
||||
throw new RuntimeException();
|
||||
}
|
||||
};
|
||||
// The bean is started externally and fails.
|
||||
assertThrows(RuntimeException.class, bean::start);
|
||||
|
||||
// The same bean now becomes part of a container.
|
||||
ContainerLifeCycle container = new ContainerLifeCycle();
|
||||
container.addBean(bean);
|
||||
assertTrue(container.isAuto(bean));
|
||||
|
||||
// Start the container, the bean must not be managed.
|
||||
container.start();
|
||||
assertTrue(container.isStarted());
|
||||
assertTrue(bean.isFailed());
|
||||
assertTrue(container.isUnmanaged(bean));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue