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