#include "base/task/sequence_manager/work_tracker.h"
#include "base/check.h"
#include "base/task/common/scoped_defer_task_posting.h"
#include "base/threading/thread_restrictions.h"
namespace base::sequence_manager::internal {
SyncWorkAuthorization::SyncWorkAuthorization(SyncWorkAuthorization&& other)
: tracker_(other.tracker_) {
other.tracker_ = nullptr;
}
SyncWorkAuthorization& SyncWorkAuthorization::operator=(
SyncWorkAuthorization&& other) {
tracker_ = other.tracker_;
other.tracker_ = nullptr;
return *this;
}
SyncWorkAuthorization::~SyncWorkAuthorization() {
if (!tracker_) {
return;
}
{
base::internal::CheckedAutoLock auto_lock(tracker_->active_sync_work_lock_);
uint32_t prev = tracker_->state_.fetch_and(
~WorkTracker::kActiveSyncWork, WorkTracker::kMemoryReleaseAllowWork);
DCHECK(prev & WorkTracker::kActiveSyncWork);
}
tracker_->active_sync_work_cv_.Signal();
}
SyncWorkAuthorization::SyncWorkAuthorization(WorkTracker* state)
: tracker_(state) {}
WorkTracker::WorkTracker() {
DETACH_FROM_THREAD(thread_checker_);
}
WorkTracker::~WorkTracker() = default;
void WorkTracker::SetRunTaskSynchronouslyAllowed(
bool can_run_tasks_synchronously) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (can_run_tasks_synchronously) {
state_.fetch_or(kSyncWorkSupported, kMemoryReleaseAllowWork);
} else {
uint32_t prev =
state_.fetch_and(~kSyncWorkSupported, kMemoryAcquireBeforeWork);
if (prev & kActiveSyncWork) {
WaitNoSyncWork();
}
}
}
void WorkTracker::WaitNoSyncWork() {
ScopedDeferTaskPosting disallow_task_posting;
ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow;
base::internal::CheckedAutoLock auto_lock(active_sync_work_lock_);
uint32_t prev = state_.load(std::memory_order_relaxed);
while (prev & kActiveSyncWork) {
active_sync_work_cv_.Wait();
prev = state_.load(std::memory_order_relaxed);
}
}
void WorkTracker::WillRequestReloadImmediateWorkQueue() {
state_.fetch_or(kImmediateWorkQueueNeedsReload,
kMemoryRelaxedNotAllowOrBeforeWork);
}
void WorkTracker::WillReloadImmediateWorkQueues() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
state_.fetch_and(
~(kImmediateWorkQueueNeedsReload | kWorkQueuesEmptyAndNoWorkRunning),
kMemoryRelaxedNotAllowOrBeforeWork);
}
void WorkTracker::OnBeginWork() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
uint32_t prev = state_.fetch_and(~kWorkQueuesEmptyAndNoWorkRunning,
kMemoryAcquireBeforeWork);
if (prev & kActiveSyncWork) {
DCHECK(prev & kSyncWorkSupported);
WaitNoSyncWork();
}
}
void WorkTracker::OnIdle() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
state_.fetch_or(kWorkQueuesEmptyAndNoWorkRunning, std::memory_order_release);
}
SyncWorkAuthorization WorkTracker::TryAcquireSyncWorkAuthorization() {
uint32_t state = state_.load(std::memory_order_relaxed);
if (state == (kSyncWorkSupported | kWorkQueuesEmptyAndNoWorkRunning) &&
state_.compare_exchange_strong(state, state | kActiveSyncWork,
std::memory_order_acquire,
std::memory_order_relaxed)) {
return SyncWorkAuthorization(this);
}
return SyncWorkAuthorization(nullptr);
}
void WorkTracker::AssertHasWork() {
CHECK(!(state_.load(std::memory_order_relaxed) &
kWorkQueuesEmptyAndNoWorkRunning));
}
}