mirror of
https://github.com/chromium/crashpad.git
synced 2025-01-14 09:17:57 +08: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;
|
||||
}
|
||||
|
||||
// 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
|
||||
// priority, and nice value can be collected all in one call with
|
||||
// sched_getattr().
|
||||
int res = sched_getscheduler(tid);
|
||||
if (res < 0) {
|
||||
PLOG(ERROR) << "sched_getscheduler";
|
||||
return false;
|
||||
PLOG(WARNING) << "sched_getscheduler";
|
||||
return true;
|
||||
}
|
||||
sched_policy = res;
|
||||
|
||||
sched_param param;
|
||||
if (sched_getparam(tid, ¶m) != 0) {
|
||||
PLOG(ERROR) << "sched_getparam";
|
||||
return false;
|
||||
PLOG(WARNING) << "sched_getparam";
|
||||
return true;
|
||||
}
|
||||
static_priority = param.sched_priority;
|
||||
|
||||
errno = 0;
|
||||
res = getpriority(PRIO_PROCESS, tid);
|
||||
if (res == -1 && errno) {
|
||||
PLOG(ERROR) << "getpriority";
|
||||
return false;
|
||||
PLOG(WARNING) << "getpriority";
|
||||
return true;
|
||||
}
|
||||
nice_value = res;
|
||||
|
||||
have_priorities = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,10 @@ class ProcessReaderLinux {
|
||||
int static_priority;
|
||||
int nice_value;
|
||||
|
||||
//! \brief `true` if `sched_policy`, `static_priority`, and `nice_value` are
|
||||
//! all valid.
|
||||
bool have_priorities;
|
||||
|
||||
private:
|
||||
friend class ProcessReaderLinux;
|
||||
|
||||
|
@ -23,6 +23,109 @@
|
||||
namespace crashpad {
|
||||
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()
|
||||
: ThreadSnapshot(),
|
||||
context_union_(),
|
||||
@ -31,11 +134,9 @@ ThreadSnapshotLinux::ThreadSnapshotLinux()
|
||||
thread_specific_data_address_(0),
|
||||
thread_id_(-1),
|
||||
priority_(-1),
|
||||
initialized_() {
|
||||
}
|
||||
initialized_() {}
|
||||
|
||||
ThreadSnapshotLinux::~ThreadSnapshotLinux() {
|
||||
}
|
||||
ThreadSnapshotLinux::~ThreadSnapshotLinux() {}
|
||||
|
||||
bool ThreadSnapshotLinux::Initialize(ProcessReaderLinux* process_reader,
|
||||
const ProcessReaderLinux::Thread& thread) {
|
||||
@ -89,107 +190,19 @@ bool ThreadSnapshotLinux::Initialize(ProcessReaderLinux* process_reader,
|
||||
#error Port.
|
||||
#endif
|
||||
|
||||
stack_.Initialize(process_reader,
|
||||
thread.stack_region_address,
|
||||
thread.stack_region_size);
|
||||
stack_.Initialize(
|
||||
process_reader, thread.stack_region_address, thread.stack_region_size);
|
||||
|
||||
thread_specific_data_address_ =
|
||||
thread.thread_info.thread_specific_data_address;
|
||||
|
||||
thread_id_ = thread.tid;
|
||||
|
||||
// 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 (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;
|
||||
}
|
||||
priority_ =
|
||||
thread.have_priorities
|
||||
? ComputeThreadPriority(
|
||||
thread.static_priority, thread.sched_policy, thread.nice_value)
|
||||
: -1;
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user