OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 package org.webrtc; | |
12 | |
13 import android.os.Handler; | |
14 import android.os.SystemClock; | |
15 | |
16 import java.util.concurrent.Callable; | |
17 import java.util.concurrent.CountDownLatch; | |
18 import java.util.concurrent.TimeUnit; | |
19 | |
20 public class ThreadUtils { | |
21 /** | |
22 * Utility class to be used for checking that a method is called on the correc
t thread. | |
23 */ | |
24 public static class ThreadChecker { | |
25 private Thread thread = Thread.currentThread(); | |
26 | |
27 public void checkIsOnValidThread() { | |
28 if (thread == null) { | |
29 thread = Thread.currentThread(); | |
30 } | |
31 if (Thread.currentThread() != thread) { | |
32 throw new IllegalStateException("Wrong thread"); | |
33 } | |
34 } | |
35 | |
36 public void detachThread() { | |
37 thread = null; | |
38 } | |
39 } | |
40 | |
41 /** | |
42 * Utility interface to be used with executeUninterruptibly() to wait for bloc
king operations | |
43 * to complete without getting interrupted.. | |
44 */ | |
45 public interface BlockingOperation { | |
46 void run() throws InterruptedException; | |
47 } | |
48 | |
49 /** | |
50 * Utility method to make sure a blocking operation is executed to completion
without getting | |
51 * interrupted. This should be used in cases where the operation is waiting fo
r some critical | |
52 * work, e.g. cleanup, that must complete before returning. If the thread is i
nterrupted during | |
53 * the blocking operation, this function will re-run the operation until compl
etion, and only then | |
54 * re-interrupt the thread. | |
55 */ | |
56 public static void executeUninterruptibly(BlockingOperation operation) { | |
57 boolean wasInterrupted = false; | |
58 while (true) { | |
59 try { | |
60 operation.run(); | |
61 break; | |
62 } catch (InterruptedException e) { | |
63 // Someone is asking us to return early at our convenience. We can't can
cel this operation, | |
64 // but we should preserve the information and pass it along. | |
65 wasInterrupted = true; | |
66 } | |
67 } | |
68 // Pass interruption information along. | |
69 if (wasInterrupted) { | |
70 Thread.currentThread().interrupt(); | |
71 } | |
72 } | |
73 | |
74 public static boolean joinUninterruptibly(final Thread thread, long timeoutMs)
{ | |
75 final long startTimeMs = SystemClock.elapsedRealtime(); | |
76 long timeRemainingMs = timeoutMs; | |
77 boolean wasInterrupted = false; | |
78 while (timeRemainingMs > 0) { | |
79 try { | |
80 thread.join(timeRemainingMs); | |
81 break; | |
82 } catch (InterruptedException e) { | |
83 // Someone is asking us to return early at our convenience. We can't can
cel this operation, | |
84 // but we should preserve the information and pass it along. | |
85 wasInterrupted = true; | |
86 final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs; | |
87 timeRemainingMs = timeoutMs - elapsedTimeMs; | |
88 } | |
89 } | |
90 // Pass interruption information along. | |
91 if (wasInterrupted) { | |
92 Thread.currentThread().interrupt(); | |
93 } | |
94 return !thread.isAlive(); | |
95 } | |
96 | |
97 public static void joinUninterruptibly(final Thread thread) { | |
98 executeUninterruptibly(new BlockingOperation() { | |
99 @Override | |
100 public void run() throws InterruptedException { | |
101 thread.join(); | |
102 } | |
103 }); | |
104 } | |
105 | |
106 public static void awaitUninterruptibly(final CountDownLatch latch) { | |
107 executeUninterruptibly(new BlockingOperation() { | |
108 @Override | |
109 public void run() throws InterruptedException { | |
110 latch.await(); | |
111 } | |
112 }); | |
113 } | |
114 | |
115 public static boolean awaitUninterruptibly(CountDownLatch barrier, long timeou
tMs) { | |
116 final long startTimeMs = SystemClock.elapsedRealtime(); | |
117 long timeRemainingMs = timeoutMs; | |
118 boolean wasInterrupted = false; | |
119 boolean result = false; | |
120 do { | |
121 try { | |
122 result = barrier.await(timeRemainingMs, TimeUnit.MILLISECONDS); | |
123 break; | |
124 } catch (InterruptedException e) { | |
125 // Someone is asking us to return early at our convenience. We can't can
cel this operation, | |
126 // but we should preserve the information and pass it along. | |
127 wasInterrupted = true; | |
128 final long elapsedTimeMs = SystemClock.elapsedRealtime() - startTimeMs; | |
129 timeRemainingMs = timeoutMs - elapsedTimeMs; | |
130 } | |
131 } while (timeRemainingMs > 0); | |
132 // Pass interruption information along. | |
133 if (wasInterrupted) { | |
134 Thread.currentThread().interrupt(); | |
135 } | |
136 return result; | |
137 } | |
138 | |
139 /** | |
140 * Post |callable| to |handler| and wait for the result. | |
141 */ | |
142 public static <V> V invokeUninterruptibly(final Handler handler, final Callabl
e<V> callable) { | |
143 class Result { | |
144 public V value; | |
145 } | |
146 final Result result = new Result(); | |
147 final CountDownLatch barrier = new CountDownLatch(1); | |
148 handler.post(new Runnable() { | |
149 @Override public void run() { | |
150 try { | |
151 result.value = callable.call(); | |
152 } catch (Exception e) { | |
153 final RuntimeException runtimeException = | |
154 new RuntimeException("Callable threw exception: " + e); | |
155 runtimeException.setStackTrace(e.getStackTrace()); | |
156 throw runtimeException; | |
157 } | |
158 barrier.countDown(); | |
159 } | |
160 }); | |
161 awaitUninterruptibly(barrier); | |
162 return result.value; | |
163 } | |
164 | |
165 /** | |
166 * Post |runner| to |handler| and wait for the result. | |
167 */ | |
168 public static void invokeUninterruptibly(final Handler handler, final Runnable
runner) { | |
169 final CountDownLatch barrier = new CountDownLatch(1); | |
170 handler.post(new Runnable() { | |
171 @Override public void run() { | |
172 runner.run(); | |
173 barrier.countDown(); | |
174 } | |
175 }); | |
176 awaitUninterruptibly(barrier); | |
177 } | |
178 } | |
OLD | NEW |