184 lines
5.6 KiB
C++
184 lines
5.6 KiB
C++
// Copyright 2018 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "base/threading/platform_thread.h"
|
|
|
|
#include <array>
|
|
|
|
#include "base/bits.h"
|
|
#include "base/no_destructor.h"
|
|
#include "base/task/current_thread.h"
|
|
#include "base/threading/scoped_thread_priority.h"
|
|
#include "base/threading/thread_id_name_manager.h"
|
|
#include "base/trace_event/trace_event.h"
|
|
|
|
#if BUILDFLAG(IS_FUCHSIA)
|
|
#include "base/fuchsia/scheduler.h"
|
|
#endif
|
|
|
|
namespace base {
|
|
namespace {
|
|
|
|
MessagePumpType GetCurrentMessagePumpType() {
|
|
// CurrentIOThread::IsSet() and CurrentUIThread::IsSet() can't both be set at
|
|
// the same time, so there's no precedence to worry about: both
|
|
// CurrentIOThread::IsSet() and CurrentUIThread::IsSet() rely on
|
|
// GetCurrentSequenceManagerImpl(), which returns the single SequenceManager
|
|
// instance bound to the current thread.
|
|
if (CurrentIOThread::IsSet()) {
|
|
return MessagePumpType::IO;
|
|
} else if (CurrentUIThread::IsSet()) {
|
|
return MessagePumpType::UI;
|
|
}
|
|
return MessagePumpType::DEFAULT;
|
|
}
|
|
|
|
internal::ThreadTypeManager* GetThreadTypeManager() {
|
|
constinit thread_local internal::ThreadTypeManager thread_type_manager;
|
|
return &thread_type_manager;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void PlatformThreadId::WriteIntoTrace(perfetto::TracedValue&& context) const {
|
|
perfetto::WriteIntoTracedValue(std::move(context), value_);
|
|
}
|
|
|
|
// static
|
|
void PlatformThreadBase::SetDefaultThreadType(ThreadType thread_type) {
|
|
GetThreadTypeManager()->SetDefault(thread_type);
|
|
}
|
|
|
|
// static
|
|
ThreadType PlatformThreadBase::GetCurrentThreadType() {
|
|
return GetThreadTypeManager()->GetCurrent();
|
|
}
|
|
|
|
// static
|
|
std::optional<TimeDelta> PlatformThreadBase::GetThreadLeewayOverride() {
|
|
#if BUILDFLAG(IS_FUCHSIA)
|
|
// On Fuchsia, all audio threads run with the CPU scheduling profile that uses
|
|
// an interval of |kAudioSchedulingPeriod|. Using the default leeway may lead
|
|
// to some tasks posted to audio threads to be executed too late (see
|
|
// http://crbug.com/1368858).
|
|
if (GetCurrentThreadType() == ThreadType::kRealtimeAudio) {
|
|
return kAudioSchedulingPeriod;
|
|
}
|
|
#endif
|
|
return std::nullopt;
|
|
}
|
|
|
|
// static
|
|
void PlatformThreadBase::SetNameCommon(const std::string& name) {
|
|
ThreadIdNameManager::GetInstance()->SetName(name);
|
|
}
|
|
|
|
// static
|
|
bool PlatformThreadBase::CurrentThreadHasLeases() {
|
|
return GetThreadTypeManager()->HasLeases();
|
|
}
|
|
|
|
PlatformThreadBase::RaiseThreadTypeLease::RaiseThreadTypeLease(
|
|
ThreadType thread_type)
|
|
: RaiseThreadTypeLease(thread_type, GetThreadTypeManager()) {}
|
|
|
|
PlatformThreadBase::RaiseThreadTypeLease::RaiseThreadTypeLease(
|
|
ThreadType thread_type,
|
|
internal::ThreadTypeManager* manager)
|
|
: leased_thread_type_(thread_type), manager_(manager) {
|
|
// Creating a lease while a ScopedBoostPriority is active is not allowed.
|
|
DCHECK(!ScopedBoostablePriority::CurrentThreadHasScope());
|
|
manager_->AcquireRaiseLease(thread_type);
|
|
}
|
|
|
|
PlatformThreadBase::RaiseThreadTypeLease::RaiseThreadTypeLease(
|
|
RaiseThreadTypeLease&& other) noexcept
|
|
: leased_thread_type_(other.leased_thread_type_),
|
|
manager_(std::exchange(other.manager_, nullptr)) {}
|
|
|
|
PlatformThreadBase::RaiseThreadTypeLease::~RaiseThreadTypeLease() {
|
|
if (manager_) {
|
|
// Releasing a lease while a ScopedBoostPriority is active is not allowed.
|
|
DCHECK(!ScopedBoostablePriority::CurrentThreadHasScope());
|
|
manager_->DropRaiseLease(leased_thread_type_);
|
|
}
|
|
}
|
|
|
|
namespace internal {
|
|
|
|
void ThreadTypeManager::SetDefault(ThreadType type) {
|
|
CHECK_LE(type, ThreadType::kMaxValue);
|
|
default_thread_type_ = type;
|
|
MaybeUpdate();
|
|
}
|
|
|
|
ThreadType ThreadTypeManager::GetCurrent() const {
|
|
return effective_thread_type_.value_or(ThreadType::kDefault);
|
|
}
|
|
|
|
void ThreadTypeManager::MaybeUpdate() {
|
|
auto highest_lease = raise_leases_.GetHighestLease();
|
|
ThreadType type;
|
|
if (!highest_lease.has_value() && !default_thread_type_.has_value()) {
|
|
type = ThreadType::kDefault;
|
|
} else {
|
|
type = std::max(highest_lease.value_or(ThreadType::kBackground),
|
|
default_thread_type_.value_or(ThreadType::kBackground));
|
|
}
|
|
|
|
if (type != effective_thread_type_) {
|
|
effective_thread_type_ = type;
|
|
SetCurrentThreadTypeImpl(effective_thread_type_.value(),
|
|
GetCurrentMessagePumpType());
|
|
}
|
|
}
|
|
|
|
void ThreadTypeManager::AcquireRaiseLease(ThreadType type) {
|
|
CHECK_LE(type, ThreadType::kMaxValue);
|
|
raise_leases_.Acquire(type);
|
|
MaybeUpdate();
|
|
}
|
|
|
|
void ThreadTypeManager::DropRaiseLease(ThreadType type) {
|
|
CHECK_LE(type, ThreadType::kMaxValue);
|
|
raise_leases_.Drop(type);
|
|
MaybeUpdate();
|
|
}
|
|
|
|
void ThreadTypeManager::RaiseLeases::Acquire(ThreadType thread_type) {
|
|
// TODO(crbug.com/470337728): consider using base::EnumSet.
|
|
auto type = static_cast<uint32_t>(thread_type);
|
|
leases[type]++;
|
|
bitmask |= (1u << type);
|
|
}
|
|
|
|
void ThreadTypeManager::RaiseLeases::Drop(ThreadType thread_type) {
|
|
// TODO(crbug.com/470337728): consider using base::EnumSet.
|
|
auto type = static_cast<uint32_t>(thread_type);
|
|
leases[type]--;
|
|
if (leases[type] == 0) {
|
|
bitmask &= ~(1u << type);
|
|
}
|
|
}
|
|
|
|
std::optional<ThreadType> ThreadTypeManager::RaiseLeases::GetHighestLease()
|
|
const {
|
|
if (bitmask == 0) {
|
|
return std::nullopt;
|
|
}
|
|
return static_cast<ThreadType>(base::bits::Log2Floor(bitmask));
|
|
}
|
|
|
|
void ThreadTypeManager::SetCurrentThreadTypeImpl(
|
|
ThreadType thread_type,
|
|
MessagePumpType pump_type_hint) {
|
|
base::internal::SetCurrentThreadTypeImpl(thread_type, pump_type_hint);
|
|
}
|
|
|
|
bool ThreadTypeManager::HasLeases() const {
|
|
return raise_leases_.GetHighestLease().has_value();
|
|
}
|
|
} // namespace internal
|
|
} // namespace base
|