1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/win/object_watcher.h" 6 7#include "base/bind.h" 8#include "base/logging.h" 9 10namespace base { 11namespace win { 12 13//----------------------------------------------------------------------------- 14 15ObjectWatcher::ObjectWatcher() 16 : weak_factory_(this), 17 object_(NULL), 18 wait_object_(NULL), 19 origin_loop_(NULL) { 20} 21 22ObjectWatcher::~ObjectWatcher() { 23 StopWatching(); 24} 25 26bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) { 27 CHECK(delegate); 28 if (wait_object_) { 29 NOTREACHED() << "Already watching an object"; 30 return false; 31 } 32 33 // Since our job is to just notice when an object is signaled and report the 34 // result back to this thread, we can just run on a Windows wait thread. 35 DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE; 36 37 // DoneWaiting can be synchronously called from RegisterWaitForSingleObject, 38 // so set up all state now. 39 callback_ = base::Bind(&ObjectWatcher::Signal, weak_factory_.GetWeakPtr(), 40 delegate); 41 object_ = object; 42 origin_loop_ = MessageLoop::current(); 43 44 if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting, 45 this, INFINITE, wait_flags)) { 46 DLOG_GETLASTERROR(FATAL) << "RegisterWaitForSingleObject failed"; 47 object_ = NULL; 48 wait_object_ = NULL; 49 return false; 50 } 51 52 // We need to know if the current message loop is going away so we can 53 // prevent the wait thread from trying to access a dead message loop. 54 MessageLoop::current()->AddDestructionObserver(this); 55 return true; 56} 57 58bool ObjectWatcher::StopWatching() { 59 if (!wait_object_) 60 return false; 61 62 // Make sure ObjectWatcher is used in a single-threaded fashion. 63 DCHECK_EQ(origin_loop_, MessageLoop::current()); 64 65 // Blocking call to cancel the wait. Any callbacks already in progress will 66 // finish before we return from this call. 67 if (!UnregisterWaitEx(wait_object_, INVALID_HANDLE_VALUE)) { 68 DLOG_GETLASTERROR(FATAL) << "UnregisterWaitEx failed"; 69 return false; 70 } 71 72 weak_factory_.InvalidateWeakPtrs(); 73 object_ = NULL; 74 wait_object_ = NULL; 75 76 MessageLoop::current()->RemoveDestructionObserver(this); 77 return true; 78} 79 80HANDLE ObjectWatcher::GetWatchedObject() { 81 return object_; 82} 83 84// static 85void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) { 86 DCHECK(!timed_out); 87 88 // The destructor blocks on any callbacks that are in flight, so we know that 89 // that is always a pointer to a valid ObjectWater. 90 ObjectWatcher* that = static_cast<ObjectWatcher*>(param); 91 that->origin_loop_->PostTask(FROM_HERE, that->callback_); 92 that->callback_.Reset(); 93} 94 95void ObjectWatcher::Signal(Delegate* delegate) { 96 // Signaling the delegate may result in our destruction or a nested call to 97 // StartWatching(). As a result, we save any state we need and clear previous 98 // watcher state before signaling the delegate. 99 HANDLE object = object_; 100 StopWatching(); 101 delegate->OnObjectSignaled(object); 102} 103 104void ObjectWatcher::WillDestroyCurrentMessageLoop() { 105 // Need to shutdown the watch so that we don't try to access the MessageLoop 106 // after this point. 107 StopWatching(); 108} 109 110} // namespace win 111} // namespace base 112