OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * libjingle |
| 3 * Copyright 2015 Google Inc. |
| 4 * |
| 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions are met: |
| 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright notice, |
| 9 * this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
| 11 * this list of conditions and the following disclaimer in the documentation |
| 12 * and/or other materials provided with the distribution. |
| 13 * 3. The name of the author may not be used to endorse or promote products |
| 14 * derived from this software without specific prior written permission. |
| 15 * |
| 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 */ |
| 27 |
| 28 package org.webrtc; |
| 29 |
| 30 import android.os.Handler; |
| 31 import android.os.SystemClock; |
| 32 |
| 33 import java.util.concurrent.Callable; |
| 34 import java.util.concurrent.CountDownLatch; |
| 35 import java.util.concurrent.TimeUnit; |
| 36 |
| 37 final class ThreadUtils { |
| 38 /** |
| 39 * Utility class to be used for checking that a method is called on the correc
t thread. |
| 40 */ |
| 41 public static class ThreadChecker { |
| 42 private Thread thread = Thread.currentThread(); |
| 43 |
| 44 public void checkIsOnValidThread() { |
| 45 if (thread == null) { |
| 46 thread = Thread.currentThread(); |
| 47 } |
| 48 if (Thread.currentThread() != thread) { |
| 49 throw new IllegalStateException("Wrong thread"); |
| 50 } |
| 51 } |
| 52 |
| 53 public void detachThread() { |
| 54 thread = null; |
| 55 } |
| 56 } |
| 57 |
| 58 /** |
| 59 * Utility interface to be used with executeUninterruptibly() to wait for bloc
king operations |
| 60 * to complete without getting interrupted.. |
| 61 */ |
| 62 public interface BlockingOperation { |
| 63 void run() throws InterruptedException; |
| 64 } |
| 65 |
| 66 /** |
| 67 * Utility method to make sure a blocking operation is executed to completion
without getting |
| 68 * interrupted. This should be used in cases where the operation is waiting fo
r some critical |
| 69 * work, e.g. cleanup, that must complete before returning. If the thread is i
nterrupted during |
| 70 * the blocking operation, this function will re-run the operation until compl
etion, and only then |
| 71 * re-interrupt the thread. |
| 72 */ |
| 73 public static void executeUninterruptibly(BlockingOperation operation) { |
| 74 boolean wasInterrupted = false; |
| 75 while (true) { |
| 76 try { |
| 77 operation.run(); |
| 78 break; |
| 79 } catch (InterruptedException e) { |
| 80 // Someone is asking us to return early at our convenience. We can't can
cel this operation, |
| 81 // but we should preserve the information and pass it along. |
| 82 wasInterrupted = true; |
| 83 } |
| 84 } |
| 85 // Pass interruption information along. |
| 86 if (wasInterrupted) { |
| 87 Thread.currentThread().interrupt(); |
| 88 } |
| 89 } |
| 90 |
| 91 public static boolean joinUninterruptibly(final Thread thread, long timeoutMs)
{ |
| 92 final long startTimeMs = SystemClock.elapsedRealtime(); |
| 93 long timeRemainingMs = timeoutMs; |
| 94 boolean wasInterrupted = false; |
| 95 while (timeRemainingMs > 0) { |
| 96 try { |
| 97 thread.join(timeRemainingMs); |
| 98 break; |
| 99 } catch (InterruptedException e) { |
| 100 // Someone is asking us to return early at our convenience. We can't can
cel this operation, |
| 101 // but we should preserve the information and pass it along. |
| 102 wasInterrupted = true; |
| 103 final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs; |
| 104 timeRemainingMs = timeoutMs - elapsedTimeMs; |
| 105 } |
| 106 } |
| 107 // Pass interruption information along. |
| 108 if (wasInterrupted) { |
| 109 Thread.currentThread().interrupt(); |
| 110 } |
| 111 return !thread.isAlive(); |
| 112 } |
| 113 |
| 114 public static void joinUninterruptibly(final Thread thread) { |
| 115 executeUninterruptibly(new BlockingOperation() { |
| 116 @Override |
| 117 public void run() throws InterruptedException { |
| 118 thread.join(); |
| 119 } |
| 120 }); |
| 121 } |
| 122 |
| 123 public static void awaitUninterruptibly(final CountDownLatch latch) { |
| 124 executeUninterruptibly(new BlockingOperation() { |
| 125 @Override |
| 126 public void run() throws InterruptedException { |
| 127 latch.await(); |
| 128 } |
| 129 }); |
| 130 } |
| 131 |
| 132 public static boolean awaitUninterruptibly(CountDownLatch barrier, long timeou
tMs) { |
| 133 final long startTimeMs = SystemClock.elapsedRealtime(); |
| 134 long timeRemainingMs = timeoutMs; |
| 135 boolean wasInterrupted = false; |
| 136 boolean result = false; |
| 137 do { |
| 138 try { |
| 139 result = barrier.await(timeRemainingMs, TimeUnit.MILLISECONDS); |
| 140 break; |
| 141 } catch (InterruptedException e) { |
| 142 // Someone is asking us to return early at our convenience. We can't can
cel this operation, |
| 143 // but we should preserve the information and pass it along. |
| 144 wasInterrupted = true; |
| 145 final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs; |
| 146 timeRemainingMs = timeoutMs - elapsedTimeMs; |
| 147 } |
| 148 } while (timeRemainingMs > 0); |
| 149 // Pass interruption information along. |
| 150 if (wasInterrupted) { |
| 151 Thread.currentThread().interrupt(); |
| 152 } |
| 153 return result; |
| 154 } |
| 155 |
| 156 /** |
| 157 * Post |callable| to |handler| and wait for the result. |
| 158 */ |
| 159 public static <V> V invokeUninterruptibly(final Handler handler, final Callabl
e<V> callable) { |
| 160 class Result { |
| 161 public V value; |
| 162 } |
| 163 final Result result = new Result(); |
| 164 final CountDownLatch barrier = new CountDownLatch(1); |
| 165 handler.post(new Runnable() { |
| 166 @Override public void run() { |
| 167 try { |
| 168 result.value = callable.call(); |
| 169 } catch (Exception e) { |
| 170 throw new RuntimeException("Callable threw exception: " + e); |
| 171 } |
| 172 barrier.countDown(); |
| 173 } |
| 174 }); |
| 175 awaitUninterruptibly(barrier); |
| 176 return result.value; |
| 177 } |
| 178 |
| 179 /** |
| 180 * Post |runner| to |handler| and wait for the result. |
| 181 */ |
| 182 public static void invokeUninterruptibly(final Handler handler, final Runnable
runner) { |
| 183 final CountDownLatch barrier = new CountDownLatch(1); |
| 184 handler.post(new Runnable() { |
| 185 @Override public void run() { |
| 186 runner.run(); |
| 187 barrier.countDown(); |
| 188 } |
| 189 }); |
| 190 awaitUninterruptibly(barrier); |
| 191 } |
| 192 } |
OLD | NEW |