Bug 980027 - Part 1: Provide mechanism to set thread priorities. r=gsvelto, r=dhylands

This commit is contained in:
Mason Chang 2014-05-05 11:37:00 -04:00
parent 042dcaf7fc
commit da2b2f344d
7 changed files with 230 additions and 6 deletions

View File

@ -871,6 +871,12 @@ SetProcessPriority(int aPid,
aBackgroundLRU));
}
void
SetCurrentThreadPriority(hal::ThreadPriority aThreadPriority)
{
PROXY_IF_SANDBOXED(SetCurrentThreadPriority(aThreadPriority));
}
// From HalTypes.h.
const char*
ProcessPriorityToString(ProcessPriority aPriority)
@ -900,6 +906,18 @@ ProcessPriorityToString(ProcessPriority aPriority)
}
}
const char *
ThreadPriorityToString(ThreadPriority aPriority)
{
switch (aPriority) {
case THREAD_PRIORITY_COMPOSITOR:
return "COMPOSITOR";
default:
MOZ_ASSERT(false);
return "???";
}
}
// From HalTypes.h.
const char*
ProcessPriorityToString(ProcessPriority aPriority,

View File

@ -496,6 +496,14 @@ void SetProcessPriority(int aPid,
hal::ProcessCPUPriority aCPUPriority,
uint32_t aLRU = 0);
/**
* Set the current thread's priority to appropriate platform-specific value for
* given functionality. Instead of providing arbitrary priority numbers you
* must specify a type of function like THREAD_PRIORITY_COMPOSITOR.
*/
void SetCurrentThreadPriority(hal::ThreadPriority aThreadPriority);
/**
* Register an observer for the FM radio.
*/

View File

@ -102,12 +102,26 @@ enum ProcessCPUPriority {
NUM_PROCESS_CPU_PRIORITY
};
// Convert a ProcessPriority enum value (with an optional ProcessCPUPriority)
// to a string. The strings returned by this function are statically
// allocated; do not attempt to free one!
//
// If you pass an unknown process priority (or NUM_PROCESS_PRIORITY), we
// fatally assert in debug builds and otherwise return "???".
/**
* Values that can be passed to hal::SetCurrentThreadPriority(). These should be
* functional in nature, such as COMPOSITOR, instead of levels, like LOW/HIGH.
* This allows us to tune our priority scheme for the system in one place such
* that it makes sense holistically for the overall operating system. On gonk
* or android we may want different priority schemes than on windows, etc.
*/
enum ThreadPriority {
THREAD_PRIORITY_COMPOSITOR,
NUM_THREAD_PRIORITY
};
/**
* Convert a ProcessPriority enum value (with an optional ProcessCPUPriority)
* to a string. The strings returned by this function are statically
* allocated; do not attempt to free one!
*
* If you pass an unknown process priority, we fatally assert in debug
* builds and otherwise return "???".
*/
const char*
ProcessPriorityToString(ProcessPriority aPriority);
@ -115,6 +129,16 @@ const char*
ProcessPriorityToString(ProcessPriority aPriority,
ProcessCPUPriority aCPUPriority);
/**
* Convert a ThreadPriority enum value to a string. The strings returned by
* this function are statically allocated; do not attempt to free one!
*
* If you pass an unknown process priority, we assert in debug builds
* and otherwise return "???".
*/
const char *
ThreadPriorityToString(ThreadPriority aPriority);
/**
* Used by ModifyWakeLock
*/

View File

@ -0,0 +1,20 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Hal.h"
using namespace mozilla::hal;
namespace mozilla {
namespace hal_impl {
void
SetCurrentThreadPriority(ThreadPriority aPriority)
{
HAL_LOG(("FallbackThreadPriority - SetCurrentThreadPriority(%d)\n",
ThreadPriorityToString(aPriority)));
}
} // hal_impl
} // namespace mozilla

View File

@ -21,6 +21,7 @@
#include <linux/android_alarm.h>
#include <math.h>
#include <regex.h>
#include <sched.h>
#include <stdio.h>
#include <sys/klog.h>
#include <sys/syscall.h>
@ -38,6 +39,7 @@
#include "hardware_legacy/vibrator.h"
#include "hardware_legacy/power.h"
#include "libdisplay/GonkDisplay.h"
#include "utils/threads.h"
#include "base/message_loop.h"
@ -1357,6 +1359,14 @@ SetNiceForPid(int aPid, int aNice)
int tid = static_cast<int>(tidlong);
// Do not set the priority of threads running with a real-time policy
// as part of the bulk process adjustment. These threads need to run
// at their specified priority in order to meet timing guarantees.
int schedPolicy = sched_getscheduler(tid);
if (schedPolicy == SCHED_FIFO || schedPolicy == SCHED_RR) {
continue;
}
errno = 0;
// Get and set the task's new priority.
int origtaskpriority = getpriority(PRIO_PROCESS, tid);
@ -1369,6 +1379,15 @@ SetNiceForPid(int aPid, int aNice)
int newtaskpriority =
std::max(origtaskpriority - origProcPriority + aNice, aNice);
// Do not reduce priority of threads already running at priorities greater
// than normal. These threads are likely special service threads that need
// elevated priorities to process audio, display composition, etc.
if (newtaskpriority > origtaskpriority &&
origtaskpriority < ANDROID_PRIORITY_NORMAL) {
continue;
}
rv = setpriority(PRIO_PROCESS, tid, newtaskpriority);
if (rv) {
@ -1463,6 +1482,134 @@ SetProcessPriority(int aPid,
}
}
static bool
IsValidRealTimePriority(int aValue, int aSchedulePolicy)
{
return (aValue >= sched_get_priority_min(aSchedulePolicy)) &&
(aValue <= sched_get_priority_max(aSchedulePolicy));
}
static void
SetThreadNiceValue(pid_t aTid, ThreadPriority aThreadPriority, int aValue)
{
MOZ_ASSERT(aThreadPriority < NUM_THREAD_PRIORITY);
MOZ_ASSERT(aThreadPriority >= 0);
LOG("Setting thread %d to priority level %s; nice level %d",
aTid, ThreadPriorityToString(aThreadPriority), aValue);
int rv = setpriority(PRIO_PROCESS, aTid, aValue);
if (rv) {
LOG("Failed to set thread %d to priority level %s; error %s",
aTid, ThreadPriorityToString(aThreadPriority), strerror(errno));
}
}
static void
SetRealTimeThreadPriority(pid_t aTid,
ThreadPriority aThreadPriority,
int aValue)
{
int policy = SCHED_FIFO;
MOZ_ASSERT(aThreadPriority < NUM_THREAD_PRIORITY);
MOZ_ASSERT(aThreadPriority >= 0);
MOZ_ASSERT(IsValidRealTimePriority(aValue, policy), "Invalid real time priority");
// Setting real time priorities requires using sched_setscheduler
LOG("Setting thread %d to priority level %s; Real Time priority %d, Schedule FIFO",
aTid, ThreadPriorityToString(aThreadPriority), aValue);
sched_param schedParam;
schedParam.sched_priority = aValue;
int rv = sched_setscheduler(aTid, policy, &schedParam);
if (rv) {
LOG("Failed to set thread %d to real time priority level %s; error %s",
aTid, ThreadPriorityToString(aThreadPriority), strerror(errno));
}
}
static void
SetThreadPriority(pid_t aTid, hal::ThreadPriority aThreadPriority)
{
// See bug 999115, we can only read preferences on the main thread otherwise
// we create a race condition in HAL
MOZ_ASSERT(NS_IsMainThread(), "Can only set thread priorities on main thread");
MOZ_ASSERT(aThreadPriority >= 0);
const char* threadPriorityStr;
switch (aThreadPriority) {
case THREAD_PRIORITY_COMPOSITOR:
threadPriorityStr = ThreadPriorityToString(aThreadPriority);
break;
default:
LOG("Unrecognized thread priority %d; Doing nothing", aThreadPriority);
return;
}
int realTimePriority = Preferences::GetInt(
nsPrintfCString("hal.gonk.%s.rt_priority", threadPriorityStr).get());
if (IsValidRealTimePriority(realTimePriority, SCHED_FIFO)) {
SetRealTimeThreadPriority(aTid, aThreadPriority, realTimePriority);
return;
}
int niceValue = Preferences::GetInt(
nsPrintfCString("hal.gonk.%s.nice", threadPriorityStr).get());
SetThreadNiceValue(aTid, aThreadPriority, niceValue);
}
namespace {
/**
* This class sets the priority of threads given the kernel thread's id and a
* value taken from hal::ThreadPriority.
*
* This runnable must always be dispatched to the main thread otherwise it will fail.
* We have to run this from the main thread since preferences can only be read on
* main thread.
*/
class SetThreadPriorityRunnable : public nsRunnable
{
public:
SetThreadPriorityRunnable(pid_t aThreadId, hal::ThreadPriority aThreadPriority)
: mThreadId(aThreadId)
, mThreadPriority(aThreadPriority)
{ }
NS_IMETHOD Run()
{
NS_ASSERTION(NS_IsMainThread(), "Can only set thread priorities on main thread");
hal_impl::SetThreadPriority(mThreadId, mThreadPriority);
return NS_OK;
}
private:
pid_t mThreadId;
hal::ThreadPriority mThreadPriority;
};
} // anonymous namespace
void
SetCurrentThreadPriority(ThreadPriority aThreadPriority)
{
switch (aThreadPriority) {
case THREAD_PRIORITY_COMPOSITOR: {
pid_t threadId = gettid();
nsCOMPtr<nsIRunnable> runnable =
new SetThreadPriorityRunnable(threadId, aThreadPriority);
NS_DispatchToMainThread(runnable);
break;
}
default:
LOG("Unrecognized thread priority %d; Doing nothing", aThreadPriority);
return;
}
}
void
FactoryReset()
{

View File

@ -155,6 +155,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
'fallback/FallbackProcessPriority.cpp',
'fallback/FallbackScreenPower.cpp',
'fallback/FallbackSwitch.cpp',
'fallback/FallbackThreadPriority.cpp',
'fallback/FallbackTime.cpp',
'fallback/FallbackWakeLocks.cpp',
]

View File

@ -362,6 +362,12 @@ SetProcessPriority(int aPid,
NS_RUNTIMEABORT("Only the main process may set processes' priorities.");
}
void
SetCurrentThreadPriority(ThreadPriority aThreadPriority)
{
NS_RUNTIMEABORT("Setting thread priority cannot be called from sandboxed contexts.");
}
void
EnableFMRadio(const hal::FMRadioSettings& aSettings)
{