• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.car.internal.util;
18 
19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
20 
21 import android.car.builtin.util.Slogf;
22 import android.os.Process;
23 
24 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
25 
26 import java.util.concurrent.CountDownLatch;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.Executor;
29 import java.util.concurrent.ExecutorService;
30 import java.util.concurrent.Executors;
31 import java.util.concurrent.Future;
32 import java.util.concurrent.ThreadFactory;
33 import java.util.concurrent.TimeUnit;
34 import java.util.concurrent.atomic.AtomicInteger;
35 
36 
37 // Copied from frameworks/base
38 
39 /**
40  * Utility methods for common functionality using java.util.concurrent package
41  *
42  * @hide
43  */
44 public class ConcurrentUtils {
45 
ConcurrentUtils()46     private ConcurrentUtils() {
47     }
48 
49     public static final Executor DIRECT_EXECUTOR = new DirectExecutor();
50 
51     /**
52      * Creates a thread pool using
53      * {@link java.util.concurrent.Executors#newFixedThreadPool(int, ThreadFactory)}
54      *
55      * @param nThreads the number of threads in the pool
56      * @param poolName base name of the threads in the pool
57      * @param linuxThreadPriority a Linux priority level. see {@link Process#setThreadPriority(int)}
58      * @return the newly created thread pool
59      */
newFixedThreadPool(int nThreads, String poolName, int linuxThreadPriority)60     public static ExecutorService newFixedThreadPool(int nThreads, String poolName,
61             int linuxThreadPriority) {
62         return Executors.newFixedThreadPool(nThreads,
63                 new ThreadFactory() {
64                     private final AtomicInteger mThreadNum = new AtomicInteger(0);
65 
66                     @Override
67                     public Thread newThread(final Runnable r) {
68                         return new Thread(poolName + mThreadNum.incrementAndGet()) {
69                             @Override
70                             public void run() {
71                                 Process.setThreadPriority(linuxThreadPriority);
72                                 r.run();
73                             }
74                         };
75                     }
76                 });
77     }
78 
79     /**
80      * Waits if necessary for the computation to complete, and then retrieves its result.
81      * <p>If {@code InterruptedException} occurs, this method will interrupt the current thread
82      * and throw {@code IllegalStateException}</p>
83      *
84      * @param future future to wait for result
85      * @param description short description of the operation
86      * @return the computed result
87      * @throws IllegalStateException if interrupted during wait
88      * @throws RuntimeException if an error occurs while waiting for {@link Future#get()}
89      * @see Future#get()
90      */
91     public static <T> T waitForFutureNoInterrupt(Future<T> future, String description) {
92         try {
93             return future.get();
94         } catch (InterruptedException e) {
95             Thread.currentThread().interrupt();
96             throw new IllegalStateException(description + " interrupted");
97         } catch (ExecutionException e) {
98             throw new RuntimeException(description + " failed", e);
99         }
100     }
101 
102     /**
103      * Waits for {@link CountDownLatch#countDown()} to be called on the {@code countDownLatch}.
104      * <p>If {@link CountDownLatch#countDown()} doesn't occur within {@code timeoutMs}, this
105      * method will throw {@code IllegalStateException}
106      * <p>If {@code InterruptedException} occurs, this method will interrupt the current thread
107      * and throw {@code IllegalStateException}
108      *
109      * @param countDownLatch the CountDownLatch which {@link CountDownLatch#countDown()} is
110      *                       being waited on.
111      * @param timeoutMs the maximum time waited for {@link CountDownLatch#countDown()}
112      * @param description a short description of the operation
113      */
114     public static void waitForCountDownNoInterrupt(CountDownLatch countDownLatch, long timeoutMs,
115             String description) {
116         try {
117             if (!countDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
118                 throw new IllegalStateException(description + " timed out.");
119             }
120         } catch (InterruptedException e) {
121             Thread.currentThread().interrupt();
122             throw new IllegalStateException(description + " interrupted.");
123         }
124     }
125 
126     /**
127      * Calls {@link Slog#wtf} if a given lock is held.
128      */
129     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
130     public static void wtfIfLockHeld(String tag, Object lock) {
131         if (Thread.holdsLock(lock)) {
132             Slogf.wtf(tag, "Lock mustn't be held");
133         }
134     }
135 
136     /**
137      * Calls {@link Slog#wtf} if a given lock is not held.
138      */
139     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
140     public static void wtfIfLockNotHeld(String tag, Object lock) {
141         if (!Thread.holdsLock(lock)) {
142             Slogf.wtf(tag, "Lock must be held");
143         }
144     }
145 
146     private static class DirectExecutor implements Executor {
147 
148         @Override
149         public void execute(Runnable command) {
150             command.run();
151         }
152 
153         @Override
154         @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
155         public String toString() {
156             return "DIRECT_EXECUTOR";
157         }
158     }
159 }
160