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}