ipc/chromium/src/base/object_watcher.cc

changeset 0
6474c204b198
     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

mercurial