| // Copyright (c) 2012 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/win/object_watcher.h" |
| |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/threading/sequenced_task_runner_handle.h" |
| |
| #include <windows.h> |
| |
| namespace base { |
| namespace win { |
| |
| //----------------------------------------------------------------------------- |
| |
| ObjectWatcher::ObjectWatcher() : weak_factory_(this) {} |
| |
| ObjectWatcher::~ObjectWatcher() { |
| StopWatching(); |
| } |
| |
| bool ObjectWatcher::StartWatchingOnce(HANDLE object, Delegate* delegate) { |
| return StartWatchingInternal(object, delegate, true); |
| } |
| |
| bool ObjectWatcher::StartWatchingMultipleTimes(HANDLE object, |
| Delegate* delegate) { |
| return StartWatchingInternal(object, delegate, false); |
| } |
| |
| bool ObjectWatcher::StopWatching() { |
| if (!wait_object_) |
| return false; |
| |
| // Make sure ObjectWatcher is used in a sequenced fashion. |
| DCHECK(task_runner_->RunsTasksInCurrentSequence()); |
| |
| // Blocking call to cancel the wait. Any callbacks already in progress will |
| // finish before we return from this call. |
| if (!UnregisterWaitEx(wait_object_, INVALID_HANDLE_VALUE)) { |
| DPLOG(FATAL) << "UnregisterWaitEx failed"; |
| return false; |
| } |
| |
| Reset(); |
| return true; |
| } |
| |
| bool ObjectWatcher::IsWatching() const { |
| return object_ != nullptr; |
| } |
| |
| HANDLE ObjectWatcher::GetWatchedObject() const { |
| return object_; |
| } |
| |
| // static |
| void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) { |
| DCHECK(!timed_out); |
| |
| // The destructor blocks on any callbacks that are in flight, so we know that |
| // that is always a pointer to a valid ObjectWater. |
| ObjectWatcher* that = static_cast<ObjectWatcher*>(param); |
| that->task_runner_->PostTask(FROM_HERE, that->callback_); |
| if (that->run_once_) |
| that->callback_.Reset(); |
| } |
| |
| bool ObjectWatcher::StartWatchingInternal(HANDLE object, Delegate* delegate, |
| bool execute_only_once) { |
| DCHECK(delegate); |
| DCHECK(!wait_object_) << "Already watching an object"; |
| DCHECK(SequencedTaskRunnerHandle::IsSet()); |
| |
| task_runner_ = SequencedTaskRunnerHandle::Get(); |
| |
| run_once_ = execute_only_once; |
| |
| // Since our job is to just notice when an object is signaled and report the |
| // result back to this sequence, we can just run on a Windows wait thread. |
| DWORD wait_flags = WT_EXECUTEINWAITTHREAD; |
| if (run_once_) |
| wait_flags |= WT_EXECUTEONLYONCE; |
| |
| // DoneWaiting can be synchronously called from RegisterWaitForSingleObject, |
| // so set up all state now. |
| callback_ = |
| Bind(&ObjectWatcher::Signal, weak_factory_.GetWeakPtr(), delegate); |
| object_ = object; |
| |
| if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting, |
| this, INFINITE, wait_flags)) { |
| DPLOG(FATAL) << "RegisterWaitForSingleObject failed"; |
| Reset(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void ObjectWatcher::Signal(Delegate* delegate) { |
| // Signaling the delegate may result in our destruction or a nested call to |
| // StartWatching(). As a result, we save any state we need and clear previous |
| // watcher state before signaling the delegate. |
| HANDLE object = object_; |
| if (run_once_) |
| StopWatching(); |
| delegate->OnObjectSignaled(object); |
| } |
| |
| void ObjectWatcher::Reset() { |
| callback_.Reset(); |
| object_ = nullptr; |
| wait_object_ = nullptr; |
| task_runner_ = nullptr; |
| run_once_ = true; |
| weak_factory_.InvalidateWeakPtrs(); |
| } |
| |
| } // namespace win |
| } // namespace base |