• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.internal.util;
18 
19 import android.os.Process;
20 import android.util.Slog;
21 
22 import java.util.concurrent.CountDownLatch;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.Executor;
25 import java.util.concurrent.ExecutorService;
26 import java.util.concurrent.Executors;
27 import java.util.concurrent.Future;
28 import java.util.concurrent.ThreadFactory;
29 import java.util.concurrent.TimeUnit;
30 import java.util.concurrent.atomic.AtomicInteger;
31 
32 /**
33  * Utility methods for common functionality using java.util.concurrent package
34  *
35  * @hide
36  */
37 public class ConcurrentUtils {
38 
ConcurrentUtils()39     private ConcurrentUtils() {
40     }
41 
42     public static final Executor DIRECT_EXECUTOR = new DirectExecutor();
43 
44     /**
45      * Creates a thread pool using
46      * {@link java.util.concurrent.Executors#newFixedThreadPool(int, ThreadFactory)}
47      *
48      * @param nThreads the number of threads in the pool
49      * @param poolName base name of the threads in the pool
50      * @param linuxThreadPriority a Linux priority level. see {@link Process#setThreadPriority(int)}
51      * @return the newly created thread pool
52      */
newFixedThreadPool(int nThreads, String poolName, int linuxThreadPriority)53     public static ExecutorService newFixedThreadPool(int nThreads, String poolName,
54             int linuxThreadPriority) {
55         return Executors.newFixedThreadPool(nThreads,
56                 new ThreadFactory() {
57                     private final AtomicInteger threadNum = new AtomicInteger(0);
58 
59                     @Override
60                     public Thread newThread(final Runnable r) {
61                         return new Thread(poolName + threadNum.incrementAndGet()) {
62                             @Override
63                             public void run() {
64                                 Process.setThreadPriority(linuxThreadPriority);
65                                 r.run();
66                             }
67                         };
68                     }
69                 });
70     }
71 
72     /**
73      * Waits if necessary for the computation to complete, and then retrieves its result.
74      * <p>If {@code InterruptedException} occurs, this method will interrupt the current thread
75      * and throw {@code IllegalStateException}</p>
76      *
77      * @param future future to wait for result
78      * @param description short description of the operation
79      * @return the computed result
80      * @throws IllegalStateException if interrupted during wait
81      * @throws RuntimeException if an error occurs while waiting for {@link Future#get()}
82      * @see Future#get()
83      */
84     public static <T> T waitForFutureNoInterrupt(Future<T> future, String description) {
85         try {
86             return future.get();
87         } catch (InterruptedException e) {
88             Thread.currentThread().interrupt();
89             throw new IllegalStateException(description + " interrupted");
90         } catch (ExecutionException e) {
91             throw new RuntimeException(description + " failed", e);
92         }
93     }
94 
95     /**
96      * Waits for {@link CountDownLatch#countDown()} to be called on the {@param countDownLatch}.
97      * <p>If {@link CountDownLatch#countDown()} doesn't occur within {@param timeoutMs}, this
98      * method will throw {@code IllegalStateException}
99      * <p>If {@code InterruptedException} occurs, this method will interrupt the current thread
100      * and throw {@code IllegalStateException}
101      *
102      * @param countDownLatch the CountDownLatch which {@link CountDownLatch#countDown()} is
103      *                       being waited on.
104      * @param timeoutMs the maximum time waited for {@link CountDownLatch#countDown()}
105      * @param description a short description of the operation
106      */
107     public static void waitForCountDownNoInterrupt(CountDownLatch countDownLatch, long timeoutMs,
108             String description) {
109         try {
110             if (!countDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
111                 throw new IllegalStateException(description + " timed out.");
112             }
113         } catch (InterruptedException e) {
114             Thread.currentThread().interrupt();
115             throw new IllegalStateException(description + " interrupted.");
116         }
117     }
118 
119     /**
120      * Calls {@link Slog#wtf} if a given lock is held.
121      */
122     public static void wtfIfLockHeld(String tag, Object lock) {
123         if (Thread.holdsLock(lock)) {
124             Slog.wtf(tag, "Lock mustn't be held");
125         }
126     }
127 
128     /**
129      * Calls {@link Slog#wtf} if a given lock is not held.
130      */
131     public static void wtfIfLockNotHeld(String tag, Object lock) {
132         if (!Thread.holdsLock(lock)) {
133             Slog.wtf(tag, "Lock must be held");
134         }
135     }
136 
137     private static class DirectExecutor implements Executor {
138 
139         @Override
140         public void execute(Runnable command) {
141             command.run();
142         }
143 
144         @Override
145         public String toString() {
146             return "DIRECT_EXECUTOR";
147         }
148     }
149 }
150