Merge pull request #11306 from jetty/fix/jetty-12/11282/debug-deadlock

Fixes #11282 - Deadlocks with DEBUG logging enabled in jetty-server testing.
This commit is contained in:
Joakim Erdfelt 2024-01-25 09:26:49 -06:00 committed by GitHub
commit ef75595e8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 47 additions and 16 deletions

View File

@ -492,13 +492,14 @@ public class ByteArrayEndPoint extends AbstractEndPoint
public String toString() public String toString()
{ {
int q; int q;
ByteBuffer b; Object b;
String o; String o;
try (AutoLock lock = _lock.lock()) try (AutoLock lock = _lock.tryLock())
{ {
q = _inQ.size(); boolean held = lock.isHeldByCurrentThread();
b = _inQ.peek(); q = held ? _inQ.size() : -1;
o = BufferUtil.toDetailString(_out); b = held ? _inQ.peek() : "?";
o = held ? BufferUtil.toDetailString(_out) : "?";
} }
return String.format("%s[q=%d,q[0]=%s,o=%s]", super.toString(), q, b, o); return String.format("%s[q=%d,q[0]=%s,o=%s]", super.toString(), q, b, o);
} }

View File

@ -546,16 +546,18 @@ public class HttpChannelState implements HttpChannel, Components
@Override @Override
public String toString() public String toString()
{ {
try (AutoLock ignored = _lock.lock()) try (AutoLock lock = _lock.tryLock())
{ {
return String.format("%s@%x{handling=%s, handled=%b, send=%s, completed=%b, request=%s}", boolean held = lock.isHeldByCurrentThread();
return String.format("%s@%x{handling=%s, handled=%s, send=%s, completed=%s, request=%s}",
this.getClass().getSimpleName(), this.getClass().getSimpleName(),
hashCode(), hashCode(),
_handling, held ? _handling : "?",
_handled, held ? _handled : "?",
_streamSendState, held ? _streamSendState : "?",
_callbackCompleted, held ? _callbackCompleted : "?",
_request); held ? _request : "?"
);
} }
} }
@ -1270,6 +1272,7 @@ public class HttpChannelState implements HttpChannel, Components
* <p> * <p>
* The implementation maintains the {@link #_streamSendState} before taking * The implementation maintains the {@link #_streamSendState} before taking
* and serializing the call to the {@link #_writeCallback}, which was set by the call to {@code write}. * and serializing the call to the {@link #_writeCallback}, which was set by the call to {@code write}.
*
* @param x The reason for the failure. * @param x The reason for the failure.
*/ */
@Override @Override
@ -1498,6 +1501,7 @@ public class HttpChannelState implements HttpChannel, Components
/** /**
* Called when the {@link Handler} (or it's delegates) fail the request handling. * Called when the {@link Handler} (or it's delegates) fail the request handling.
*
* @param failure The reason for the failure. * @param failure The reason for the failure.
*/ */
@Override @Override
@ -1679,6 +1683,7 @@ public class HttpChannelState implements HttpChannel, Components
/** /**
* Called when the error write in {@link HttpChannelState.ChannelCallback#failed(Throwable)} fails. * Called when the error write in {@link HttpChannelState.ChannelCallback#failed(Throwable)} fails.
*
* @param x The reason for the failure. * @param x The reason for the failure.
*/ */
@Override @Override

View File

@ -13,6 +13,7 @@
package org.eclipse.jetty.util.thread; package org.eclipse.jetty.util.thread;
import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Condition;
@ -30,6 +31,7 @@ import java.util.concurrent.locks.ReentrantLock;
*/ */
public class AutoLock implements AutoCloseable, Serializable public class AutoLock implements AutoCloseable, Serializable
{ {
@Serial
private static final long serialVersionUID = 3300696774541816341L; private static final long serialVersionUID = 3300696774541816341L;
private final ReentrantLock _lock = new ReentrantLock(); private final ReentrantLock _lock = new ReentrantLock();
@ -46,8 +48,24 @@ public class AutoLock implements AutoCloseable, Serializable
} }
/** /**
* @see ReentrantLock#isHeldByCurrentThread() * <p>Tries to acquire the lock.</p>
* <p>Whether the lock was acquired can be tested
* with {@link #isHeldByCurrentThread()}.</p>
* <p>Typical usage of this method is in {@code toString()},
* to avoid deadlocks when the implementation needs to lock
* to retrieve a consistent state to produce the string.</p>
*
* @return this AutoLock for unlocking
*/
public AutoLock tryLock()
{
_lock.tryLock();
return this;
}
/**
* @return whether this lock is held by the current thread * @return whether this lock is held by the current thread
* @see ReentrantLock#isHeldByCurrentThread()
*/ */
public boolean isHeldByCurrentThread() public boolean isHeldByCurrentThread()
{ {
@ -71,7 +89,8 @@ public class AutoLock implements AutoCloseable, Serializable
@Override @Override
public void close() public void close()
{ {
_lock.unlock(); if (isHeldByCurrentThread())
_lock.unlock();
} }
/** /**
@ -101,6 +120,12 @@ public class AutoLock implements AutoCloseable, Serializable
return (WithCondition)super.lock(); return (WithCondition)super.lock();
} }
@Override
public AutoLock.WithCondition tryLock()
{
return (WithCondition)super.tryLock();
}
/** /**
* @see Condition#signal() * @see Condition#signal()
*/ */
@ -118,8 +143,8 @@ public class AutoLock implements AutoCloseable, Serializable
} }
/** /**
* @see Condition#await()
* @throws InterruptedException if the current thread is interrupted * @throws InterruptedException if the current thread is interrupted
* @see Condition#await()
*/ */
public void await() throws InterruptedException public void await() throws InterruptedException
{ {
@ -127,11 +152,11 @@ public class AutoLock implements AutoCloseable, Serializable
} }
/** /**
* @see Condition#await(long, TimeUnit)
* @param time the time to wait * @param time the time to wait
* @param unit the time unit * @param unit the time unit
* @return false if the waiting time elapsed * @return false if the waiting time elapsed
* @throws InterruptedException if the current thread is interrupted * @throws InterruptedException if the current thread is interrupted
* @see Condition#await(long, TimeUnit)
*/ */
public boolean await(long time, TimeUnit unit) throws InterruptedException public boolean await(long time, TimeUnit unit) throws InterruptedException
{ {