// 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" namespace base { namespace win { //----------------------------------------------------------------------------- ObjectWatcher::ObjectWatcher() : weak_factory_(this), object_(NULL), wait_object_(NULL), origin_loop_(NULL) { } ObjectWatcher::~ObjectWatcher() { StopWatching(); } bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) { CHECK(delegate); if (wait_object_) { NOTREACHED() << "Already watching an object"; return false; } // Since our job is to just notice when an object is signaled and report the // result back to this thread, we can just run on a Windows wait thread. DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE; // DoneWaiting can be synchronously called from RegisterWaitForSingleObject, // so set up all state now. callback_ = base::Bind(&ObjectWatcher::Signal, weak_factory_.GetWeakPtr(), delegate); object_ = object; origin_loop_ = MessageLoop::current(); if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting, this, INFINITE, wait_flags)) { DPLOG(FATAL) << "RegisterWaitForSingleObject failed"; object_ = NULL; wait_object_ = NULL; return false; } // We need to know if the current message loop is going away so we can // prevent the wait thread from trying to access a dead message loop. MessageLoop::current()->AddDestructionObserver(this); return true; } bool ObjectWatcher::StopWatching() { if (!wait_object_) return false; // Make sure ObjectWatcher is used in a single-threaded fashion. DCHECK_EQ(origin_loop_, MessageLoop::current()); // 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; } weak_factory_.InvalidateWeakPtrs(); object_ = NULL; wait_object_ = NULL; MessageLoop::current()->RemoveDestructionObserver(this); return true; } HANDLE ObjectWatcher::GetWatchedObject() { 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->origin_loop_->PostTask(FROM_HERE, that->callback_); that->callback_.Reset(); } 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_; StopWatching(); delegate->OnObjectSignaled(object); } void ObjectWatcher::WillDestroyCurrentMessageLoop() { // Need to shutdown the watch so that we don't try to access the MessageLoop // after this point. StopWatching(); } } // namespace win } // namespace base