136db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi/* 236db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * Copyright (C) 2017 The Android Open Source Project 336db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * 436db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License"); 536db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * you may not use this file except in compliance with the License. 636db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * You may obtain a copy of the License at 736db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * 836db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * http://www.apache.org/licenses/LICENSE-2.0 936db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * 1036db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * Unless required by applicable law or agreed to in writing, software 1136db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS, 1236db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1336db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * See the License for the specific language governing permissions and 1436db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * limitations under the License 1536db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi */ 1636db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi 1736db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggipackage com.android.server; 1836db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi 19245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggiimport static android.os.Process.getThreadPriority; 20245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggiimport static android.os.Process.myTid; 21245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggiimport static android.os.Process.setThreadPriority; 2236db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi 2336db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi/** 2436db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * Utility class to boost threads in sections where important locks are held. 2536db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi */ 2636db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggipublic class ThreadPriorityBooster { 2736db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi 28245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi private volatile int mBoostToPriority; 2936db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi private final int mLockGuardIndex; 3036db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi 3136db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi private final ThreadLocal<PriorityState> mThreadState = new ThreadLocal<PriorityState>() { 3236db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi @Override protected PriorityState initialValue() { 3336db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi return new PriorityState(); 3436db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi } 3536db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi }; 3636db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi 3736db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi public ThreadPriorityBooster(int boostToPriority, int lockGuardIndex) { 3836db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi mBoostToPriority = boostToPriority; 3936db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi mLockGuardIndex = lockGuardIndex; 4036db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi } 4136db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi 4236db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi public void boost() { 43245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi final int tid = myTid(); 44245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi final int prevPriority = getThreadPriority(tid); 45245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi final PriorityState state = mThreadState.get(); 467e12b6d8489f68a43b0afb5111a6cfcddb350679Jorim Jaggi if (state.regionCounter == 0) { 477e12b6d8489f68a43b0afb5111a6cfcddb350679Jorim Jaggi state.prevPriority = prevPriority; 487e12b6d8489f68a43b0afb5111a6cfcddb350679Jorim Jaggi if (prevPriority > mBoostToPriority) { 497e12b6d8489f68a43b0afb5111a6cfcddb350679Jorim Jaggi setThreadPriority(tid, mBoostToPriority); 507e12b6d8489f68a43b0afb5111a6cfcddb350679Jorim Jaggi } 5136db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi } 5236db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi state.regionCounter++; 5336db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi if (LockGuard.ENABLED) { 5436db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi LockGuard.guard(mLockGuardIndex); 5536db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi } 5636db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi } 5736db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi 5836db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi public void reset() { 59245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi final PriorityState state = mThreadState.get(); 6036db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi state.regionCounter--; 61245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi final int currentPriority = getThreadPriority(myTid()); 62245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi if (state.regionCounter == 0 && state.prevPriority != currentPriority) { 63245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi setThreadPriority(myTid(), state.prevPriority); 64245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi } 65245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi } 66245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi 67245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi /** 68245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi * Updates the priority we boost the threads to, and updates the current thread's priority if 69245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi * necessary. 70245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi */ 71245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi protected void setBoostToPriority(int priority) { 72245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi 73245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi // We don't care about the other threads here, as long as they see the update of this 74245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi // variable immediately. 75245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi mBoostToPriority = priority; 76245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi final PriorityState state = mThreadState.get(); 77245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi final int tid = myTid(); 78245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi final int prevPriority = getThreadPriority(tid); 79245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi if (state.regionCounter != 0 && prevPriority != priority) { 80245281c056a5b880486671157b48d6c4e5815ce1Jorim Jaggi setThreadPriority(tid, priority); 8136db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi } 8236db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi } 8336db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi 8436db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi private static class PriorityState { 8536db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi 8636db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi /** 8736db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * Acts as counter for number of synchronized region that needs to acquire 'this' as a lock 8836db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * the current thread is currently in. When it drops down to zero, we will no longer boost 8936db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * the thread's priority. 9036db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi */ 9136db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi int regionCounter; 9236db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi 9336db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi /** 9436db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi * The thread's previous priority before boosting. 9536db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi */ 9636db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi int prevPriority; 9736db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi } 9836db127e4733ea8ef41a96be5b683e1a2e705677Jorim Jaggi}