diff options
author | alexeypa@google.com <alexeypa@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-22 20:06:56 +0000 |
---|---|---|
committer | alexeypa@google.com <alexeypa@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-22 20:06:56 +0000 |
commit | c9904b429860b83606492d4fe8f1b232c04753b5 (patch) | |
tree | 4540d02ffe16677475ae55d0b19bc2d339b961d4 /base/message_loop | |
parent | 7552e6b65ac0a972036bef093ed48b5c85827f44 (diff) | |
download | chromium_src-c9904b429860b83606492d4fe8f1b232c04753b5.zip chromium_src-c9904b429860b83606492d4fe8f1b232c04753b5.tar.gz chromium_src-c9904b429860b83606492d4fe8f1b232c04753b5.tar.bz2 |
Revert 212948 "Made MessagePump a non-thread safe class."
r212948 broke Mac Builder: http://build.chromium.org/p/chromium.memory/builders/Mac%20ASAN%20Builder/builds/25623
> Made MessagePump a non-thread safe class.
>
> This CL makes MessagePump a non-thread safe class to make sure thread-bound resources (such as the UI window used for pumping messages on Windows) are freed on the correct thread.
>
> Handling of incoming tasks and synchronization between different threads was moved out to a separate class - IncomingTaskQueue reducing the number of locks to be taken while posting a task to one. Posting tasks via both MessageLoop and MessageLoopProxyImpl is now routed via IncomingTaskQueue.
>
> BUG=241939
>
> Review URL: https://chromiumcodereview.appspot.com/17567007
TBR=alexeypa@chromium.org
Review URL: https://codereview.chromium.org/19737005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@212952 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/message_loop')
25 files changed, 388 insertions, 468 deletions
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc deleted file mode 100644 index db99d87..0000000 --- a/base/message_loop/incoming_task_queue.cc +++ /dev/null @@ -1,169 +0,0 @@ -// 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 deleted file mode 100644 index d831a71..0000000 --- a/base/message_loop/incoming_task_queue.h +++ /dev/null @@ -1,104 +0,0 @@ -// 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 d2eafbd8..bd3542a 100644 --- a/base/message_loop/message_loop.cc +++ b/base/message_loop/message_loop.cc @@ -13,6 +13,7 @@ #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" @@ -88,6 +89,14 @@ 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) { @@ -137,19 +146,18 @@ MessageLoop::DestructionObserver::~DestructionObserver() { MessageLoop::MessageLoop(Type type) : type_(type), - exception_restoration_(false), nestable_tasks_allowed_(true), + exception_restoration_(false), + message_histogram_(NULL), + run_loop_(NULL), #if defined(OS_WIN) os_modal_loop_(false), #endif // OS_WIN - message_histogram_(NULL), - run_loop_(NULL) { + next_sequence_num_(0) { DCHECK(!current()) << "should only have one message loop per thread"; lazy_tls_ptr.Pointer()->Set(this); - incoming_task_queue_ = new internal::IncomingTaskQueue(this); - message_loop_proxy_ = - new internal::MessageLoopProxyImpl(incoming_task_queue_); + message_loop_proxy_ = new MessageLoopProxyImpl(); thread_task_runner_handle_.reset( new ThreadTaskRunnerHandle(message_loop_proxy_)); @@ -169,7 +177,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() @@ -179,14 +187,14 @@ MessageLoop::MessageLoop(Type type) if (type_ == TYPE_UI) { if (message_pump_for_ui_factory_) - pump_.reset(message_pump_for_ui_factory_()); + pump_ = message_pump_for_ui_factory_(); else - pump_.reset(MESSAGE_PUMP_UI); + pump_ = MESSAGE_PUMP_UI; } else if (type_ == TYPE_IO) { - pump_.reset(MESSAGE_PUMP_IO); + pump_ = MESSAGE_PUMP_IO; } else { DCHECK_EQ(TYPE_DEFAULT, type_); - pump_.reset(new MessagePumpDefault()); + pump_ = new MessagePumpDefault(); } } @@ -218,13 +226,23 @@ MessageLoop::~MessageLoop() { thread_task_runner_handle_.reset(); - // Tell the incoming queue that we are dying. - incoming_task_queue_->WillDestroyCurrentMessageLoop(); - incoming_task_queue_ = NULL; + // Tell the message_loop_proxy that we are dying. + static_cast<MessageLoopProxyImpl*>(message_loop_proxy_.get())-> + WillDestroyCurrentMessageLoop(); 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 @@ -265,14 +283,18 @@ void MessageLoop::PostTask( const tracked_objects::Location& from_here, const Closure& task) { DCHECK(!task.is_null()) << from_here.ToString(); - incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), true); + PendingTask pending_task( + from_here, task, CalculateDelayedRuntime(TimeDelta()), true); + AddToIncomingQueue(&pending_task, false); } bool MessageLoop::TryPostTask( const tracked_objects::Location& from_here, const Closure& task) { DCHECK(!task.is_null()) << from_here.ToString(); - return incoming_task_queue_->TryAddToIncomingQueue(from_here, task); + PendingTask pending_task( + from_here, task, CalculateDelayedRuntime(TimeDelta()), true); + return AddToIncomingQueue(&pending_task, true); } void MessageLoop::PostDelayedTask( @@ -280,14 +302,18 @@ void MessageLoop::PostDelayedTask( const Closure& task, TimeDelta delay) { DCHECK(!task.is_null()) << from_here.ToString(); - incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true); + PendingTask pending_task( + from_here, task, CalculateDelayedRuntime(delay), true); + AddToIncomingQueue(&pending_task, false); } void MessageLoop::PostNonNestableTask( const tracked_objects::Location& from_here, const Closure& task) { DCHECK(!task.is_null()) << from_here.ToString(); - incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), false); + PendingTask pending_task( + from_here, task, CalculateDelayedRuntime(TimeDelta()), false); + AddToIncomingQueue(&pending_task, false); } void MessageLoop::PostNonNestableDelayedTask( @@ -295,7 +321,9 @@ void MessageLoop::PostNonNestableDelayedTask( const Closure& task, TimeDelta delay) { DCHECK(!task.is_null()) << from_here.ToString(); - incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false); + PendingTask pending_task( + from_here, task, CalculateDelayedRuntime(delay), false); + AddToIncomingQueue(&pending_task, false); } void MessageLoop::Run() { @@ -367,26 +395,17 @@ 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: @@ -451,7 +470,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)), + TRACE_ID_MANGLE(GetTaskTraceID(pending_task, this)), "queue_duration", (start_time - pending_task.EffectiveTimePosted()).InMilliseconds()); TRACE_EVENT2("task", "MessageLoop::RunTask", @@ -504,6 +523,24 @@ 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()) { @@ -533,25 +570,87 @@ bool MessageLoop::DeletePendingTasks() { return did_work; } -uint64 MessageLoop::GetTaskTraceID(const PendingTask& task) { - return (static_cast<uint64>(task.sequence_num) << 32) | - static_cast<uint64>(reinterpret_cast<intptr_t>(this)); -} +TimeTicks MessageLoop::CalculateDelayedRuntime(TimeDelta delay) { + TimeTicks delayed_run_time; + if (delay > TimeDelta()) { + delayed_run_time = TimeTicks::Now() + delay; -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_); +#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; } -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(); +// 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_. + + pump->ScheduleWork(); + return true; } //------------------------------------------------------------------------------ diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h index 6f71a85..846cc8d 100644 --- a/base/message_loop/message_loop.h +++ b/base/message_loop/message_loop.h @@ -13,10 +13,7 @@ #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" @@ -49,12 +46,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. @@ -286,7 +283,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_; + return message_loop_proxy_.get(); } // Enables or disables the recursive task processing. This happens in the case @@ -362,10 +359,23 @@ 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; @@ -379,18 +389,6 @@ 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: @@ -404,11 +402,11 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { } #endif - scoped_ptr<MessagePump> pump_; + scoped_refptr<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 @@ -438,23 +436,34 @@ 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(); - // 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); + // Calculates the time at which a PendingTask should run. + TimeTicks CalculateDelayedRuntime(TimeDelta delay); // Start recording histogram info about events and action IF it was enabled // and IF the statistics recorder can accept a registration of our histogram. @@ -489,30 +498,40 @@ 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_; -#if defined(OS_WIN) - // Should be set to true before calling Windows APIs like TrackPopupMenu, etc - // which enter a modal message loop. - bool os_modal_loop_; -#endif + 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_; - ObserverList<TaskObserver> task_observers_; +#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 - scoped_refptr<internal::IncomingTaskQueue> incoming_task_queue_; + // The next sequence number to use for delayed tasks. Updating this counter is + // protected by incoming_queue_lock_. + int next_sequence_num_; + + ObserverList<TaskObserver> task_observers_; - // The message loop proxy associated with this message loop. - scoped_refptr<internal::MessageLoopProxyImpl> message_loop_proxy_; + // The message loop proxy associated with this message loop, if one exists. + scoped_refptr<MessageLoopProxy> 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 b7abca3..7dc8caa 100644 --- a/base/message_loop/message_loop_proxy_impl.cc +++ b/base/message_loop/message_loop_proxy_impl.cc @@ -5,43 +5,81 @@ #include "base/message_loop/message_loop_proxy_impl.h" #include "base/location.h" -#include "base/logging.h" -#include "base/message_loop/incoming_task_queue.h" -#include "base/message_loop/message_loop.h" +#include "base/threading/thread_restrictions.h" namespace base { -namespace internal { -MessageLoopProxyImpl::MessageLoopProxyImpl( - scoped_refptr<IncomingTaskQueue> incoming_queue) - : incoming_queue_(incoming_queue), - valid_thread_id_(PlatformThread::CurrentId()) { +MessageLoopProxyImpl::~MessageLoopProxyImpl() { } bool MessageLoopProxyImpl::PostDelayedTask( const tracked_objects::Location& from_here, const base::Closure& task, base::TimeDelta delay) { - DCHECK(!task.is_null()) << from_here.ToString(); - return incoming_queue_->AddToIncomingQueue(from_here, task, delay, true); + return PostTaskHelper(from_here, task, delay, true); } bool MessageLoopProxyImpl::PostNonNestableDelayedTask( const tracked_objects::Location& from_here, const base::Closure& task, base::TimeDelta delay) { - DCHECK(!task.is_null()) << from_here.ToString(); - return incoming_queue_->AddToIncomingQueue(from_here, task, delay, false); + return PostTaskHelper(from_here, task, delay, false); } bool MessageLoopProxyImpl::RunsTasksOnCurrentThread() const { - return valid_thread_id_ == PlatformThread::CurrentId(); + // 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_)); } -MessageLoopProxyImpl::~MessageLoopProxyImpl() { +// MessageLoop::DestructionObserver implementation +void MessageLoopProxyImpl::WillDestroyCurrentMessageLoop() { + AutoLock lock(message_loop_lock_); + target_message_loop_ = NULL; +} + +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; } -} // namespace internal +MessageLoopProxyImpl::MessageLoopProxyImpl() + : target_message_loop_(MessageLoop::current()) { +} + +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; +} 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 b7f62b9..6d6f0f6 100644 --- a/base/message_loop/message_loop_proxy_impl.h +++ b/base/message_loop/message_loop_proxy_impl.h @@ -6,24 +6,17 @@ #define BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_ #include "base/base_export.h" -#include "base/memory/ref_counted.h" +#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" -#include "base/pending_task.h" -#include "base/threading/platform_thread.h" +#include "base/synchronization/lock.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, @@ -34,20 +27,36 @@ class BASE_EXPORT MessageLoopProxyImpl : public MessageLoopProxy { base::TimeDelta delay) OVERRIDE; virtual bool RunsTasksOnCurrentThread() const OVERRIDE; - private: - friend class RefCountedThreadSafe<MessageLoopProxyImpl>; + protected: virtual ~MessageLoopProxyImpl(); - // THe incoming queue receiving all posted tasks. - scoped_refptr<IncomingTaskQueue> incoming_queue_; + // 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(); + + + bool PostTaskHelper(const tracked_objects::Location& from_here, + const base::Closure& task, + base::TimeDelta delay, + bool nestable); - // ID of the thread |this| was created on. - PlatformThreadId valid_thread_id_; + // The lock that protects access to target_message_loop_. + mutable base::Lock message_loop_lock_; + MessageLoop* target_message_loop_; 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 ab05b3c..504c8e3 100644 --- a/base/message_loop/message_loop_unittest.cc +++ b/base/message_loop/message_loop_unittest.cc @@ -10,7 +10,6 @@ #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" @@ -27,6 +26,19 @@ 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. @@ -109,10 +121,10 @@ void RunTest_PostTask(MessageLoop::Type message_loop_type) { thread.Start(); thread.message_loop()->PostTask( FROM_HERE, - Bind(&MessageLoop::LockWaitUnLockForTesting, - base::Unretained(MessageLoop::current()), - &wait, - &signal)); + Bind(&MessageLoopLockTest::LockWaitUnLock, + MessageLoop::current(), + &wait, + &signal)); wait.Wait(); EXPECT_FALSE(MessageLoop::current()->TryPostTask(FROM_HERE, Bind( @@ -1883,20 +1895,20 @@ TEST(MessageLoopTest, HighResolutionTimer) { const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5); const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100); - EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting()); + EXPECT_FALSE(loop.high_resolution_timers_enabled()); // Post a fast task to enable the high resolution timers. loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), kFastTimer); loop.Run(); - EXPECT_TRUE(loop.IsHighResolutionTimerEnabledForTesting()); + EXPECT_TRUE(loop.high_resolution_timers_enabled()); // 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.IsHighResolutionTimerEnabledForTesting()); + EXPECT_TRUE(loop.high_resolution_timers_enabled()); // Wait for a while so that high-resolution mode elapses. PlatformThread::Sleep(TimeDelta::FromMilliseconds( @@ -1906,7 +1918,7 @@ TEST(MessageLoopTest, HighResolutionTimer) { loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), kSlowTimer); loop.Run(); - EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting()); + EXPECT_FALSE(loop.high_resolution_timers_enabled()); } #endif // defined(OS_WIN) diff --git a/base/message_loop/message_pump.h b/base/message_loop/message_pump.h index 0ebba3a..5b72232 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/threading/non_thread_safe.h" +#include "base/memory/ref_counted.h" namespace base { class TimeTicks; -class BASE_EXPORT MessagePump : public NonThreadSafe { +class BASE_EXPORT MessagePump : public RefCountedThreadSafe<MessagePump> { public: // Please see the comments above the Run method for an illustration of how // these delegate methods are used. @@ -42,7 +42,6 @@ class BASE_EXPORT MessagePump : public NonThreadSafe { }; MessagePump(); - virtual ~MessagePump(); // The Run method is called to enter the message pump's run loop. // @@ -119,6 +118,10 @@ class BASE_EXPORT MessagePump : public NonThreadSafe { // 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 8a07a0f..f3a8ded 100644 --- a/base/message_loop/message_pump_android.h +++ b/base/message_loop/message_pump_android.h @@ -22,7 +22,6 @@ class TimeTicks; class BASE_EXPORT MessagePumpForUI : public MessagePump { public: MessagePumpForUI(); - virtual ~MessagePumpForUI(); virtual void Run(Delegate* delegate) OVERRIDE; virtual void Quit() OVERRIDE; @@ -33,6 +32,9 @@ 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 1f91a0e..7f60628 100644 --- a/base/message_loop/message_pump_aurax11.cc +++ b/base/message_loop/message_pump_aurax11.cc @@ -139,13 +139,6 @@ 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) @@ -218,6 +211,13 @@ 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 89089ad..f11b3b4 100644 --- a/base/message_loop/message_pump_aurax11.h +++ b/base/message_loop/message_pump_aurax11.h @@ -35,7 +35,6 @@ class BASE_EXPORT MessagePumpAuraX11 : public MessagePumpGlib, public MessagePumpDispatcher { public: MessagePumpAuraX11(); - virtual ~MessagePumpAuraX11(); // Returns default X Display. static Display* GetDefaultXDisplay(); @@ -73,6 +72,9 @@ 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 27c19e0..b36ff21 100644 --- a/base/message_loop/message_pump_default.cc +++ b/base/message_loop/message_pump_default.cc @@ -18,9 +18,6 @@ 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 a9b83e8..07a6c70 100644 --- a/base/message_loop/message_pump_default.h +++ b/base/message_loop/message_pump_default.h @@ -14,7 +14,6 @@ namespace base { class MessagePumpDefault : public MessagePump { public: MessagePumpDefault(); - virtual ~MessagePumpDefault(); // MessagePump methods: virtual void Run(Delegate* delegate) OVERRIDE; @@ -22,6 +21,9 @@ 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 cfacb7b..de012fd 100644 --- a/base/message_loop/message_pump_glib.cc +++ b/base/message_loop/message_pump_glib.cc @@ -160,13 +160,6 @@ 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 @@ -327,6 +320,13 @@ 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 33690d0..775470e 100644 --- a/base/message_loop/message_pump_glib.h +++ b/base/message_loop/message_pump_glib.h @@ -35,7 +35,6 @@ 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, @@ -65,6 +64,8 @@ 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 ad65113..8fa8cf2 100644 --- a/base/message_loop/message_pump_gtk.cc +++ b/base/message_loop/message_pump_gtk.cc @@ -65,11 +65,6 @@ 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)); @@ -97,6 +92,11 @@ 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 947ab88..e22e04f 100644 --- a/base/message_loop/message_pump_gtk.h +++ b/base/message_loop/message_pump_gtk.h @@ -43,7 +43,6 @@ 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). @@ -52,6 +51,9 @@ 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 cd5ffed..0dd6930 100644 --- a/base/message_loop/message_pump_io_ios.cc +++ b/base/message_loop/message_pump_io_ios.cc @@ -11,6 +11,7 @@ MessagePumpIOSForIO::FileDescriptorWatcher::FileDescriptorWatcher() fdref_(NULL), callback_types_(0), fd_source_(NULL), + pump_(NULL), watcher_(NULL) { } @@ -23,12 +24,11 @@ bool MessagePumpIOSForIO::FileDescriptorWatcher::StopWatchingFileDescriptor() { return true; CFFileDescriptorDisableCallBacks(fdref_, callback_types_); - if (pump_) - pump_->RemoveRunLoopSource(fd_source_); + pump_->RemoveRunLoopSource(fd_source_); fd_source_.reset(); fdref_.reset(); callback_types_ = 0; - pump_.reset(); + pump_ = NULL; watcher_ = NULL; return true; } @@ -65,7 +65,7 @@ void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking( pump->DidProcessIOEvent(); } -MessagePumpIOSForIO::MessagePumpIOSForIO() : weak_factory_(this) { +MessagePumpIOSForIO::MessagePumpIOSForIO() { } MessagePumpIOSForIO::~MessagePumpIOSForIO() { @@ -143,7 +143,7 @@ bool MessagePumpIOSForIO::WatchFileDescriptor( } controller->set_watcher(delegate); - controller->set_pump(weak_factory_.GetWeakPtr()); + controller->set_pump(this); return true; } @@ -183,8 +183,7 @@ void MessagePumpIOSForIO::HandleFdIOEvent(CFFileDescriptorRef fdref, fdref, base::scoped_policy::RETAIN); int fd = CFFileDescriptorGetNativeDescriptor(fdref); - MessagePumpIOSForIO* pump = controller->pump().get(); - DCHECK(pump); + MessagePumpIOSForIO* pump = controller->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 52de9fd..6596862b 100644 --- a/base/message_loop/message_pump_io_ios.h +++ b/base/message_loop/message_pump_io_ios.h @@ -9,7 +9,6 @@ #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" @@ -71,8 +70,8 @@ class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop { CFRunLoopSourceRef fd_source, bool is_persistent); - void set_pump(base::WeakPtr<MessagePumpIOSForIO> pump) { pump_ = pump; } - const base::WeakPtr<MessagePumpIOSForIO>& pump() const { return pump_; } + void set_pump(MessagePumpIOSForIO* pump) { pump_ = pump; } + MessagePumpIOSForIO* pump() const { return pump_; } void set_watcher(Watcher* watcher) { watcher_ = watcher; } @@ -83,7 +82,7 @@ class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop { base::mac::ScopedCFFileDescriptorRef fdref_; CFOptionFlags callback_types_; base::ScopedCFTypeRef<CFRunLoopSourceRef> fd_source_; - base::WeakPtr<MessagePumpIOSForIO> pump_; + scoped_refptr<MessagePumpIOSForIO> pump_; Watcher* watcher_; DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher); @@ -96,7 +95,6 @@ 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. @@ -120,6 +118,9 @@ class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop { void AddIOObserver(IOObserver* obs); void RemoveIOObserver(IOObserver* obs); + protected: + virtual ~MessagePumpIOSForIO(); + private: friend class MessagePumpIOSForIOTest; @@ -133,8 +134,6 @@ 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 9c7a8fb..5fbba69 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_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); + scoped_refptr<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_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); + scoped_refptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); MessagePumpIOSForIO::FileDescriptorWatcher watcher; - StopWatcher delegate(&watcher, pump.get()); + StopWatcher delegate(&watcher, pump); pump->WatchFileDescriptor(pipefds_[1], false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate); @@ -173,9 +173,9 @@ TEST_F(MessagePumpIOSForIOTest, StopWatcher) { } TEST_F(MessagePumpIOSForIOTest, StopWatcherAndWatchSomethingElse) { - scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); + scoped_refptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO); MessagePumpIOSForIO::FileDescriptorWatcher watcher; - StopWatcher delegate(&watcher, pump.get(), alternate_pipefds_[1]); + StopWatcher delegate(&watcher, pump, 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 f3a48a9..3b1d26d 100644 --- a/base/message_loop/message_pump_libevent.h +++ b/base/message_loop/message_pump_libevent.h @@ -98,7 +98,6 @@ 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. @@ -127,6 +126,9 @@ 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 52ca95b..657ac7d 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_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); + scoped_refptr<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_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent); + scoped_refptr<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 3dbeb3d..68c2a3d 100644 --- a/base/message_loop/message_pump_mac.h +++ b/base/message_loop/message_pump_mac.h @@ -63,7 +63,6 @@ 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. @@ -76,6 +75,8 @@ 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_; } @@ -198,11 +199,13 @@ 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; @@ -217,11 +220,13 @@ 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 @@ -241,7 +246,6 @@ class MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase { class MessagePumpUIApplication : public MessagePumpCFRunLoopBase { public: MessagePumpUIApplication(); - virtual ~MessagePumpUIApplication(); virtual void DoRun(Delegate* delegate) OVERRIDE; virtual void Quit() OVERRIDE; @@ -249,6 +253,9 @@ 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_; @@ -260,11 +267,13 @@ 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_; @@ -281,9 +290,10 @@ 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 f885fbf..f46d7a8 100644 --- a/base/message_loop/message_pump_mac.mm +++ b/base/message_loop/message_pump_mac.mm @@ -616,9 +616,6 @@ 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 edcdf2e..de75ab4 100644 --- a/base/message_loop/message_pump_ozone.h +++ b/base/message_loop/message_pump_ozone.h @@ -20,7 +20,6 @@ class BASE_EXPORT MessagePumpOzone : public MessagePumpLibevent, public MessagePumpDispatcher { public: MessagePumpOzone(); - virtual ~MessagePumpOzone(); // Returns the UI message pump. static MessagePumpOzone* Current(); @@ -40,6 +39,7 @@ 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); |