Index: mojo/common/handle_watcher.cc |
diff --git a/mojo/common/handle_watcher.cc b/mojo/common/handle_watcher.cc |
index a95669c5803056037723de81df2a84e391fd7881..1affa9041be060f14ee455934c7ee616457b7254 100644 |
--- a/mojo/common/handle_watcher.cc |
+++ b/mojo/common/handle_watcher.cc |
@@ -253,29 +253,55 @@ WatcherThreadManager::WatcherThreadManager() |
} // namespace |
-// HandleWatcher::StartState --------------------------------------------------- |
+// HandleWatcher::State -------------------------------------------------------- |
-// Contains the information passed to Start(). |
-struct HandleWatcher::StartState { |
- explicit StartState(HandleWatcher* watcher) : weak_factory(watcher) { |
+// Represents the state of the HandleWatcher. Owns the user's callback and |
+// monitors the current thread's MessageLoop to know when to force the callback |
+// to run (with an error) even though the pipe hasn't been signaled yet. |
+class HandleWatcher::State : public base::MessageLoop::DestructionObserver { |
+ public: |
+ State(HandleWatcher* watcher, |
+ const Handle& handle, |
+ MojoWaitFlags wait_flags, |
+ MojoDeadline deadline, |
+ const base::Callback<void(MojoResult)>& callback) |
+ : watcher_(watcher), |
+ callback_(callback), |
+ weak_factory_(this) { |
+ base::MessageLoop::current()->AddDestructionObserver(this); |
+ |
+ watcher_id_ = WatcherThreadManager::GetInstance()->StartWatching( |
+ handle, |
+ wait_flags, |
+ MojoDeadlineToTimeTicks(deadline), |
+ base::Bind(&State::OnHandleReady, weak_factory_.GetWeakPtr())); |
} |
- ~StartState() { |
+ virtual ~State() { |
+ base::MessageLoop::current()->RemoveDestructionObserver(this); |
+ |
+ WatcherThreadManager::GetInstance()->StopWatching(watcher_id_); |
} |
- // ID assigned by WatcherThreadManager. |
- WatcherID watcher_id; |
+ private: |
+ virtual void WillDestroyCurrentMessageLoop() OVERRIDE { |
+ // The current thread is exiting. Simulate a watch error. |
+ OnHandleReady(MOJO_RESULT_ABORTED); |
+ } |
- // Callback to notify when done. |
- base::Callback<void(MojoResult)> callback; |
+ void OnHandleReady(MojoResult result) { |
+ base::Callback<void(MojoResult)> callback = callback_; |
+ watcher_->Stop(); // Destroys |this|. |
+ |
+ callback.Run(result); |
+ } |
- // When Start() is invoked a callback is passed to WatcherThreadManager |
- // using a WeakRef from |weak_refactory_|. The callback invokes |
- // OnHandleReady() (on the thread Start() is invoked from) which in turn |
- // notifies |callback_|. Doing this allows us to reset state when the handle |
- // is ready, and then notify the callback. Doing this also means Stop() |
- // cancels any pending callbacks that may be inflight. |
- base::WeakPtrFactory<HandleWatcher> weak_factory; |
+ HandleWatcher* watcher_; |
+ WatcherID watcher_id_; |
+ base::Callback<void(MojoResult)> callback_; |
+ |
+ // Used to weakly bind |this| to the WatcherThreadManager. |
+ base::WeakPtrFactory<State> weak_factory_; |
}; |
// HandleWatcher --------------------------------------------------------------- |
@@ -284,7 +310,6 @@ HandleWatcher::HandleWatcher() { |
} |
HandleWatcher::~HandleWatcher() { |
- Stop(); |
} |
void HandleWatcher::Start(const Handle& handle, |
@@ -294,33 +319,11 @@ void HandleWatcher::Start(const Handle& handle, |
DCHECK(handle.is_valid()); |
DCHECK_NE(MOJO_WAIT_FLAG_NONE, wait_flags); |
- Stop(); |
- |
- start_state_.reset(new StartState(this)); |
- start_state_->callback = callback; |
- start_state_->watcher_id = |
- WatcherThreadManager::GetInstance()->StartWatching( |
- handle, |
- wait_flags, |
- MojoDeadlineToTimeTicks(deadline), |
- base::Bind(&HandleWatcher::OnHandleReady, |
- start_state_->weak_factory.GetWeakPtr())); |
+ state_.reset(new State(this, handle, wait_flags, deadline, callback)); |
} |
void HandleWatcher::Stop() { |
- if (!start_state_.get()) |
- return; |
- |
- scoped_ptr<StartState> old_state(start_state_.Pass()); |
- WatcherThreadManager::GetInstance()->StopWatching(old_state->watcher_id); |
-} |
- |
-void HandleWatcher::OnHandleReady(MojoResult result) { |
- DCHECK(start_state_.get()); |
- scoped_ptr<StartState> old_state(start_state_.Pass()); |
- old_state->callback.Run(result); |
- |
- // NOTE: We may have been deleted during callback execution. |
+ state_.reset(); |
} |
} // namespace common |