1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/base/object_watcher.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,138 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/object_watcher.h" 1.9 + 1.10 +#include "base/logging.h" 1.11 + 1.12 +namespace base { 1.13 + 1.14 +//----------------------------------------------------------------------------- 1.15 + 1.16 +struct ObjectWatcher::Watch : public Task { 1.17 + ObjectWatcher* watcher; // The associated ObjectWatcher instance 1.18 + HANDLE object; // The object being watched 1.19 + HANDLE wait_object; // Returned by RegisterWaitForSingleObject 1.20 + MessageLoop* origin_loop; // Used to get back to the origin thread 1.21 + Delegate* delegate; // Delegate to notify when signaled 1.22 + bool did_signal; // DoneWaiting was called 1.23 + 1.24 + virtual void Run() { 1.25 + // The watcher may have already been torn down, in which case we need to 1.26 + // just get out of dodge. 1.27 + if (!watcher) 1.28 + return; 1.29 + 1.30 + DCHECK(did_signal); 1.31 + watcher->StopWatching(); 1.32 + 1.33 + delegate->OnObjectSignaled(object); 1.34 + } 1.35 +}; 1.36 + 1.37 +//----------------------------------------------------------------------------- 1.38 + 1.39 +ObjectWatcher::ObjectWatcher() : watch_(NULL) { 1.40 +} 1.41 + 1.42 +ObjectWatcher::~ObjectWatcher() { 1.43 + StopWatching(); 1.44 +} 1.45 + 1.46 +bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) { 1.47 + if (watch_) { 1.48 + NOTREACHED() << "Already watching an object"; 1.49 + return false; 1.50 + } 1.51 + 1.52 + Watch* watch = new Watch; 1.53 + watch->watcher = this; 1.54 + watch->object = object; 1.55 + watch->origin_loop = MessageLoop::current(); 1.56 + watch->delegate = delegate; 1.57 + watch->did_signal = false; 1.58 + 1.59 + // Since our job is to just notice when an object is signaled and report the 1.60 + // result back to this thread, we can just run on a Windows wait thread. 1.61 + DWORD wait_flags = WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE; 1.62 + 1.63 + if (!RegisterWaitForSingleObject(&watch->wait_object, object, DoneWaiting, 1.64 + watch, INFINITE, wait_flags)) { 1.65 + NOTREACHED() << "RegisterWaitForSingleObject failed: " << GetLastError(); 1.66 + delete watch; 1.67 + return false; 1.68 + } 1.69 + 1.70 + watch_ = watch; 1.71 + 1.72 + // We need to know if the current message loop is going away so we can 1.73 + // prevent the wait thread from trying to access a dead message loop. 1.74 + MessageLoop::current()->AddDestructionObserver(this); 1.75 + return true; 1.76 +} 1.77 + 1.78 +bool ObjectWatcher::StopWatching() { 1.79 + if (!watch_) 1.80 + return false; 1.81 + 1.82 + // Make sure ObjectWatcher is used in a single-threaded fashion. 1.83 + DCHECK(watch_->origin_loop == MessageLoop::current()); 1.84 + 1.85 + // If DoneWaiting is in progress, we wait for it to finish. We know whether 1.86 + // DoneWaiting happened or not by inspecting the did_signal flag. 1.87 + if (!UnregisterWaitEx(watch_->wait_object, INVALID_HANDLE_VALUE)) { 1.88 + NOTREACHED() << "UnregisterWaitEx failed: " << GetLastError(); 1.89 + return false; 1.90 + } 1.91 + 1.92 + // Make sure that we see any mutation to did_signal. This should be a no-op 1.93 + // since we expect that UnregisterWaitEx resulted in a memory barrier, but 1.94 + // just to be sure, we're going to be explicit. 1.95 + MemoryBarrier(); 1.96 + 1.97 + // If the watch has been posted, then we need to make sure it knows not to do 1.98 + // anything once it is run. 1.99 + watch_->watcher = NULL; 1.100 + 1.101 + // If DoneWaiting was called, then the watch would have been posted as a 1.102 + // task, and will therefore be deleted by the MessageLoop. Otherwise, we 1.103 + // need to take care to delete it here. 1.104 + if (!watch_->did_signal) 1.105 + delete watch_; 1.106 + 1.107 + watch_ = NULL; 1.108 + 1.109 + MessageLoop::current()->RemoveDestructionObserver(this); 1.110 + return true; 1.111 +} 1.112 + 1.113 +HANDLE ObjectWatcher::GetWatchedObject() { 1.114 + if (!watch_) 1.115 + return NULL; 1.116 + 1.117 + return watch_->object; 1.118 +} 1.119 + 1.120 +// static 1.121 +void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) { 1.122 + DCHECK(!timed_out); 1.123 + 1.124 + Watch* watch = static_cast<Watch*>(param); 1.125 + 1.126 + // Record that we ran this function. 1.127 + watch->did_signal = true; 1.128 + 1.129 + // We rely on the locking in PostTask() to ensure that a memory barrier is 1.130 + // provided, which in turn ensures our change to did_signal can be observed 1.131 + // on the target thread. 1.132 + watch->origin_loop->PostTask(FROM_HERE, watch); 1.133 +} 1.134 + 1.135 +void ObjectWatcher::WillDestroyCurrentMessageLoop() { 1.136 + // Need to shutdown the watch so that we don't try to access the MessageLoop 1.137 + // after this point. 1.138 + StopWatching(); 1.139 +} 1.140 + 1.141 +} // namespace base