|  | // 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 |