Fix SSH deadlock during OutOfMemoryError
In close() method of SshFetchConnection and SshPushConnection errorThread.join() can wait forever if JSch will not close the channel's error stream. Join with a timeout, and interrupt the copy thread if its blocked on data that will never arrive. Bug: 312863 Change-Id: I763081267653153eed9cd7763a015059338c2df8 Reported-by: Dmitry Neverov <dmitry.neverov@gmail.com> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
parent
b3247ba524
commit
2e961989e4
|
@ -232,7 +232,7 @@ public void close() throws IOException {
|
|||
class SshFetchConnection extends BasePackFetchConnection {
|
||||
private ChannelExec channel;
|
||||
|
||||
private Thread errorThread;
|
||||
private StreamCopyThread errorThread;
|
||||
|
||||
private int exitStatus;
|
||||
|
||||
|
@ -275,7 +275,7 @@ public void close() {
|
|||
|
||||
if (errorThread != null) {
|
||||
try {
|
||||
errorThread.join();
|
||||
errorThread.halt();
|
||||
} catch (InterruptedException e) {
|
||||
// Stop waiting and return anyway.
|
||||
} finally {
|
||||
|
@ -300,7 +300,7 @@ public void close() {
|
|||
class SshPushConnection extends BasePackPushConnection {
|
||||
private ChannelExec channel;
|
||||
|
||||
private Thread errorThread;
|
||||
private StreamCopyThread errorThread;
|
||||
|
||||
private int exitStatus;
|
||||
|
||||
|
@ -343,7 +343,7 @@ public void close() {
|
|||
|
||||
if (errorThread != null) {
|
||||
try {
|
||||
errorThread.join();
|
||||
errorThread.halt();
|
||||
} catch (InterruptedException e) {
|
||||
// Stop waiting and return anyway.
|
||||
} finally {
|
||||
|
|
|
@ -59,6 +59,8 @@ public class StreamCopyThread extends Thread {
|
|||
|
||||
private final AtomicInteger flushCounter = new AtomicInteger(0);
|
||||
|
||||
private volatile boolean done;
|
||||
|
||||
/**
|
||||
* Create a thread to copy data from an input stream to an output stream.
|
||||
*
|
||||
|
@ -87,6 +89,26 @@ public void flush() {
|
|||
interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that the thread terminate, and wait for it.
|
||||
* <p>
|
||||
* This method signals to the copy thread that it should stop as soon as
|
||||
* there is no more IO occurring.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* the calling thread was interrupted.
|
||||
*/
|
||||
public void halt() throws InterruptedException {
|
||||
for (;;) {
|
||||
join(250 /* milliseconds */);
|
||||
if (isAlive()) {
|
||||
done = true;
|
||||
interrupt();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
|
@ -96,6 +118,9 @@ public void run() {
|
|||
if (needFlush())
|
||||
dst.flush();
|
||||
|
||||
if (done)
|
||||
break;
|
||||
|
||||
final int n;
|
||||
try {
|
||||
n = src.read(buf);
|
||||
|
|
Loading…
Reference in New Issue