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