diff options
34 files changed, 490 insertions, 405 deletions
diff --git a/base/base.gypi b/base/base.gypi index 19fdcb9..02abd4b 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -300,6 +300,8 @@ 'memory/singleton.h', 'memory/weak_ptr.cc', 'memory/weak_ptr.h', + 'message_loop/incoming_task_queue.cc', + 'message_loop/incoming_task_queue.h', 'message_loop/message_loop.cc', 'message_loop/message_loop.h', 'message_loop/message_loop_proxy.cc', diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc new file mode 100644 index 0000000..db99d87 --- /dev/null +++ b/base/message_loop/incoming_task_queue.cc @@ -0,0 +1,169 @@ +// Copyright 2013 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/incoming_task_queue.h" + +#include "base/debug/trace_event.h" +#include "base/location.h" +#include "base/message_loop/message_loop.h" +#include "base/synchronization/waitable_event.h" + +namespace base { +namespace internal { + +IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop) + : message_loop_(message_loop), + next_sequence_num_(0) { +} + +bool IncomingTaskQueue::AddToIncomingQueue( + const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay, + bool nestable) { + AutoLock locked(incoming_queue_lock_); + PendingTask pending_task( + from_here, task, CalculateDelayedRuntime(delay), nestable); + return PostPendingTask(&pending_task); +} + +bool IncomingTaskQueue::TryAddToIncomingQueue( + const tracked_objects::Location& from_here, + const Closure& task) { + if (!incoming_queue_lock_.Try()) { + // Reset |task|. + Closure local_task = task; + return false; + } + + AutoLock locked(incoming_queue_lock_, AutoLock::AlreadyAcquired()); + PendingTask pending_task( + from_here, task, CalculateDelayedRuntime(TimeDelta()), true); + return PostPendingTask(&pending_task); +} + +bool IncomingTaskQueue::IsHighResolutionTimerEnabledForTesting() { +#if defined(OS_WIN) + return !high_resolution_timer_expiration_.is_null(); +#else + return true; +#endif +} + +bool IncomingTaskQueue::IsIdleForTesting() { + AutoLock lock(incoming_queue_lock_); + return incoming_queue_.empty(); +} + +void IncomingTaskQueue::LockWaitUnLockForTesting(WaitableEvent* caller_wait, + WaitableEvent* caller_signal) { + AutoLock lock(incoming_queue_lock_); + caller_wait->Signal(); + caller_signal->Wait(); +} + +void IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) { + // Make sure no tasks are lost. + DCHECK(work_queue->empty()); + + // Acquire all we can from the inter-thread queue with one lock acquisition. + AutoLock lock(incoming_queue_lock_); + if (!incoming_queue_.empty()) + incoming_queue_.Swap(work_queue); // Constant time + + DCHECK(incoming_queue_.empty()); +} + +void IncomingTaskQueue::WillDestroyCurrentMessageLoop() { +#if defined(OS_WIN) + // If we left the high-resolution timer activated, deactivate it now. + // Doing this is not-critical, it is mainly to make sure we track + // the high resolution timer activations properly in our unit tests. + if (!high_resolution_timer_expiration_.is_null()) { + Time::ActivateHighResolutionTimer(false); + high_resolution_timer_expiration_ = TimeTicks(); + } +#endif + + AutoLock lock(incoming_queue_lock_); + message_loop_ = NULL; +} + +IncomingTaskQueue::~IncomingTaskQueue() { + // Verify that WillDestroyCurrentMessageLoop() has been called. + DCHECK(!message_loop_); +} + +TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) { + TimeTicks delayed_run_time; + if (delay > TimeDelta()) { + delayed_run_time = TimeTicks::Now() + delay; + +#if defined(OS_WIN) + if (high_resolution_timer_expiration_.is_null()) { + // Windows timers are granular to 15.6ms. If we only set high-res + // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms, + // which as a percentage is pretty inaccurate. So enable high + // res timers for any timer which is within 2x of the granularity. + // This is a tradeoff between accuracy and power management. + bool needs_high_res_timers = delay.InMilliseconds() < + (2 * Time::kMinLowResolutionThresholdMs); + if (needs_high_res_timers) { + if (Time::ActivateHighResolutionTimer(true)) { + high_resolution_timer_expiration_ = TimeTicks::Now() + + TimeDelta::FromMilliseconds( + MessageLoop::kHighResolutionTimerModeLeaseTimeMs); + } + } + } +#endif + } else { + DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; + } + +#if defined(OS_WIN) + if (!high_resolution_timer_expiration_.is_null()) { + if (TimeTicks::Now() > high_resolution_timer_expiration_) { + Time::ActivateHighResolutionTimer(false); + high_resolution_timer_expiration_ = TimeTicks(); + } + } +#endif + + return delayed_run_time; +} + +bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) { + // Warning: Don't try to short-circuit, and handle this thread's tasks more + // directly, as it could starve handling of foreign threads. Put every task + // into this queue. + + // This should only be called while the lock is taken. + incoming_queue_lock_.AssertAcquired(); + + if (!message_loop_) { + pending_task->task.Reset(); + return false; + } + + // Initialize the sequence number. The sequence number is used for delayed + // tasks (to faciliate FIFO sorting when two tasks have the same + // delayed_run_time value) and for identifying the task in about:tracing. + pending_task->sequence_num = next_sequence_num_++; + + TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask", + TRACE_ID_MANGLE(message_loop_->GetTaskTraceID(*pending_task))); + + bool was_empty = incoming_queue_.empty(); + incoming_queue_.push(*pending_task); + pending_task->task.Reset(); + + // Wake up the pump. + message_loop_->ScheduleWork(was_empty); + + return true; +} + +} // namespace internal +} // namespace base diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h new file mode 100644 index 0000000..d831a71 --- /dev/null +++ b/base/message_loop/incoming_task_queue.h @@ -0,0 +1,104 @@ +// Copyright 2013 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. + +#ifndef BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_ +#define BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_ + +#include "base/base_export.h" +#include "base/memory/ref_counted.h" +#include "base/pending_task.h" +#include "base/synchronization/lock.h" +#include "base/time/time.h" + +namespace base { + +class MessageLoop; +class WaitableEvent; + +namespace internal { + +// Implements a queue of tasks posted to the message loop running on the current +// thread. This class takes care of synchronizing posting tasks from different +// threads and together with MessageLoop ensures clean shutdown. +class BASE_EXPORT IncomingTaskQueue + : public RefCountedThreadSafe<IncomingTaskQueue> { + public: + explicit IncomingTaskQueue(MessageLoop* message_loop); + + // Appends a task to the incoming queue. Posting of all tasks is routed though + // AddToIncomingQueue() or TryAddToIncomingQueue() to make sure that posting + // task is properly synchronized between different threads. + // + // Returns true if the task was successfully added to the queue, otherwise + // returns false. In all cases, the ownership of |task| is transferred to the + // called method. + bool AddToIncomingQueue(const tracked_objects::Location& from_here, + const Closure& task, + TimeDelta delay, + bool nestable); + + // Same as AddToIncomingQueue() except that it will avoid blocking if the lock + // is already held, and will in that case (when the lock is contended) fail to + // add the task, and will return false. + bool TryAddToIncomingQueue(const tracked_objects::Location& from_here, + const Closure& task); + + // Returns true if the message loop has high resolution timers enabled. + // Provided for testing. + bool IsHighResolutionTimerEnabledForTesting(); + + // Returns true if the message loop is "idle". Provided for testing. + bool IsIdleForTesting(); + + // Takes the incoming queue lock, signals |caller_wait| and waits until + // |caller_signal| is signalled. + void LockWaitUnLockForTesting(WaitableEvent* caller_wait, + WaitableEvent* caller_signal); + + // Loads tasks from the |incoming_queue_| into |*work_queue|. Must be called + // from the thread that is running the loop. + void ReloadWorkQueue(TaskQueue* work_queue); + + // Disconnects |this| from the parent message loop. + void WillDestroyCurrentMessageLoop(); + + private: + friend class RefCountedThreadSafe<IncomingTaskQueue>; + virtual ~IncomingTaskQueue(); + + // Calculates the time at which a PendingTask should run. + TimeTicks CalculateDelayedRuntime(TimeDelta delay); + + // Adds a task to |incoming_queue_|. The caller retains ownership of + // |pending_task|, but this function will reset the value of + // |pending_task->task|. This is needed to ensure that the posting call stack + // does not retain |pending_task->task| beyond this function call. + bool PostPendingTask(PendingTask* pending_task); + +#if defined(OS_WIN) + TimeTicks high_resolution_timer_expiration_; +#endif + + // The lock that protects access to |incoming_queue_|, |message_loop_| and + // |next_sequence_num_|. + base::Lock incoming_queue_lock_; + + // An incoming queue of tasks that are acquired under a mutex for processing + // on this instance's thread. These tasks have not yet been been pushed to + // |message_loop_|. + TaskQueue incoming_queue_; + + // Points to the message loop that owns |this|. + MessageLoop* message_loop_; + + // The next sequence number to use for delayed tasks. + int next_sequence_num_; + + DISALLOW_COPY_AND_ASSIGN(IncomingTaskQueue); +}; + +} // namespace internal +} // namespace base + +#endif // BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_ diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc index bd3542a..d2eafbd8 100644 --- a/base/message_loop/message_loop.cc +++ b/base/message_loop/message_loop.cc @@ -13,7 +13,6 @@ #include "base/lazy_instance.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop_proxy_impl.h" #include "base/message_loop/message_pump_default.h" #include "base/metrics/histogram.h" #include "base/metrics/statistics_recorder.h" @@ -89,14 +88,6 @@ bool enable_histogrammer_ = false; MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; -// Create a process-wide unique ID to represent this task in trace events. This -// will be mangled with a Process ID hash to reduce the likelyhood of colliding -// with MessageLoop pointers on other processes. -uint64 GetTaskTraceID(const PendingTask& task, MessageLoop* loop) { - return (static_cast<uint64>(task.sequence_num) << 32) | - static_cast<uint64>(reinterpret_cast<intptr_t>(loop)); -} - // Returns true if MessagePump::ScheduleWork() must be called one // time for every task that is added to the MessageLoop incoming queue. bool AlwaysNotifyPump(MessageLoop::Type type) { @@ -146,18 +137,19 @@ MessageLoop::DestructionObserver::~DestructionObserver() { MessageLoop::MessageLoop(Type type) : type_(type), - nestable_tasks_allowed_(true), exception_restoration_(false), - message_histogram_(NULL), - run_loop_(NULL), + nestable_tasks_allowed_(true), #if defined(OS_WIN) os_modal_loop_(false), #endif // OS_WIN - next_sequence_num_(0) { + message_histogram_(NULL), + run_loop_(NULL) { DCHECK(!current()) << "should only have one message loop per thread"; lazy_tls_ptr.Pointer()->Set(this); - message_loop_proxy_ = new MessageLoopProxyImpl(); + incoming_task_queue_ = new internal::IncomingTaskQueue(this); + message_loop_proxy_ = + new internal::MessageLoopProxyImpl(incoming_task_queue_); thread_task_runner_handle_.reset( new ThreadTaskRunnerHandle(message_loop_proxy_)); @@ -177,7 +169,7 @@ MessageLoop::MessageLoop(Type type) #define MESSAGE_PUMP_UI NULL // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and // doesn't require extra support for watching file descriptors. -#define MESSAGE_PUMP_IO new MessagePumpDefault(); +#define MESSAGE_PUMP_IO new MessagePumpDefault() #elif defined(OS_POSIX) // POSIX but not MACOSX. #define MESSAGE_PUMP_UI new MessagePumpForUI() #define MESSAGE_PUMP_IO new MessagePumpLibevent() @@ -187,14 +179,14 @@ MessageLoop::MessageLoop(Type type) if (type_ == TYPE_UI) { if (message_pump_for_ui_factory_) - pump_ = message_pump_for_ui_factory_(); + pump_.reset(message_pump_for_ui_factory_()); else - pump_ = MESSAGE_PUMP_UI; + pump_.reset(MESSAGE_PUMP_UI); } else if (type_ == TYPE_IO) { - pump_ = MESSAGE_PUMP_IO; + pump_.reset(MESSAGE_PUMP_IO); } else { DCHECK_EQ(TYPE_DEFAULT, type_); - pump_ = new MessagePumpDefault(); + pump_.reset(new MessagePumpDefault()); } } @@ -226,23 +218,13 @@ MessageLoop::~MessageLoop() { thread_task_runner_handle_.reset(); - // Tell the message_loop_proxy that we are dying. - static_cast<MessageLoopProxyImpl*>(message_loop_proxy_.get())-> - WillDestroyCurrentMessageLoop(); + // Tell the incoming queue that we are dying. + incoming_task_queue_->WillDestroyCurrentMessageLoop(); + incoming_task_queue_ = NULL; message_loop_proxy_ = NULL; // OK, now make it so that no one can find us. lazy_tls_ptr.Pointer()->Set(NULL); - -#if defined(OS_WIN) - // If we left the high-resolution timer activated, deactivate it now. - // Doing this is not-critical, it is mainly to make sure we track - // the high resolution timer activations properly in our unit tests. - if (!high_resolution_timer_expiration_.is_null()) { - Time::ActivateHighResolutionTimer(false); - high_resolution_timer_expiration_ = TimeTicks(); - } -#endif } // static @@ -283,18 +265,14 @@ void MessageLoop::PostTask( const tracked_objects::Location& from_here, const Closure& task) { DCHECK(!task.is_null()) << from_here.ToString(); - PendingTask pending_task( - from_here, task, CalculateDelayedRuntime(TimeDelta()), true); - AddToIncomingQueue(&pending_task, false); + incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), true); } bool MessageLoop::TryPostTask( const tracked_objects::Location& from_here, const Closure& task) { DCHECK(!task.is_null()) << from_here.ToString(); - PendingTask pending_task( - from_here, task, CalculateDelayedRuntime(TimeDelta()), true); - return AddToIncomingQueue(&pending_task, true); + return incoming_task_queue_->TryAddToIncomingQueue(from_here, task); } void MessageLoop::PostDelayedTask( @@ -302,18 +280,14 @@ void MessageLoop::PostDelayedTask( const Closure& task, TimeDelta delay) { DCHECK(!task.is_null()) << from_here.ToString(); - PendingTask pending_task( - from_here, task, CalculateDelayedRuntime(delay), true); - AddToIncomingQueue(&pending_task, false); + incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true); } void MessageLoop::PostNonNestableTask( const tracked_objects::Location& from_here, const Closure& task) { DCHECK(!task.is_null()) << from_here.ToString(); - PendingTask pending_task( - from_here, task, CalculateDelayedRuntime(TimeDelta()), false); - AddToIncomingQueue(&pending_task, false); + incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), false); } void MessageLoop::PostNonNestableDelayedTask( @@ -321,9 +295,7 @@ void MessageLoop::PostNonNestableDelayedTask( const Closure& task, TimeDelta delay) { DCHECK(!task.is_null()) << from_here.ToString(); - PendingTask pending_task( - from_here, task, CalculateDelayedRuntime(delay), false); - AddToIncomingQueue(&pending_task, false); + incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false); } void MessageLoop::Run() { @@ -395,17 +367,26 @@ void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { task_observers_.RemoveObserver(task_observer); } -void MessageLoop::AssertIdle() const { - // We only check |incoming_queue_|, since we don't want to lock |work_queue_|. - AutoLock lock(incoming_queue_lock_); - DCHECK(incoming_queue_.empty()); -} - bool MessageLoop::is_running() const { DCHECK_EQ(this, current()); return run_loop_ != NULL; } +bool MessageLoop::IsHighResolutionTimerEnabledForTesting() { + return incoming_task_queue_->IsHighResolutionTimerEnabledForTesting(); +} + +bool MessageLoop::IsIdleForTesting() { + // We only check the imcoming queue|, since we don't want to lock the work + // queue. + return incoming_task_queue_->IsIdleForTesting(); +} + +void MessageLoop::LockWaitUnLockForTesting(WaitableEvent* caller_wait, + WaitableEvent* caller_signal) { + incoming_task_queue_->LockWaitUnLockForTesting(caller_wait, caller_signal); +} + //------------------------------------------------------------------------------ // Runs the loop in two different SEH modes: @@ -470,7 +451,7 @@ void MessageLoop::RunTask(const PendingTask& pending_task) { tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally); TRACE_EVENT_FLOW_END1("task", "MessageLoop::PostTask", - TRACE_ID_MANGLE(GetTaskTraceID(pending_task, this)), + TRACE_ID_MANGLE(GetTaskTraceID(pending_task)), "queue_duration", (start_time - pending_task.EffectiveTimePosted()).InMilliseconds()); TRACE_EVENT2("task", "MessageLoop::RunTask", @@ -523,24 +504,6 @@ void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { delayed_work_queue_.push(pending_task); } -void MessageLoop::ReloadWorkQueue() { - // We can improve performance of our loading tasks from incoming_queue_ to - // work_queue_ by waiting until the last minute (work_queue_ is empty) to - // load. That reduces the number of locks-per-task significantly when our - // queues get large. - if (!work_queue_.empty()) - return; // Wait till we *really* need to lock and load. - - // Acquire all we can from the inter-thread queue with one lock acquisition. - { - AutoLock lock(incoming_queue_lock_); - if (incoming_queue_.empty()) - return; - incoming_queue_.Swap(&work_queue_); // Constant time - DCHECK(incoming_queue_.empty()); - } -} - bool MessageLoop::DeletePendingTasks() { bool did_work = !work_queue_.empty(); while (!work_queue_.empty()) { @@ -570,87 +533,25 @@ bool MessageLoop::DeletePendingTasks() { return did_work; } -TimeTicks MessageLoop::CalculateDelayedRuntime(TimeDelta delay) { - TimeTicks delayed_run_time; - if (delay > TimeDelta()) { - delayed_run_time = TimeTicks::Now() + delay; - -#if defined(OS_WIN) - if (high_resolution_timer_expiration_.is_null()) { - // Windows timers are granular to 15.6ms. If we only set high-res - // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms, - // which as a percentage is pretty inaccurate. So enable high - // res timers for any timer which is within 2x of the granularity. - // This is a tradeoff between accuracy and power management. - bool needs_high_res_timers = delay.InMilliseconds() < - (2 * Time::kMinLowResolutionThresholdMs); - if (needs_high_res_timers) { - if (Time::ActivateHighResolutionTimer(true)) { - high_resolution_timer_expiration_ = TimeTicks::Now() + - TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs); - } - } - } -#endif - } else { - DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; - } - -#if defined(OS_WIN) - if (!high_resolution_timer_expiration_.is_null()) { - if (TimeTicks::Now() > high_resolution_timer_expiration_) { - Time::ActivateHighResolutionTimer(false); - high_resolution_timer_expiration_ = TimeTicks(); - } - } -#endif - - return delayed_run_time; +uint64 MessageLoop::GetTaskTraceID(const PendingTask& task) { + return (static_cast<uint64>(task.sequence_num) << 32) | + static_cast<uint64>(reinterpret_cast<intptr_t>(this)); } -// Possibly called on a background thread! -bool MessageLoop::AddToIncomingQueue(PendingTask* pending_task, - bool use_try_lock) { - // Warning: Don't try to short-circuit, and handle this thread's tasks more - // directly, as it could starve handling of foreign threads. Put every task - // into this queue. - - scoped_refptr<MessagePump> pump; - { - if (use_try_lock) { - if (!incoming_queue_lock_.Try()) { - pending_task->task.Reset(); - return false; - } - } else { - incoming_queue_lock_.Acquire(); - } - AutoLock locked(incoming_queue_lock_, AutoLock::AlreadyAcquired()); - // Initialize the sequence number. The sequence number is used for delayed - // tasks (to faciliate FIFO sorting when two tasks have the same - // delayed_run_time value) and for identifying the task in about:tracing. - pending_task->sequence_num = next_sequence_num_++; - - TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask", - TRACE_ID_MANGLE(GetTaskTraceID(*pending_task, this))); - - bool was_empty = incoming_queue_.empty(); - incoming_queue_.push(*pending_task); - pending_task->task.Reset(); - // The Android UI message loop needs to get notified each time - // a task is added to the incoming queue. - if (!was_empty && !AlwaysNotifyPump(type_)) - return true; // Someone else should have started the sub-pump. - - pump = pump_; - } - // Since the incoming_queue_ may contain a task that destroys this message - // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. - // We use a stack-based reference to the message pump so that we can call - // ScheduleWork outside of incoming_queue_lock_. +void MessageLoop::ReloadWorkQueue() { + // We can improve performance of our loading tasks from the incoming queue to + // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to + // load. That reduces the number of locks-per-task significantly when our + // queues get large. + if (work_queue_.empty()) + incoming_task_queue_->ReloadWorkQueue(&work_queue_); +} - pump->ScheduleWork(); - return true; +void MessageLoop::ScheduleWork(bool was_empty) { + // The Android UI message loop needs to get notified each time + // a task is added to the incoming queue. + if (was_empty || AlwaysNotifyPump(type_)) + pump_->ScheduleWork(); } //------------------------------------------------------------------------------ diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h index 846cc8d..6f71a85 100644 --- a/base/message_loop/message_loop.h +++ b/base/message_loop/message_loop.h @@ -13,7 +13,10 @@ #include "base/callback_forward.h" #include "base/location.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/incoming_task_queue.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/message_loop/message_loop_proxy_impl.h" #include "base/message_loop/message_pump.h" #include "base/observer_list.h" #include "base/pending_task.h" @@ -46,12 +49,12 @@ namespace base { class HistogramBase; -class MessageLoopLockTest; class RunLoop; class ThreadTaskRunnerHandle; #if defined(OS_ANDROID) class MessagePumpForUI; #endif +class WaitableEvent; // A MessageLoop is used to process events for a particular thread. There is // at most one MessageLoop instance per thread. @@ -283,7 +286,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { // Gets the message loop proxy associated with this message loop. scoped_refptr<MessageLoopProxy> message_loop_proxy() { - return message_loop_proxy_.get(); + return message_loop_proxy_; } // Enables or disables the recursive task processing. This happens in the case @@ -359,23 +362,10 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { void AddTaskObserver(TaskObserver* task_observer); void RemoveTaskObserver(TaskObserver* task_observer); - // Returns true if the message loop has high resolution timers enabled. - // Provided for testing. - bool high_resolution_timers_enabled() { -#if defined(OS_WIN) - return !high_resolution_timer_expiration_.is_null(); -#else - return true; -#endif - } - // When we go into high resolution timer mode, we will stay in hi-res mode // for at least 1s. static const int kHighResolutionTimerModeLeaseTimeMs = 1000; - // Asserts that the MessageLoop is "idle". - void AssertIdle() const; - #if defined(OS_WIN) void set_os_modal_loop(bool os_modal_loop) { os_modal_loop_ = os_modal_loop; @@ -389,6 +379,18 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { // Can only be called from the thread that owns the MessageLoop. bool is_running() const; + // Returns true if the message loop has high resolution timers enabled. + // Provided for testing. + bool IsHighResolutionTimerEnabledForTesting(); + + // Returns true if the message loop is "idle". Provided for testing. + bool IsIdleForTesting(); + + // Takes the incoming queue lock, signals |caller_wait| and waits until + // |caller_signal| is signalled. + void LockWaitUnLockForTesting(WaitableEvent* caller_wait, + WaitableEvent* caller_signal); + //---------------------------------------------------------------------------- protected: @@ -402,11 +404,11 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { } #endif - scoped_refptr<MessagePump> pump_; + scoped_ptr<MessagePump> pump_; private: + friend class internal::IncomingTaskQueue; friend class RunLoop; - friend class MessageLoopLockTest; // A function to encapsulate all the exception handling capability in the // stacks around the running of a main message loop. It will run the message @@ -436,34 +438,23 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { // Adds the pending task to delayed_work_queue_. void AddToDelayedWorkQueue(const PendingTask& pending_task); - // This function attempts to add pending task to our incoming_queue_. - // The append can only possibly fail when |use_try_lock| is true. - // - // When |use_try_lock| is true, then this call will avoid blocking if - // the related lock is already held, and will in that case (when the - // lock is contended) fail to perform the append, and will return false. - // - // If the call succeeds to append to the queue, then this call - // will return true. - // - // In all cases, the caller retains ownership of |pending_task|, but this - // function will reset the value of pending_task->task. This is needed to - // ensure that the posting call stack does not retain pending_task->task - // beyond this function call. - bool AddToIncomingQueue(PendingTask* pending_task, bool use_try_lock); - - // Load tasks from the incoming_queue_ into work_queue_ if the latter is - // empty. The former requires a lock to access, while the latter is directly - // accessible on this thread. - void ReloadWorkQueue(); - // Delete tasks that haven't run yet without running them. Used in the // destructor to make sure all the task's destructors get called. Returns // true if some work was done. bool DeletePendingTasks(); - // Calculates the time at which a PendingTask should run. - TimeTicks CalculateDelayedRuntime(TimeDelta delay); + // Creates a process-wide unique ID to represent this task in trace events. + // This will be mangled with a Process ID hash to reduce the likelyhood of + // colliding with MessageLoop pointers on other processes. + uint64 GetTaskTraceID(const PendingTask& task); + + // Loads tasks from the incoming queue to |work_queue_| if the latter is + // empty. + void ReloadWorkQueue(); + + // Wakes up the message pump. Can be called on any thread. The caller is + // responsible for synchronizing ScheduleWork() calls. + void ScheduleWork(bool was_empty); // Start recording histogram info about events and action IF it was enabled // and IF the statistics recorder can accept a registration of our histogram. @@ -498,40 +489,30 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { ObserverList<DestructionObserver> destruction_observers_; + bool exception_restoration_; + // A recursion block that prevents accidentally running additional tasks when // insider a (accidentally induced?) nested message pump. bool nestable_tasks_allowed_; - bool exception_restoration_; - - std::string thread_name_; - // A profiling histogram showing the counts of various messages and events. - HistogramBase* message_histogram_; - - // An incoming queue of tasks that are acquired under a mutex for processing - // on this instance's thread. These tasks have not yet been sorted out into - // items for our work_queue_ vs delayed_work_queue_. - TaskQueue incoming_queue_; - // Protect access to incoming_queue_. - mutable Lock incoming_queue_lock_; - - RunLoop* run_loop_; - #if defined(OS_WIN) - TimeTicks high_resolution_timer_expiration_; // Should be set to true before calling Windows APIs like TrackPopupMenu, etc // which enter a modal message loop. bool os_modal_loop_; #endif - // The next sequence number to use for delayed tasks. Updating this counter is - // protected by incoming_queue_lock_. - int next_sequence_num_; + std::string thread_name_; + // A profiling histogram showing the counts of various messages and events. + HistogramBase* message_histogram_; + + RunLoop* run_loop_; ObserverList<TaskObserver> task_observers_; - // The message loop proxy associated with this message loop, if one exists. - scoped_refptr<MessageLoopProxy> message_loop_proxy_; + scoped_refptr<internal::IncomingTaskQueue> incoming_task_queue_; + + // The message loop proxy associated with this message loop. + scoped_refptr<internal::MessageLoopProxyImpl> message_loop_proxy_; scoped_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_; template <class T, class R> friend class base::subtle::DeleteHelperInternal; diff --git a/base/message_loop/message_loop_proxy_impl.cc b/base/message_loop/message_loop_proxy_impl.cc index 7dc8caa..b7abca3 100644 --- a/base/message_loop/message_loop_proxy_impl.cc +++ b/base/message_loop/message_loop_proxy_impl.cc @@ -5,81 +5,43 @@ #include "base/message_loop/message_loop_proxy_impl.h" #include "base/location.h" -#include "base/threading/thread_restrictions.h" +#include "base/logging.h" +#include "base/message_loop/incoming_task_queue.h" +#include "base/message_loop/message_loop.h" namespace base { +namespace internal { -MessageLoopProxyImpl::~MessageLoopProxyImpl() { +MessageLoopProxyImpl::MessageLoopProxyImpl( + scoped_refptr<IncomingTaskQueue> incoming_queue) + : incoming_queue_(incoming_queue), + valid_thread_id_(PlatformThread::CurrentId()) { } bool MessageLoopProxyImpl::PostDelayedTask( const tracked_objects::Location& from_here, const base::Closure& task, base::TimeDelta delay) { - return PostTaskHelper(from_here, task, delay, true); + DCHECK(!task.is_null()) << from_here.ToString(); + return incoming_queue_->AddToIncomingQueue(from_here, task, delay, true); } bool MessageLoopProxyImpl::PostNonNestableDelayedTask( const tracked_objects::Location& from_here, const base::Closure& task, base::TimeDelta delay) { - return PostTaskHelper(from_here, task, delay, false); + DCHECK(!task.is_null()) << from_here.ToString(); + return incoming_queue_->AddToIncomingQueue(from_here, task, delay, false); } bool MessageLoopProxyImpl::RunsTasksOnCurrentThread() const { - // We shouldn't use MessageLoop::current() since it uses LazyInstance which - // may be deleted by ~AtExitManager when a WorkerPool thread calls this - // function. - // http://crbug.com/63678 - base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; - AutoLock lock(message_loop_lock_); - return (target_message_loop_ && - (MessageLoop::current() == target_message_loop_)); -} - -// MessageLoop::DestructionObserver implementation -void MessageLoopProxyImpl::WillDestroyCurrentMessageLoop() { - AutoLock lock(message_loop_lock_); - target_message_loop_ = NULL; + return valid_thread_id_ == PlatformThread::CurrentId(); } -void MessageLoopProxyImpl::OnDestruct() const { - // We shouldn't use MessageLoop::current() since it uses LazyInstance which - // may be deleted by ~AtExitManager when a WorkerPool thread calls this - // function. - // http://crbug.com/63678 - base::ThreadRestrictions::ScopedAllowSingleton allow_singleton; - bool delete_later = false; - { - AutoLock lock(message_loop_lock_); - if (target_message_loop_ && - (MessageLoop::current() != target_message_loop_)) { - target_message_loop_->DeleteSoon(FROM_HERE, this); - delete_later = true; - } - } - if (!delete_later) - delete this; -} - -MessageLoopProxyImpl::MessageLoopProxyImpl() - : target_message_loop_(MessageLoop::current()) { +MessageLoopProxyImpl::~MessageLoopProxyImpl() { } -bool MessageLoopProxyImpl::PostTaskHelper( - const tracked_objects::Location& from_here, const base::Closure& task, - base::TimeDelta delay, bool nestable) { - AutoLock lock(message_loop_lock_); - if (target_message_loop_) { - if (nestable) { - target_message_loop_->PostDelayedTask(from_here, task, delay); - } else { - target_message_loop_->PostNonNestableDelayedTask(from_here, task, delay); - } - return true; - } - return false; -} +} // namespace internal scoped_refptr<MessageLoopProxy> MessageLoopProxy::current() { diff --git a/base/message_loop/message_loop_proxy_impl.h b/base/message_loop/message_loop_proxy_impl.h index 6d6f0f6..b7f62b9 100644 --- a/base/message_loop/message_loop_proxy_impl.h +++ b/base/message_loop/message_loop_proxy_impl.h @@ -6,17 +6,24 @@ #define BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_ #include "base/base_export.h" -#include "base/message_loop/message_loop.h" +#include "base/memory/ref_counted.h" #include "base/message_loop/message_loop_proxy.h" -#include "base/synchronization/lock.h" +#include "base/pending_task.h" +#include "base/threading/platform_thread.h" namespace base { +namespace internal { + +class IncomingTaskQueue; // A stock implementation of MessageLoopProxy that is created and managed by a // MessageLoop. For now a MessageLoopProxyImpl can only be created as part of a // MessageLoop. class BASE_EXPORT MessageLoopProxyImpl : public MessageLoopProxy { public: + explicit MessageLoopProxyImpl( + scoped_refptr<IncomingTaskQueue> incoming_queue); + // MessageLoopProxy implementation virtual bool PostDelayedTask(const tracked_objects::Location& from_here, const base::Closure& task, @@ -27,36 +34,20 @@ class BASE_EXPORT MessageLoopProxyImpl : public MessageLoopProxy { base::TimeDelta delay) OVERRIDE; virtual bool RunsTasksOnCurrentThread() const OVERRIDE; - protected: - virtual ~MessageLoopProxyImpl(); - - // Override OnDestruct so that we can delete the object on the target message - // loop if it still exists. - virtual void OnDestruct() const OVERRIDE; - private: - // Allow the MessageLoop to create a MessageLoopProxyImpl. - friend class MessageLoop; - friend class DeleteHelper<MessageLoopProxyImpl>; - - MessageLoopProxyImpl(); - - // Called directly by MessageLoop::~MessageLoop. - virtual void WillDestroyCurrentMessageLoop(); - + friend class RefCountedThreadSafe<MessageLoopProxyImpl>; + virtual ~MessageLoopProxyImpl(); - bool PostTaskHelper(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay, - bool nestable); + // THe incoming queue receiving all posted tasks. + scoped_refptr<IncomingTaskQueue> incoming_queue_; - // The lock that protects access to target_message_loop_. - mutable base::Lock message_loop_lock_; - MessageLoop* target_message_loop_; + // ID of the thread |this| was created on. + PlatformThreadId valid_thread_id_; DISALLOW_COPY_AND_ASSIGN(MessageLoopProxyImpl); }; +} // namespace internal } // namespace base #endif // BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_ diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc index 504c8e3..ab05b3c 100644 --- a/base/message_loop/message_loop_unittest.cc +++ b/base/message_loop/message_loop_unittest.cc @@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_proxy_impl.h" #include "base/pending_task.h" #include "base/posix/eintr_wrapper.h" #include "base/run_loop.h" @@ -26,19 +27,6 @@ namespace base { -class MessageLoopLockTest { - public: - static void LockWaitUnLock(MessageLoop* loop, - WaitableEvent* caller_wait, - WaitableEvent* caller_signal) { - - loop->incoming_queue_lock_.Acquire(); - caller_wait->Signal(); - caller_signal->Wait(); - loop->incoming_queue_lock_.Release(); - } -}; - // TODO(darin): Platform-specific MessageLoop tests should be grouped together // to avoid chopping this file up with so many #ifdefs. @@ -121,10 +109,10 @@ void RunTest_PostTask(MessageLoop::Type message_loop_type) { thread.Start(); thread.message_loop()->PostTask( FROM_HERE, - Bind(&MessageLoopLockTest::LockWaitUnLock, - MessageLoop::current(), - &wait, - &signal)); + Bind(&MessageLoop::LockWaitUnLockForTesting, + base::Unretained(MessageLoop::current()), + &wait, + &signal)); wait.Wait(); EXPECT_FALSE(MessageLoop::current()->TryPostTask(FROM_HERE, Bind( @@ -1895,20 +1883,20 @@ TEST(MessageLoopTest, HighResolutionTimer) { const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5); const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100); - EXPECT_FALSE(loop.high_resolution_timers_enabled()); + EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting()); // Post a fast task to enable the high resolution timers. loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), kFastTimer); loop.Run(); - EXPECT_TRUE(loop.high_resolution_timers_enabled()); + EXPECT_TRUE(loop.IsHighResolutionTimerEnabledForTesting()); // Post a slow task and verify high resolution timers // are still enabled. loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), kSlowTimer); loop.Run(); - EXPECT_TRUE(loop.high_resolution_timers_enabled()); + EXPECT_TRUE(loop.IsHighResolutionTimerEnabledForTesting()); // Wait for a while so that high-resolution mode elapses. PlatformThread::Sleep(TimeDelta::FromMilliseconds( @@ -1918,7 +1906,7 @@ TEST(MessageLoopTest, HighResolutionTimer) { loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), kSlowTimer); loop.Run(); - EXPECT_FALSE(loop.high_resolution_timers_enabled()); + EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting()); } #endif // defined(OS_WIN) diff --git a/base/message_loop/message_pump.h b/base/message_loop/message_pump.h index 5b72232..0ebba3a 100644 --- a/base/message_loop/message_pump.h +++ b/base/message_loop/message_pump.h @@ -6,13 +6,13 @@ #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_ #include "base/base_export.h" -#include "base/memory/ref_counted.h" +#include "base/threading/non_thread_safe.h" namespace base { class TimeTicks; -class BASE_EXPORT MessagePump : public RefCountedThreadSafe<MessagePump> { +class BASE_EXPORT MessagePump : public NonThreadSafe { public: // Please see the comments above the Run method for an illustration of how // these delegate methods are used. @@ -42,6 +42,7 @@ class BASE_EXPORT MessagePump : public RefCountedThreadSafe<MessagePump> { }; MessagePump(); + virtual ~MessagePump(); // The Run method is called to enter the message pump's run loop. // @@ -118,10 +119,6 @@ class BASE_EXPORT MessagePump : public RefCountedThreadSafe<MessagePump> { // cancelling any pending DoDelayedWork callback. This method may only be // used on the thread that called Run. virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0; - - protected: - virtual ~MessagePump(); - friend class RefCountedThreadSafe<MessagePump>; }; } // namespace base diff --git a/base/message_loop/message_pump_android.h b/base/message_loop/message_pump_android.h index f3a8ded..8a07a0f 100644 --- a/base/message_loop/message_pump_android.h +++ b/base/message_loop/message_pump_android.h @@ -22,6 +22,7 @@ class TimeTicks; class BASE_EXPORT MessagePumpForUI : public MessagePump { public: MessagePumpForUI(); + virtual ~MessagePumpForUI(); virtual void Run(Delegate* delegate) OVERRIDE; virtual void Quit() OVERRIDE; @@ -32,9 +33,6 @@ class BASE_EXPORT MessagePumpForUI : public MessagePump { static bool RegisterBindings(JNIEnv* env); - protected: - virtual ~MessagePumpForUI(); - private: RunLoop* run_loop_; base::android::ScopedJavaGlobalRef<jobject> system_message_handler_obj_; diff --git a/base/message_loop/message_pump_aurax11.cc b/base/message_loop/message_pump_aurax11.cc index 7f60628..1f91a0e 100644 --- a/base/message_loop/message_pump_aurax11.cc +++ b/base/message_loop/message_pump_aurax11.cc @@ -139,6 +139,13 @@ MessagePumpAuraX11::MessagePumpAuraX11() : MessagePumpGlib(), x_root_window_ = DefaultRootWindow(g_xdisplay); } +MessagePumpAuraX11::~MessagePumpAuraX11() { + g_source_destroy(x_source_); + g_source_unref(x_source_); + XCloseDisplay(g_xdisplay); + g_xdisplay = NULL; +} + // static Display* MessagePumpAuraX11::GetDefaultXDisplay() { if (!g_xdisplay) @@ -211,13 +218,6 @@ void MessagePumpAuraX11::BlockUntilWindowMapped(unsigned long xid) { } while (event.type != MapNotify); } -MessagePumpAuraX11::~MessagePumpAuraX11() { - g_source_destroy(x_source_); - g_source_unref(x_source_); - XCloseDisplay(g_xdisplay); - g_xdisplay = NULL; -} - void MessagePumpAuraX11::InitXSource() { // CHECKs are to help track down crbug.com/113106. CHECK(!x_source_); diff --git a/base/message_loop/message_pump_aurax11.h b/base/message_loop/message_pump_aurax11.h index f11b3b4..89089ad 100644 --- a/base/message_loop/message_pump_aurax11.h +++ b/base/message_loop/message_pump_aurax11.h @@ -35,6 +35,7 @@ class BASE_EXPORT MessagePumpAuraX11 : public MessagePumpGlib, public MessagePumpDispatcher { public: MessagePumpAuraX11(); + virtual ~MessagePumpAuraX11(); // Returns default X Display. static Display* GetDefaultXDisplay(); @@ -72,9 +73,6 @@ class BASE_EXPORT MessagePumpAuraX11 : public MessagePumpGlib, // functions which require a mapped window. void BlockUntilWindowMapped(unsigned long xid); - protected: - virtual ~MessagePumpAuraX11(); - private: typedef std::map<unsigned long, MessagePumpDispatcher*> DispatchersMap; diff --git a/base/message_loop/message_pump_default.cc b/base/message_loop/message_pump_default.cc index b36ff21..27c19e0 100644 --- a/base/message_loop/message_pump_default.cc +++ b/base/message_loop/message_pump_default.cc @@ -18,6 +18,9 @@ MessagePumpDefault::MessagePumpDefault() event_(false, false) { } +MessagePumpDefault::~MessagePumpDefault() { +} + void MessagePumpDefault::Run(Delegate* delegate) { DCHECK(keep_running_) << "Quit must have been called outside of Run!"; diff --git a/base/message_loop/message_pump_default.h b/base/message_loop/message_pump_default.h index 07a6c70..a9b83e8 100644 --- a/base/message_loop/message_pump_default.h +++ b/base/message_loop/message_pump_default.h @@ -14,6 +14,7 @@ namespace base { class MessagePumpDefault : public MessagePump { public: MessagePumpDefault(); + virtual ~MessagePumpDefault(); // MessagePump methods: virtual void Run(Delegate* delegate) OVERRIDE; @@ -21,9 +22,6 @@ class MessagePumpDefault : public MessagePump { virtual void ScheduleWork() OVERRIDE; virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE; - protected: - virtual ~MessagePumpDefault() {} - private: // This flag is set to false when Run should return. bool keep_running_; diff --git a/base/message_loop/message_pump_glib.cc b/base/message_loop/message_pump_glib.cc index de012fd..cfacb7b 100644 --- a/base/message_loop/message_pump_glib.cc +++ b/base/message_loop/message_pump_glib.cc @@ -160,6 +160,13 @@ MessagePumpGlib::MessagePumpGlib() g_source_attach(work_source_, context_); } +MessagePumpGlib::~MessagePumpGlib() { + g_source_destroy(work_source_); + g_source_unref(work_source_); + close(wakeup_pipe_read_); + close(wakeup_pipe_write_); +} + void MessagePumpGlib::RunWithDispatcher(Delegate* delegate, MessagePumpDispatcher* dispatcher) { #ifndef NDEBUG @@ -320,13 +327,6 @@ void MessagePumpGlib::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { ScheduleWork(); } -MessagePumpGlib::~MessagePumpGlib() { - g_source_destroy(work_source_); - g_source_unref(work_source_); - close(wakeup_pipe_read_); - close(wakeup_pipe_write_); -} - MessagePumpDispatcher* MessagePumpGlib::GetDispatcher() { return state_ ? state_->dispatcher : NULL; } diff --git a/base/message_loop/message_pump_glib.h b/base/message_loop/message_pump_glib.h index 775470e..33690d0 100644 --- a/base/message_loop/message_pump_glib.h +++ b/base/message_loop/message_pump_glib.h @@ -35,6 +35,7 @@ class MessagePumpDispatcher; class BASE_EXPORT MessagePumpGlib : public MessagePump { public: MessagePumpGlib(); + virtual ~MessagePumpGlib(); // Like MessagePump::Run, but events are routed through dispatcher. virtual void RunWithDispatcher(Delegate* delegate, @@ -64,8 +65,6 @@ class BASE_EXPORT MessagePumpGlib : public MessagePump { virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE; protected: - virtual ~MessagePumpGlib(); - // Returns the dispatcher for the current run state (|state_->dispatcher|). MessagePumpDispatcher* GetDispatcher(); diff --git a/base/message_loop/message_pump_gtk.cc b/base/message_loop/message_pump_gtk.cc index 8fa8cf2..ad65113 100644 --- a/base/message_loop/message_pump_gtk.cc +++ b/base/message_loop/message_pump_gtk.cc @@ -65,6 +65,11 @@ MessagePumpGtk::MessagePumpGtk() : MessagePumpGlib() { gdk_event_handler_set(&EventDispatcher, this, NULL); } +MessagePumpGtk::~MessagePumpGtk() { + gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event), + this, NULL); +} + void MessagePumpGtk::DispatchEvents(GdkEvent* event) { UNSHIPPED_TRACE_EVENT1("task", "MessagePumpGtk::DispatchEvents", "type", EventToTypeString(event)); @@ -92,11 +97,6 @@ Display* MessagePumpGtk::GetDefaultXDisplay() { return GDK_DISPLAY_XDISPLAY(display); } -MessagePumpGtk::~MessagePumpGtk() { - gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event), - this, NULL); -} - void MessagePumpGtk::WillProcessEvent(GdkEvent* event) { FOR_EACH_OBSERVER(MessagePumpObserver, observers(), WillProcessEvent(event)); } diff --git a/base/message_loop/message_pump_gtk.h b/base/message_loop/message_pump_gtk.h index e22e04f..947ab88 100644 --- a/base/message_loop/message_pump_gtk.h +++ b/base/message_loop/message_pump_gtk.h @@ -43,6 +43,7 @@ class MessagePumpDispatcher { class BASE_EXPORT MessagePumpGtk : public MessagePumpGlib { public: MessagePumpGtk(); + virtual ~MessagePumpGtk(); // Dispatch an available GdkEvent. Essentially this allows a subclass to do // some task before/after calling the default handler (EventDispatcher). @@ -51,9 +52,6 @@ class BASE_EXPORT MessagePumpGtk : public MessagePumpGlib { // Returns default X Display. static Display* GetDefaultXDisplay(); - protected: - virtual ~MessagePumpGtk(); - private: // Invoked from EventDispatcher. Notifies all observers we're about to // process an event. diff --git a/base/message_loop/message_pump_io_ios.cc b/base/message_loop/message_pump_io_ios.cc index 0dd6930..cd5ffed 100644 --- a/base/message_loop/message_pump_io_ios.cc +++ b/base/message_loop/message_pump_io_ios.cc @@ -11,7 +11,6 @@ MessagePumpIOSForIO::FileDescriptorWatcher::FileDescriptorWatcher() fdref_(NULL), callback_types_(0), fd_source_(NULL), - pump_(NULL), watcher_(NULL) { } @@ -24,11 +23,12 @@ bool MessagePumpIOSForIO::FileDescriptorWatcher::StopWatchingFileDescriptor() { return true; CFFileDescriptorDisableCallBacks(fdref_, callback_types_); - pump_->RemoveRunLoopSource(fd_source_); + if (pump_) + pump_->RemoveRunLoopSource(fd_source_); fd_source_.reset(); fdref_.reset(); callback_types_ = 0; - pump_ = NULL; + pump_.reset(); watcher_ = NULL; return true; } @@ -65,7 +65,7 @@ void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking( pump->DidProcessIOEvent(); } -MessagePumpIOSForIO::MessagePumpIOSForIO() { +MessagePumpIOSForIO::MessagePumpIOSForIO() : weak_factory_(this) { } MessagePumpIOSForIO::~MessagePumpIOSForIO() { @@ -143,7 +143,7 @@ bool MessagePumpIOSForIO::WatchFileDescriptor( } controller->set_watcher(delegate); - controller->set_pump(this); + controller->set_pump(weak_factory_.GetWeakPtr()); return true; } @@ -183,7 +183,8 @@ void MessagePumpIOSForIO::HandleFdIOEvent(CFFileDescriptorRef fdref, fdref, base::scoped_policy::RETAIN); int fd = CFFileDescriptorGetNativeDescriptor(fdref); - MessagePumpIOSForIO* pump = controller->pump(); + MessagePumpIOSForIO* pump = controller->pump().get(); + DCHECK(pump); if (callback_types & kCFFileDescriptorWriteCallBack) controller->OnFileCanWriteWithoutBlocking(fd, pump); diff --git a/base/message_loop/message_pump_io_ios.h b/base/message_loop/message_pump_io_ios.h index 6596862b..52de9fd 100644 --- a/base/message_loop/message_pump_io_ios.h +++ b/base/message_loop/message_pump_io_ios.h @@ -9,6 +9,7 @@ #include "base/mac/scoped_cffiledescriptorref.h" #include "base/mac/scoped_cftyperef.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "base/message_loop/message_pump_mac.h" #include "base/observer_list.h" @@ -70,8 +71,8 @@ class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop { CFRunLoopSourceRef fd_source, bool is_persistent); - void set_pump(MessagePumpIOSForIO* pump) { pump_ = pump; } - MessagePumpIOSForIO* pump() const { return pump_; } + void set_pump(base::WeakPtr<MessagePumpIOSForIO> pump) { pump_ = pump; } + const base::WeakPtr<MessagePumpIOSForIO>& pump() const { return pump_; } void set_watcher(Watcher* watcher) { watcher_ = watcher; } @@ -82,7 +83,7 @@ class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop { base::mac::ScopedCFFileDescriptorRef fdref_; CFOptionFlags callback_types_; base::ScopedCFTypeRef<CFRunLoopSourceRef> fd_source_; - scoped_refptr<MessagePumpIOSForIO> pump_; + base::WeakPtr<MessagePumpIOSForIO> pump_; Watcher* watcher_; DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher); @@ -95,6 +96,7 @@ class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop { }; MessagePumpIOSForIO(); + virtual ~MessagePumpIOSForIO(); // Have the current thread's message loop watch for a a situation in which // reading/writing to the FD can be performed without blocking. @@ -118,9 +120,6 @@ class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop { void AddIOObserver(IOObserver* obs); void RemoveIOObserver(IOObserver* obs); - protected: - virtual ~MessagePumpIOSForIO(); - private: friend class MessagePumpIOSForIOTest; @@ -134,6 +133,8 @@ class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop { ObserverList<IOObserver> io_observers_; ThreadChecker watch_file_descriptor_caller_checker_; + base::WeakPtrFactory<MessagePumpIOSForIO> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIO); }; diff --git a/base/message_loop/message_pump_io_ios_unittest.cc b/base/message_loop/message_pump_io_ios_unittest.cc index 5fbba69..9c7a8fb 100644 --- a/base/message_loop/message_pump_io_ios_unittest.cc +++ b/base/message_loop/message_pump_io_ios_unittest.cc @@ -126,7 +126,7 @@ class DeleteWatcher : public BaseWatcher { }; TEST_F(MessagePumpIOSForIOTest, DeleteWatcher) { - scoped_refptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); + scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); MessagePumpIOSForIO::FileDescriptorWatcher* watcher = new MessagePumpIOSForIO::FileDescriptorWatcher; DeleteWatcher delegate(watcher); @@ -162,9 +162,9 @@ class StopWatcher : public BaseWatcher { }; TEST_F(MessagePumpIOSForIOTest, StopWatcher) { - scoped_refptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); + scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); MessagePumpIOSForIO::FileDescriptorWatcher watcher; - StopWatcher delegate(&watcher, pump); + StopWatcher delegate(&watcher, pump.get()); pump->WatchFileDescriptor(pipefds_[1], false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate); @@ -173,9 +173,9 @@ TEST_F(MessagePumpIOSForIOTest, StopWatcher) { } TEST_F(MessagePumpIOSForIOTest, StopWatcherAndWatchSomethingElse) { - scoped_refptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); + scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); MessagePumpIOSForIO::FileDescriptorWatcher watcher; - StopWatcher delegate(&watcher, pump, alternate_pipefds_[1]); + StopWatcher delegate(&watcher, pump.get(), alternate_pipefds_[1]); pump->WatchFileDescriptor(pipefds_[1], false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate); diff --git a/base/message_loop/message_pump_libevent.h b/base/message_loop/message_pump_libevent.h index 3b1d26d..f3a48a9 100644 --- a/base/message_loop/message_pump_libevent.h +++ b/base/message_loop/message_pump_libevent.h @@ -98,6 +98,7 @@ class BASE_EXPORT MessagePumpLibevent : public MessagePump { }; MessagePumpLibevent(); + virtual ~MessagePumpLibevent(); // Have the current thread's message loop watch for a a situation in which // reading/writing to the FD can be performed without blocking. @@ -126,9 +127,6 @@ class BASE_EXPORT MessagePumpLibevent : public MessagePump { virtual void ScheduleWork() OVERRIDE; virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE; - protected: - virtual ~MessagePumpLibevent(); - private: friend class MessagePumpLibeventTest; diff --git a/base/message_loop/message_pump_libevent_unittest.cc b/base/message_loop/message_pump_libevent_unittest.cc index 657ac7d..52ca95b 100644 --- a/base/message_loop/message_pump_libevent_unittest.cc +++ b/base/message_loop/message_pump_libevent_unittest.cc @@ -122,7 +122,7 @@ class DeleteWatcher : public BaseWatcher { }; TEST_F(MessagePumpLibeventTest, DeleteWatcher) { - scoped_refptr<MessagePumpLibevent> pump(new MessagePumpLibevent); + scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); MessagePumpLibevent::FileDescriptorWatcher* watcher = new MessagePumpLibevent::FileDescriptorWatcher; DeleteWatcher delegate(watcher); @@ -147,7 +147,7 @@ class StopWatcher : public BaseWatcher { }; TEST_F(MessagePumpLibeventTest, StopWatcher) { - scoped_refptr<MessagePumpLibevent> pump(new MessagePumpLibevent); + scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); MessagePumpLibevent::FileDescriptorWatcher watcher; StopWatcher delegate(&watcher); pump->WatchFileDescriptor(pipefds_[1], diff --git a/base/message_loop/message_pump_mac.h b/base/message_loop/message_pump_mac.h index 68c2a3d..3dbeb3d 100644 --- a/base/message_loop/message_pump_mac.h +++ b/base/message_loop/message_pump_mac.h @@ -63,6 +63,7 @@ class MessagePumpCFRunLoopBase : public MessagePump { friend class MessagePumpScopedAutoreleasePool; public: MessagePumpCFRunLoopBase(); + virtual ~MessagePumpCFRunLoopBase(); // Subclasses should implement the work they need to do in MessagePump::Run // in the DoRun method. MessagePumpCFRunLoopBase::Run calls DoRun directly. @@ -75,8 +76,6 @@ class MessagePumpCFRunLoopBase : public MessagePump { virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) OVERRIDE; protected: - virtual ~MessagePumpCFRunLoopBase(); - // Accessors for private data members to be used by subclasses. CFRunLoopRef run_loop() const { return run_loop_; } int nesting_level() const { return nesting_level_; } @@ -199,13 +198,11 @@ class MessagePumpCFRunLoopBase : public MessagePump { class MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase { public: MessagePumpCFRunLoop(); + virtual ~MessagePumpCFRunLoop(); virtual void DoRun(Delegate* delegate) OVERRIDE; virtual void Quit() OVERRIDE; - protected: - virtual ~MessagePumpCFRunLoop(); - private: virtual void EnterExitRunLoop(CFRunLoopActivity activity) OVERRIDE; @@ -220,13 +217,11 @@ class MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase { class MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase { public: BASE_EXPORT MessagePumpNSRunLoop(); + virtual ~MessagePumpNSRunLoop(); virtual void DoRun(Delegate* delegate) OVERRIDE; virtual void Quit() OVERRIDE; - protected: - virtual ~MessagePumpNSRunLoop(); - private: // A source that doesn't do anything but provide something signalable // attached to the run loop. This source will be signalled when Quit @@ -246,6 +241,7 @@ class MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase { class MessagePumpUIApplication : public MessagePumpCFRunLoopBase { public: MessagePumpUIApplication(); + virtual ~MessagePumpUIApplication(); virtual void DoRun(Delegate* delegate) OVERRIDE; virtual void Quit() OVERRIDE; @@ -253,9 +249,6 @@ class MessagePumpUIApplication : public MessagePumpCFRunLoopBase { // call |Attach()| to set up a delegate. It is an error to call |Run()|. virtual void Attach(Delegate* delegate); - protected: - virtual ~MessagePumpUIApplication(); - private: RunLoop* run_loop_; @@ -267,13 +260,11 @@ class MessagePumpUIApplication : public MessagePumpCFRunLoopBase { class MessagePumpNSApplication : public MessagePumpCFRunLoopBase { public: MessagePumpNSApplication(); + virtual ~MessagePumpNSApplication(); virtual void DoRun(Delegate* delegate) OVERRIDE; virtual void Quit() OVERRIDE; - protected: - virtual ~MessagePumpNSApplication(); - private: // False after Quit is called. bool keep_running_; @@ -290,10 +281,9 @@ class MessagePumpNSApplication : public MessagePumpCFRunLoopBase { class MessagePumpCrApplication : public MessagePumpNSApplication { public: MessagePumpCrApplication(); + virtual ~MessagePumpCrApplication(); protected: - virtual ~MessagePumpCrApplication() {} - // Returns nil if NSApp is currently in the middle of calling // -sendEvent. Requires NSApp implementing CrAppProtocol. virtual NSAutoreleasePool* CreateAutoreleasePool() OVERRIDE; diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm index f46d7a8..f885fbf 100644 --- a/base/message_loop/message_pump_mac.mm +++ b/base/message_loop/message_pump_mac.mm @@ -616,6 +616,9 @@ void MessagePumpNSApplication::Quit() { MessagePumpCrApplication::MessagePumpCrApplication() { } +MessagePumpCrApplication::~MessagePumpCrApplication() { +} + // Prevents an autorelease pool from being created if the app is in the midst of // handling a UI event because various parts of AppKit depend on objects that // are created while handling a UI event to be autoreleased in the event loop. diff --git a/base/message_loop/message_pump_ozone.h b/base/message_loop/message_pump_ozone.h index de75ab4..edcdf2e 100644 --- a/base/message_loop/message_pump_ozone.h +++ b/base/message_loop/message_pump_ozone.h @@ -20,6 +20,7 @@ class BASE_EXPORT MessagePumpOzone : public MessagePumpLibevent, public MessagePumpDispatcher { public: MessagePumpOzone(); + virtual ~MessagePumpOzone(); // Returns the UI message pump. static MessagePumpOzone* Current(); @@ -39,7 +40,6 @@ class BASE_EXPORT MessagePumpOzone : public MessagePumpLibevent, virtual bool Dispatch(const NativeEvent& event) OVERRIDE; private: - virtual ~MessagePumpOzone(); std::vector<MessagePumpDispatcher*> dispatcher_; DISALLOW_COPY_AND_ASSIGN(MessagePumpOzone); diff --git a/base/test/test_support_android.cc b/base/test/test_support_android.cc index e044322..1ad4c2b 100644 --- a/base/test/test_support_android.cc +++ b/base/test/test_support_android.cc @@ -72,6 +72,8 @@ class Waitable { // The MessagePumpForUI implementation for test purpose. class MessagePumpForUIStub : public base::MessagePumpForUI { + virtual ~MessagePumpForUIStub() {} + virtual void Start(base::MessagePump::Delegate* delegate) OVERRIDE { NOTREACHED() << "The Start() method shouldn't be called in test, using" " Run() method should be used."; @@ -129,9 +131,6 @@ class MessagePumpForUIStub : public base::MessagePumpForUI { const base::TimeTicks& delayed_work_time) OVERRIDE { Waitable::GetInstance()->Signal(); } - - protected: - virtual ~MessagePumpForUIStub() {} }; base::MessagePump* CreateMessagePumpForUIStub() { diff --git a/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller_unittest.mm index 05304e8..b80a2a8 100644 --- a/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller_unittest.mm @@ -5,6 +5,7 @@ #import "chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h" #include "base/mac/scoped_nsobject.h" +#include "base/memory/scoped_ptr.h" #include "base/message_loop/message_pump_mac.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/prefs/pref_service_syncable.h" @@ -142,7 +143,7 @@ TEST_F(AvatarMenuBubbleControllerTest, PerformLayout) { @interface TestingAvatarMenuItemController : AvatarMenuItemController <NSAnimationDelegate> { @private - scoped_refptr<base::MessagePumpNSRunLoop> pump_; + scoped_ptr<base::MessagePumpNSRunLoop> pump_; } // After calling |-highlightForEventType:| an animation will possibly be // started. Since the animation is non-blocking, the run loop will need to be @@ -152,8 +153,8 @@ TEST_F(AvatarMenuBubbleControllerTest, PerformLayout) { @implementation TestingAvatarMenuItemController - (void)runMessagePump { - if (!pump_.get()) - pump_ = new base::MessagePumpNSRunLoop; + if (!pump_) + pump_.reset(new base::MessagePumpNSRunLoop); pump_->Run(NULL); } diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation_unittest.mm index 5ec022f..1fd2d9e 100644 --- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation_unittest.mm +++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_animation_unittest.mm @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/mac/scoped_nsobject.h" +#include "base/memory/scoped_ptr.h" #include "base/message_loop/message_pump_mac.h" #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_animation.h" @@ -12,7 +13,7 @@ <NSAnimationDelegate> { @private CGFloat frameCount_; - scoped_refptr<base::MessagePumpNSRunLoop> message_pump_; + scoped_ptr<base::MessagePumpNSRunLoop> message_pump_; } - (void)runAnimation:(NSAnimation*)animation; @@ -23,7 +24,7 @@ - (id)init { if ((self = [super init])) - message_pump_ = new base::MessagePumpNSRunLoop; + message_pump_.reset(new base::MessagePumpNSRunLoop); return self; } diff --git a/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm b/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm index 96ab915..f92ccb9 100644 --- a/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/history_overlay_controller_unittest.mm @@ -6,7 +6,7 @@ #import <QuartzCore/QuartzCore.h> -#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/message_loop/message_pump_mac.h" #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" #import "third_party/ocmock/gtest_support.h" @@ -53,7 +53,7 @@ TEST_F(HistoryOverlayControllerTest, DismissClearsAnimations) { [[HistoryOverlayController alloc] initForMode:kHistoryOverlayModeBack]); [controller showPanelForView:test_view()]; - scoped_refptr<base::MessagePumpNSRunLoop> message_pump( + scoped_ptr<base::MessagePumpNSRunLoop> message_pump( new base::MessagePumpNSRunLoop); id mock = [OCMockObject partialMockForObject:controller]; @@ -61,8 +61,9 @@ TEST_F(HistoryOverlayControllerTest, DismissClearsAnimations) { [[[mock expect] andForwardToRealObject] dismiss]; // Called after |-animationDidStop:finished:|. + base::MessagePumpNSRunLoop* weak_message_pump = message_pump.get(); void (^quit_loop)(NSInvocation* invocation) = ^(NSInvocation* invocation) { - message_pump->Quit(); + weak_message_pump->Quit(); }; // Set up the mock to first forward to the real implementation and then call // the above block to quit the run loop. diff --git a/chrome/browser/ui/cocoa/run_loop_testing.mm b/chrome/browser/ui/cocoa/run_loop_testing.mm index f79aa53..927e440a 100644 --- a/chrome/browser/ui/cocoa/run_loop_testing.mm +++ b/chrome/browser/ui/cocoa/run_loop_testing.mm @@ -7,6 +7,7 @@ #import <Foundation/Foundation.h> #include "base/mac/scoped_nsobject.h" +#include "base/memory/scoped_ptr.h" #include "base/message_loop/message_pump_mac.h" // This class is scheduled with a delayed selector to quit the message pump. @@ -37,7 +38,7 @@ namespace chrome { namespace testing { void NSRunLoopRunAllPending() { - scoped_refptr<base::MessagePumpNSRunLoop> message_pump( + scoped_ptr<base::MessagePumpNSRunLoop> message_pump( new base::MessagePumpNSRunLoop); // Put a delayed selector on the queue. All other pending delayed selectors diff --git a/media/base/pipeline_unittest.cc b/media/base/pipeline_unittest.cc index 804fc99..90c616f 100644 --- a/media/base/pipeline_unittest.cc +++ b/media/base/pipeline_unittest.cc @@ -689,14 +689,14 @@ static void TestNoCallsAfterError( CHECK(message_loop); // When we get to this stage, the message loop should be empty. - message_loop->AssertIdle(); + EXPECT_TRUE(message_loop->IsIdleForTesting()); // Make calls on pipeline after error has occurred. pipeline->SetPlaybackRate(0.5f); pipeline->SetVolume(0.5f); // No additional tasks should be queued as a result of these calls. - message_loop->AssertIdle(); + EXPECT_TRUE(message_loop->IsIdleForTesting()); } TEST_F(PipelineTest, NoMessageDuringTearDownFromError) { diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc index 80473b5..f9667ee 100644 --- a/net/dns/dns_transaction_unittest.cc +++ b/net/dns/dns_transaction_unittest.cc @@ -621,7 +621,7 @@ TEST_F(DnsTransactionTest, Timeout) { TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_DNS_TIMED_OUT); EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get())); - base::MessageLoop::current()->AssertIdle(); + EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); } TEST_F(DnsTransactionTest, ServerFallbackAndRotate) { diff --git a/net/dns/serial_worker_unittest.cc b/net/dns/serial_worker_unittest.cc index 70259f7..442526f 100644 --- a/net/dns/serial_worker_unittest.cc +++ b/net/dns/serial_worker_unittest.cc @@ -141,7 +141,7 @@ TEST_F(SerialWorkerTest, ExecuteAndSerializeReads) { WaitForWork(); RunUntilBreak("OnWorkFinished"); - message_loop_->AssertIdle(); + EXPECT_TRUE(message_loop_->IsIdleForTesting()); } // Schedule two calls. OnWork checks if it is called serially. @@ -154,7 +154,7 @@ TEST_F(SerialWorkerTest, ExecuteAndSerializeReads) { RunUntilBreak("OnWorkFinished"); // No more tasks should remain. - message_loop_->AssertIdle(); + EXPECT_TRUE(message_loop_->IsIdleForTesting()); } } // namespace |