13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 53f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/win/object_watcher.h" 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h" 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace base { 103f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace win { 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//----------------------------------------------------------------------------- 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct ObjectWatcher::Watch : public Task { 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ObjectWatcher* watcher; // The associated ObjectWatcher instance 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott HANDLE object; // The object being watched 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott HANDLE wait_object; // Returned by RegisterWaitForSingleObject 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott MessageLoop* origin_loop; // Used to get back to the origin thread 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Delegate* delegate; // Delegate to notify when signaled 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool did_signal; // DoneWaiting was called 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott virtual void Run() { 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // The watcher may have already been torn down, in which case we need to 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // just get out of dodge. 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!watcher) 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(did_signal); 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watcher->StopWatching(); 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delegate->OnObjectSignaled(object); 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//----------------------------------------------------------------------------- 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottObjectWatcher::ObjectWatcher() : watch_(NULL) { 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottObjectWatcher::~ObjectWatcher() { 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott StopWatching(); 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) { 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (watch_) { 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED() << "Already watching an object"; 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Watch* watch = new Watch; 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watch->watcher = this; 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watch->object = object; 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watch->origin_loop = MessageLoop::current(); 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watch->delegate = delegate; 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watch->did_signal = false; 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Since our job is to just notice when an object is signaled and report the 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // result back to this thread, we can just run on a Windows wait thread. 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE; 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!RegisterWaitForSingleObject(&watch->wait_object, object, DoneWaiting, 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watch, INFINITE, wait_flags)) { 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED() << "RegisterWaitForSingleObject failed: " << GetLastError(); 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delete watch; 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watch_ = watch; 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We need to know if the current message loop is going away so we can 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // prevent the wait thread from trying to access a dead message loop. 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott MessageLoop::current()->AddDestructionObserver(this); 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool ObjectWatcher::StopWatching() { 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!watch_) 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Make sure ObjectWatcher is used in a single-threaded fashion. 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(watch_->origin_loop == MessageLoop::current()); 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If DoneWaiting is in progress, we wait for it to finish. We know whether 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // DoneWaiting happened or not by inspecting the did_signal flag. 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!UnregisterWaitEx(watch_->wait_object, INVALID_HANDLE_VALUE)) { 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED() << "UnregisterWaitEx failed: " << GetLastError(); 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Make sure that we see any mutation to did_signal. This should be a no-op 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // since we expect that UnregisterWaitEx resulted in a memory barrier, but 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // just to be sure, we're going to be explicit. 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott MemoryBarrier(); 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If the watch has been posted, then we need to make sure it knows not to do 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // anything once it is run. 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watch_->watcher = NULL; 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If DoneWaiting was called, then the watch would have been posted as a 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // task, and will therefore be deleted by the MessageLoop. Otherwise, we 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // need to take care to delete it here. 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!watch_->did_signal) 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delete watch_; 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watch_ = NULL; 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott MessageLoop::current()->RemoveDestructionObserver(this); 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHANDLE ObjectWatcher::GetWatchedObject() { 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!watch_) 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return NULL; 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return watch_->object; 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// static 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) { 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!timed_out); 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Watch* watch = static_cast<Watch*>(param); 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Record that we ran this function. 125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watch->did_signal = true; 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We rely on the locking in PostTask() to ensure that a memory barrier is 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // provided, which in turn ensures our change to did_signal can be observed 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // on the target thread. 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watch->origin_loop->PostTask(FROM_HERE, watch); 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid ObjectWatcher::WillDestroyCurrentMessageLoop() { 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Need to shutdown the watch so that we don't try to access the MessageLoop 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // after this point. 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott StopWatching(); 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1393f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} // namespace win 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace base 141