2015-09-22 15:17:08 +02:00
|
|
|
/*
|
2016-02-10 07:54:43 -08:00
|
|
|
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
|
2015-09-22 15:17:08 +02:00
|
|
|
*
|
2016-02-10 07:54:43 -08:00
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
2015-09-22 15:17:08 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package org.webrtc;
|
|
|
|
|
|
2015-10-12 09:15:45 +02:00
|
|
|
import android.os.Handler;
|
2015-10-30 15:31:07 -07:00
|
|
|
import android.os.SystemClock;
|
2015-10-12 09:15:45 +02:00
|
|
|
|
|
|
|
|
import java.util.concurrent.Callable;
|
2015-09-28 11:05:44 +02:00
|
|
|
import java.util.concurrent.CountDownLatch;
|
2015-10-30 15:31:07 -07:00
|
|
|
import java.util.concurrent.TimeUnit;
|
2015-09-28 11:05:44 +02:00
|
|
|
|
2015-11-23 20:13:24 +01:00
|
|
|
public class ThreadUtils {
|
2015-10-05 20:49:04 +02:00
|
|
|
/**
|
|
|
|
|
* Utility class to be used for checking that a method is called on the correct thread.
|
|
|
|
|
*/
|
|
|
|
|
public static class ThreadChecker {
|
|
|
|
|
private Thread thread = Thread.currentThread();
|
|
|
|
|
|
|
|
|
|
public void checkIsOnValidThread() {
|
|
|
|
|
if (thread == null) {
|
|
|
|
|
thread = Thread.currentThread();
|
|
|
|
|
}
|
|
|
|
|
if (Thread.currentThread() != thread) {
|
|
|
|
|
throw new IllegalStateException("Wrong thread");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void detachThread() {
|
|
|
|
|
thread = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-22 15:17:08 +02:00
|
|
|
/**
|
2015-09-28 11:05:44 +02:00
|
|
|
* Utility interface to be used with executeUninterruptibly() to wait for blocking operations
|
|
|
|
|
* to complete without getting interrupted..
|
2015-09-22 15:17:08 +02:00
|
|
|
*/
|
2015-09-28 11:05:44 +02:00
|
|
|
public interface BlockingOperation {
|
|
|
|
|
void run() throws InterruptedException;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Utility method to make sure a blocking operation is executed to completion without getting
|
|
|
|
|
* interrupted. This should be used in cases where the operation is waiting for some critical
|
|
|
|
|
* work, e.g. cleanup, that must complete before returning. If the thread is interrupted during
|
|
|
|
|
* the blocking operation, this function will re-run the operation until completion, and only then
|
|
|
|
|
* re-interrupt the thread.
|
|
|
|
|
*/
|
|
|
|
|
public static void executeUninterruptibly(BlockingOperation operation) {
|
2015-09-22 15:17:08 +02:00
|
|
|
boolean wasInterrupted = false;
|
|
|
|
|
while (true) {
|
|
|
|
|
try {
|
2015-09-28 11:05:44 +02:00
|
|
|
operation.run();
|
2015-09-22 15:17:08 +02:00
|
|
|
break;
|
|
|
|
|
} catch (InterruptedException e) {
|
2015-09-28 11:05:44 +02:00
|
|
|
// Someone is asking us to return early at our convenience. We can't cancel this operation,
|
2015-09-22 15:17:08 +02:00
|
|
|
// but we should preserve the information and pass it along.
|
|
|
|
|
wasInterrupted = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Pass interruption information along.
|
|
|
|
|
if (wasInterrupted) {
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-28 11:05:44 +02:00
|
|
|
|
2015-11-16 05:12:30 -08:00
|
|
|
public static boolean joinUninterruptibly(final Thread thread, long timeoutMs) {
|
|
|
|
|
final long startTimeMs = SystemClock.elapsedRealtime();
|
|
|
|
|
long timeRemainingMs = timeoutMs;
|
|
|
|
|
boolean wasInterrupted = false;
|
|
|
|
|
while (timeRemainingMs > 0) {
|
|
|
|
|
try {
|
|
|
|
|
thread.join(timeRemainingMs);
|
|
|
|
|
break;
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
// Someone is asking us to return early at our convenience. We can't cancel this operation,
|
|
|
|
|
// but we should preserve the information and pass it along.
|
|
|
|
|
wasInterrupted = true;
|
|
|
|
|
final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs;
|
|
|
|
|
timeRemainingMs = timeoutMs - elapsedTimeMs;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Pass interruption information along.
|
|
|
|
|
if (wasInterrupted) {
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
}
|
|
|
|
|
return !thread.isAlive();
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-28 11:05:44 +02:00
|
|
|
public static void joinUninterruptibly(final Thread thread) {
|
|
|
|
|
executeUninterruptibly(new BlockingOperation() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() throws InterruptedException {
|
|
|
|
|
thread.join();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void awaitUninterruptibly(final CountDownLatch latch) {
|
|
|
|
|
executeUninterruptibly(new BlockingOperation() {
|
|
|
|
|
@Override
|
|
|
|
|
public void run() throws InterruptedException {
|
|
|
|
|
latch.await();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2015-10-12 09:15:45 +02:00
|
|
|
|
2015-10-30 15:31:07 -07:00
|
|
|
public static boolean awaitUninterruptibly(CountDownLatch barrier, long timeoutMs) {
|
|
|
|
|
final long startTimeMs = SystemClock.elapsedRealtime();
|
|
|
|
|
long timeRemainingMs = timeoutMs;
|
|
|
|
|
boolean wasInterrupted = false;
|
|
|
|
|
boolean result = false;
|
|
|
|
|
do {
|
|
|
|
|
try {
|
|
|
|
|
result = barrier.await(timeRemainingMs, TimeUnit.MILLISECONDS);
|
|
|
|
|
break;
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
// Someone is asking us to return early at our convenience. We can't cancel this operation,
|
|
|
|
|
// but we should preserve the information and pass it along.
|
|
|
|
|
wasInterrupted = true;
|
|
|
|
|
final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs;
|
|
|
|
|
timeRemainingMs = timeoutMs - elapsedTimeMs;
|
|
|
|
|
}
|
|
|
|
|
} while (timeRemainingMs > 0);
|
|
|
|
|
// Pass interruption information along.
|
|
|
|
|
if (wasInterrupted) {
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-12 09:15:45 +02:00
|
|
|
/**
|
|
|
|
|
* Post |callable| to |handler| and wait for the result.
|
|
|
|
|
*/
|
|
|
|
|
public static <V> V invokeUninterruptibly(final Handler handler, final Callable<V> callable) {
|
|
|
|
|
class Result {
|
|
|
|
|
public V value;
|
|
|
|
|
}
|
|
|
|
|
final Result result = new Result();
|
|
|
|
|
final CountDownLatch barrier = new CountDownLatch(1);
|
|
|
|
|
handler.post(new Runnable() {
|
|
|
|
|
@Override public void run() {
|
|
|
|
|
try {
|
|
|
|
|
result.value = callable.call();
|
|
|
|
|
} catch (Exception e) {
|
2016-03-15 04:43:10 -07:00
|
|
|
final RuntimeException runtimeException =
|
|
|
|
|
new RuntimeException("Callable threw exception: " + e);
|
|
|
|
|
runtimeException.setStackTrace(e.getStackTrace());
|
|
|
|
|
throw runtimeException;
|
2015-10-12 09:15:45 +02:00
|
|
|
}
|
|
|
|
|
barrier.countDown();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
awaitUninterruptibly(barrier);
|
|
|
|
|
return result.value;
|
|
|
|
|
}
|
2015-10-13 08:15:05 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Post |runner| to |handler| and wait for the result.
|
|
|
|
|
*/
|
|
|
|
|
public static void invokeUninterruptibly(final Handler handler, final Runnable runner) {
|
|
|
|
|
final CountDownLatch barrier = new CountDownLatch(1);
|
|
|
|
|
handler.post(new Runnable() {
|
|
|
|
|
@Override public void run() {
|
|
|
|
|
runner.run();
|
|
|
|
|
barrier.countDown();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
awaitUninterruptibly(barrier);
|
|
|
|
|
}
|
2015-09-22 15:17:08 +02:00
|
|
|
}
|