|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
|
2 // Use of this source code is governed by a BSD-style license that can be |
|
3 // found in the LICENSE file. |
|
4 |
|
5 package org.chromium.sdk; |
|
6 |
|
7 import java.util.concurrent.Semaphore; |
|
8 import java.util.concurrent.TimeUnit; |
|
9 |
|
10 import org.chromium.sdk.internal.tools.v8.MethodIsBlockingException; |
|
11 |
|
12 /** |
|
13 * Convenient implementation of {@code SyncCallback}. Client may create one, |
|
14 * then call asynchronous command, and finally wait on blocking method |
|
15 * {@code #tryAcquire()}. |
|
16 */ |
|
17 public class CallbackSemaphore implements SyncCallback { |
|
18 public static final long OPERATION_TIMEOUT_MS = 120000; |
|
19 |
|
20 private final Semaphore sem = new Semaphore(0); |
|
21 private Exception savedException; |
|
22 |
|
23 /** |
|
24 * Tries to acquire semaphore with some reasonable default timeout. |
|
25 * @return false if {@code #OPERATION_TIMEOUT_MS} was exceeded and we gave up |
|
26 * @throws MethodIsBlockingException if called from a callback |
|
27 */ |
|
28 public boolean tryAcquireDefault() throws MethodIsBlockingException { |
|
29 return tryAcquire(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS); |
|
30 } |
|
31 |
|
32 /** |
|
33 * Tries to acquire the semaphore. This method blocks until the semaphore is |
|
34 * released; typically release call comes from a worker thread of |
|
35 * org.chromium.sdk, the same thread that may call all other callbacks. |
|
36 * It is vital not to call this method from any callback of org.chromium.sdk, |
|
37 * because it's a sure deadlock. |
|
38 * To prevent, this the method declares throwing |
|
39 * {@code MethodIsBlockingException} which is symbolically thrown whenever |
|
40 * someone violates this rule (i.e. invokes this method from a callback). |
|
41 * Though currently nobody actually throws it, such declarations help to |
|
42 * track blocking methods. |
|
43 * @return false if {@code timeout} was exceeded and we gave up |
|
44 * @throws MethodIsBlockingException if called from a callback |
|
45 */ |
|
46 public boolean tryAcquire(long timeout, TimeUnit unit) throws MethodIsBlockingException { |
|
47 boolean res; |
|
48 try { |
|
49 res = sem.tryAcquire(timeout, unit); |
|
50 } catch (InterruptedException e) { |
|
51 throw new RuntimeException(e); |
|
52 } |
|
53 if (savedException != null) { |
|
54 throw new RuntimeException("Exception occured in callback", savedException); |
|
55 } |
|
56 return res; |
|
57 } |
|
58 /** |
|
59 * Implementation of {@code SyncCallback#callbackDone(RuntimeException)}. |
|
60 */ |
|
61 public void callbackDone(RuntimeException e) { |
|
62 if (e == null) { |
|
63 savedException = null; |
|
64 } else { |
|
65 savedException = new Exception("Exception saved from callback", e); |
|
66 } |
|
67 sem.release(); |
|
68 } |
|
69 } |