mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-19 18:03:47 +00:00
linux: allow collecting scheduler priorities to fail
SELinux blocks the handler from collecting these values on Android M. They should eventually be collected via the broker. Change-Id: Iad47759b2ebf23148cb5b2c401241ee87f8ffd27 Reviewed-on: https://chromium-review.googlesource.com/1226120 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
076d760d63
commit
8595f4b423
@ -60,31 +60,36 @@ bool ProcessReaderLinux::Thread::InitializePtrace(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(jperaza): Collect scheduling priorities via the broker when they can't
|
||||||
|
// be collected directly.
|
||||||
|
have_priorities = false;
|
||||||
|
|
||||||
// TODO(jperaza): Starting with Linux 3.14, scheduling policy, static
|
// TODO(jperaza): Starting with Linux 3.14, scheduling policy, static
|
||||||
// priority, and nice value can be collected all in one call with
|
// priority, and nice value can be collected all in one call with
|
||||||
// sched_getattr().
|
// sched_getattr().
|
||||||
int res = sched_getscheduler(tid);
|
int res = sched_getscheduler(tid);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
PLOG(ERROR) << "sched_getscheduler";
|
PLOG(WARNING) << "sched_getscheduler";
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
sched_policy = res;
|
sched_policy = res;
|
||||||
|
|
||||||
sched_param param;
|
sched_param param;
|
||||||
if (sched_getparam(tid, ¶m) != 0) {
|
if (sched_getparam(tid, ¶m) != 0) {
|
||||||
PLOG(ERROR) << "sched_getparam";
|
PLOG(WARNING) << "sched_getparam";
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
static_priority = param.sched_priority;
|
static_priority = param.sched_priority;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
res = getpriority(PRIO_PROCESS, tid);
|
res = getpriority(PRIO_PROCESS, tid);
|
||||||
if (res == -1 && errno) {
|
if (res == -1 && errno) {
|
||||||
PLOG(ERROR) << "getpriority";
|
PLOG(WARNING) << "getpriority";
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
nice_value = res;
|
nice_value = res;
|
||||||
|
|
||||||
|
have_priorities = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +66,10 @@ class ProcessReaderLinux {
|
|||||||
int static_priority;
|
int static_priority;
|
||||||
int nice_value;
|
int nice_value;
|
||||||
|
|
||||||
|
//! \brief `true` if `sched_policy`, `static_priority`, and `nice_value` are
|
||||||
|
//! all valid.
|
||||||
|
bool have_priorities;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class ProcessReaderLinux;
|
friend class ProcessReaderLinux;
|
||||||
|
|
||||||
|
@ -23,6 +23,109 @@
|
|||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
int ComputeThreadPriority(int static_priority,
|
||||||
|
int sched_policy,
|
||||||
|
int nice_value) {
|
||||||
|
// Map Linux scheduling policy, static priority, and nice value into a
|
||||||
|
// single int value.
|
||||||
|
//
|
||||||
|
// The possible policies in order of approximate priority (low to high) are
|
||||||
|
// SCHED_IDLE
|
||||||
|
// SCHED_BATCH
|
||||||
|
// SCHED_OTHER
|
||||||
|
// SCHED_RR
|
||||||
|
// SCHED_FIFO
|
||||||
|
//
|
||||||
|
// static_priority is not used for OTHER, BATCH, or IDLE and should be 0.
|
||||||
|
// For FIFO and RR, static_priority should range from 1 to 99 with 99 being
|
||||||
|
// the highest priority.
|
||||||
|
//
|
||||||
|
// nice value ranges from -20 to 19, with -20 being highest priority
|
||||||
|
|
||||||
|
enum class Policy : uint8_t {
|
||||||
|
kUnknown = 0,
|
||||||
|
kIdle,
|
||||||
|
kBatch,
|
||||||
|
kOther,
|
||||||
|
kRR,
|
||||||
|
kFIFO
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LinuxPriority {
|
||||||
|
#if defined(ARCH_CPU_LITTLE_ENDIAN)
|
||||||
|
// nice values affect how dynamic priorities are updated, which only
|
||||||
|
// matters for threads with the same static priority.
|
||||||
|
uint8_t nice_value = 0;
|
||||||
|
|
||||||
|
// The scheduling policy also affects how threads with the same static
|
||||||
|
// priority are ordered, but has greater impact than nice value.
|
||||||
|
Policy policy = Policy::kUnknown;
|
||||||
|
|
||||||
|
// The static priority is the most significant in determining overall
|
||||||
|
// priority.
|
||||||
|
uint8_t static_priority = 0;
|
||||||
|
|
||||||
|
// Put this in the most significant byte position to prevent negative
|
||||||
|
// priorities.
|
||||||
|
uint8_t unused = 0;
|
||||||
|
#elif defined(ARCH_CPU_BIG_ENDIAN)
|
||||||
|
uint8_t unused = 0;
|
||||||
|
uint8_t static_priority = 0;
|
||||||
|
Policy policy = Policy::kUnknown;
|
||||||
|
uint8_t nice_value = 0;
|
||||||
|
#endif // ARCH_CPU_LITTLE_ENDIAN
|
||||||
|
};
|
||||||
|
static_assert(sizeof(LinuxPriority) <= sizeof(int), "priority is too large");
|
||||||
|
|
||||||
|
LinuxPriority prio;
|
||||||
|
|
||||||
|
// Lower nice values have higher priority, so negate them and add 20 to put
|
||||||
|
// them in the range 1-40 with 40 being highest priority.
|
||||||
|
if (nice_value < -20 || nice_value > 19) {
|
||||||
|
LOG(WARNING) << "invalid nice value " << nice_value;
|
||||||
|
prio.nice_value = 0;
|
||||||
|
} else {
|
||||||
|
prio.nice_value = -1 * nice_value + 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (sched_policy) {
|
||||||
|
case SCHED_IDLE:
|
||||||
|
prio.policy = Policy::kIdle;
|
||||||
|
break;
|
||||||
|
case SCHED_BATCH:
|
||||||
|
prio.policy = Policy::kBatch;
|
||||||
|
break;
|
||||||
|
case SCHED_OTHER:
|
||||||
|
prio.policy = Policy::kOther;
|
||||||
|
break;
|
||||||
|
case SCHED_RR:
|
||||||
|
prio.policy = Policy::kRR;
|
||||||
|
break;
|
||||||
|
case SCHED_FIFO:
|
||||||
|
prio.policy = Policy::kFIFO;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
prio.policy = Policy::kUnknown;
|
||||||
|
LOG(WARNING) << "Unknown scheduling policy " << sched_policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static_priority < 0 || static_priority > 99) {
|
||||||
|
LOG(WARNING) << "invalid static priority " << static_priority;
|
||||||
|
}
|
||||||
|
prio.static_priority = static_priority;
|
||||||
|
|
||||||
|
int priority;
|
||||||
|
if (!ReinterpretBytes(prio, &priority)) {
|
||||||
|
LOG(ERROR) << "Couldn't set priority";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
ThreadSnapshotLinux::ThreadSnapshotLinux()
|
ThreadSnapshotLinux::ThreadSnapshotLinux()
|
||||||
: ThreadSnapshot(),
|
: ThreadSnapshot(),
|
||||||
context_union_(),
|
context_union_(),
|
||||||
@ -31,11 +134,9 @@ ThreadSnapshotLinux::ThreadSnapshotLinux()
|
|||||||
thread_specific_data_address_(0),
|
thread_specific_data_address_(0),
|
||||||
thread_id_(-1),
|
thread_id_(-1),
|
||||||
priority_(-1),
|
priority_(-1),
|
||||||
initialized_() {
|
initialized_() {}
|
||||||
}
|
|
||||||
|
|
||||||
ThreadSnapshotLinux::~ThreadSnapshotLinux() {
|
ThreadSnapshotLinux::~ThreadSnapshotLinux() {}
|
||||||
}
|
|
||||||
|
|
||||||
bool ThreadSnapshotLinux::Initialize(ProcessReaderLinux* process_reader,
|
bool ThreadSnapshotLinux::Initialize(ProcessReaderLinux* process_reader,
|
||||||
const ProcessReaderLinux::Thread& thread) {
|
const ProcessReaderLinux::Thread& thread) {
|
||||||
@ -89,107 +190,19 @@ bool ThreadSnapshotLinux::Initialize(ProcessReaderLinux* process_reader,
|
|||||||
#error Port.
|
#error Port.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
stack_.Initialize(process_reader,
|
stack_.Initialize(
|
||||||
thread.stack_region_address,
|
process_reader, thread.stack_region_address, thread.stack_region_size);
|
||||||
thread.stack_region_size);
|
|
||||||
|
|
||||||
thread_specific_data_address_ =
|
thread_specific_data_address_ =
|
||||||
thread.thread_info.thread_specific_data_address;
|
thread.thread_info.thread_specific_data_address;
|
||||||
|
|
||||||
thread_id_ = thread.tid;
|
thread_id_ = thread.tid;
|
||||||
|
|
||||||
// Map Linux scheduling policy, static priority, and nice value into a single
|
priority_ =
|
||||||
// int value.
|
thread.have_priorities
|
||||||
//
|
? ComputeThreadPriority(
|
||||||
// The possible policies in order of approximate priority (low to high) are
|
thread.static_priority, thread.sched_policy, thread.nice_value)
|
||||||
// SCHED_IDLE
|
: -1;
|
||||||
// SCHED_BATCH
|
|
||||||
// SCHED_OTHER
|
|
||||||
// SCHED_RR
|
|
||||||
// SCHED_FIFO
|
|
||||||
//
|
|
||||||
// static_priority is not used for OTHER, BATCH, or IDLE and should be 0.
|
|
||||||
// For FIFO and RR, static_priority should range from 1 to 99 with 99 being
|
|
||||||
// the highest priority.
|
|
||||||
//
|
|
||||||
// nice value ranges from -20 to 19, with -20 being highest priority
|
|
||||||
|
|
||||||
enum class Policy : uint8_t {
|
|
||||||
kUnknown = 0,
|
|
||||||
kIdle,
|
|
||||||
kBatch,
|
|
||||||
kOther,
|
|
||||||
kRR,
|
|
||||||
kFIFO
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LinuxPriority {
|
|
||||||
#if defined(ARCH_CPU_LITTLE_ENDIAN)
|
|
||||||
// nice values affect how dynamic priorities are updated, which only matters
|
|
||||||
// for threads with the same static priority.
|
|
||||||
uint8_t nice_value = 0;
|
|
||||||
|
|
||||||
// The scheduling policy also affects how threads with the same static
|
|
||||||
// priority are ordered, but has greater impact than nice value.
|
|
||||||
Policy policy = Policy::kUnknown;
|
|
||||||
|
|
||||||
// The static priority is the most significant in determining overall
|
|
||||||
// priority.
|
|
||||||
uint8_t static_priority = 0;
|
|
||||||
|
|
||||||
// Put this in the most significant byte position to prevent negative
|
|
||||||
// priorities.
|
|
||||||
uint8_t unused = 0;
|
|
||||||
#elif defined(ARCH_CPU_BIG_ENDIAN)
|
|
||||||
uint8_t unused = 0;
|
|
||||||
uint8_t static_priority = 0;
|
|
||||||
Policy policy = Policy::kUnknown;
|
|
||||||
uint8_t nice_value = 0;
|
|
||||||
#endif // ARCH_CPU_LITTLE_ENDIAN
|
|
||||||
};
|
|
||||||
static_assert(sizeof(LinuxPriority) <= sizeof(int), "priority is too large");
|
|
||||||
|
|
||||||
LinuxPriority prio;
|
|
||||||
|
|
||||||
// Lower nice values have higher priority, so negate them and add 20 to put
|
|
||||||
// them in the range 1-40 with 40 being highest priority.
|
|
||||||
if (thread.nice_value < -20 || thread.nice_value > 19) {
|
|
||||||
LOG(WARNING) << "invalid nice value " << thread.nice_value;
|
|
||||||
prio.nice_value = 0;
|
|
||||||
} else {
|
|
||||||
prio.nice_value = -1 * thread.nice_value + 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (thread.sched_policy) {
|
|
||||||
case SCHED_IDLE:
|
|
||||||
prio.policy = Policy::kIdle;
|
|
||||||
break;
|
|
||||||
case SCHED_BATCH:
|
|
||||||
prio.policy = Policy::kBatch;
|
|
||||||
break;
|
|
||||||
case SCHED_OTHER:
|
|
||||||
prio.policy = Policy::kOther;
|
|
||||||
break;
|
|
||||||
case SCHED_RR:
|
|
||||||
prio.policy = Policy::kRR;
|
|
||||||
break;
|
|
||||||
case SCHED_FIFO:
|
|
||||||
prio.policy = Policy::kFIFO;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
prio.policy = Policy::kUnknown;
|
|
||||||
LOG(WARNING) << "Unknown scheduling policy " << thread.sched_policy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread.static_priority < 0 || thread.static_priority > 99) {
|
|
||||||
LOG(WARNING) << "invalid static priority " << thread.static_priority;
|
|
||||||
}
|
|
||||||
prio.static_priority = thread.static_priority;
|
|
||||||
|
|
||||||
if (!ReinterpretBytes(prio, &priority_)) {
|
|
||||||
LOG(ERROR) << "Couldn't set priority";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user