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 |