mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 980027 - Part 1: Provide mechanism to set thread priorities. r=gsvelto, r=dhylands
This commit is contained in:
parent
042dcaf7fc
commit
da2b2f344d
18
hal/Hal.cpp
18
hal/Hal.cpp
@ -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,
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
20
hal/fallback/FallbackThreadPriority.cpp
Normal file
20
hal/fallback/FallbackThreadPriority.cpp
Normal 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
|
@ -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()
|
||||
{
|
||||
|
@ -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',
|
||||
]
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user