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