|  | // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/message_loop/message_pump_default.h" | 
|  |  | 
|  | #include "base/auto_reset.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/threading/thread_restrictions.h" | 
|  | #include "build_config.h" | 
|  |  | 
|  | #if defined(OS_MACOSX) | 
|  | #include <mach/thread_policy.h> | 
|  |  | 
|  | #include "base/mac/mach_logging.h" | 
|  | #include "base/mac/scoped_mach_port.h" | 
|  | #include "base/mac/scoped_nsautorelease_pool.h" | 
|  | #endif | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | MessagePumpDefault::MessagePumpDefault() | 
|  | : keep_running_(true), | 
|  | event_(WaitableEvent::ResetPolicy::AUTOMATIC, | 
|  | WaitableEvent::InitialState::NOT_SIGNALED) {} | 
|  |  | 
|  | MessagePumpDefault::~MessagePumpDefault() = default; | 
|  |  | 
|  | void MessagePumpDefault::Run(Delegate* delegate) { | 
|  | AutoReset<bool> auto_reset_keep_running(&keep_running_, true); | 
|  |  | 
|  | for (;;) { | 
|  | #if defined(OS_MACOSX) | 
|  | mac::ScopedNSAutoreleasePool autorelease_pool; | 
|  | #endif | 
|  |  | 
|  | bool did_work = delegate->DoWork(); | 
|  | if (!keep_running_) | 
|  | break; | 
|  |  | 
|  | did_work |= delegate->DoDelayedWork(&delayed_work_time_); | 
|  | if (!keep_running_) | 
|  | break; | 
|  |  | 
|  | if (did_work) | 
|  | continue; | 
|  |  | 
|  | did_work = delegate->DoIdleWork(); | 
|  | if (!keep_running_) | 
|  | break; | 
|  |  | 
|  | if (did_work) | 
|  | continue; | 
|  |  | 
|  | ThreadRestrictions::ScopedAllowWait allow_wait; | 
|  | if (delayed_work_time_.is_null()) { | 
|  | event_.Wait(); | 
|  | } else { | 
|  | // No need to handle already expired |delayed_work_time_| in any special | 
|  | // way. When |delayed_work_time_| is in the past TimeWaitUntil returns | 
|  | // promptly and |delayed_work_time_| will re-initialized on a next | 
|  | // DoDelayedWork call which has to be called in order to get here again. | 
|  | event_.TimedWaitUntil(delayed_work_time_); | 
|  | } | 
|  | // Since event_ is auto-reset, we don't need to do anything special here | 
|  | // other than service each delegate method. | 
|  | } | 
|  | } | 
|  |  | 
|  | void MessagePumpDefault::Quit() { | 
|  | keep_running_ = false; | 
|  | } | 
|  |  | 
|  | void MessagePumpDefault::ScheduleWork() { | 
|  | // Since this can be called on any thread, we need to ensure that our Run | 
|  | // loop wakes up. | 
|  | event_.Signal(); | 
|  | } | 
|  |  | 
|  | void MessagePumpDefault::ScheduleDelayedWork( | 
|  | const TimeTicks& delayed_work_time) { | 
|  | // We know that we can't be blocked on Wait right now since this method can | 
|  | // only be called on the same thread as Run, so we only need to update our | 
|  | // record of how long to sleep when we do sleep. | 
|  | delayed_work_time_ = delayed_work_time; | 
|  | } | 
|  |  | 
|  | #if defined(OS_MACOSX) | 
|  | void MessagePumpDefault::SetTimerSlack(TimerSlack timer_slack) { | 
|  | thread_latency_qos_policy_data_t policy{}; | 
|  | policy.thread_latency_qos_tier = timer_slack == TIMER_SLACK_MAXIMUM | 
|  | ? LATENCY_QOS_TIER_3 | 
|  | : LATENCY_QOS_TIER_UNSPECIFIED; | 
|  | mac::ScopedMachSendRight thread_port(mach_thread_self()); | 
|  | thread_policy_set(thread_port.get(), THREAD_LATENCY_QOS_POLICY, | 
|  | reinterpret_cast<thread_policy_t>(&policy), | 
|  | THREAD_LATENCY_QOS_POLICY_COUNT); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | }  // namespace base |