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