tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

object_watcher.cc (4328B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
      4 // Use of this source code is governed by a BSD-style license that can be
      5 // found in the LICENSE file.
      6 
      7 #include "base/object_watcher.h"
      8 
      9 #include "base/logging.h"
     10 
     11 namespace base {
     12 
     13 //-----------------------------------------------------------------------------
     14 
     15 class ObjectWatcher::Watch : public mozilla::Runnable {
     16 public:
     17  ObjectWatcher* watcher;    // The associated ObjectWatcher instance
     18  HANDLE object;             // The object being watched
     19  HANDLE wait_object;        // Returned by RegisterWaitForSingleObject
     20  MessageLoop* origin_loop;  // Used to get back to the origin thread
     21  Delegate* delegate;        // Delegate to notify when signaled
     22  bool did_signal;           // DoneWaiting was called
     23 
     24  Watch() : mozilla::Runnable("ObjectWatcher::Watch") {}
     25 
     26  NS_IMETHOD Run() override {
     27    // The watcher may have already been torn down, in which case we need to
     28    // just get out of dodge.
     29    if (!watcher) return NS_OK;
     30 
     31    DCHECK(did_signal);
     32    watcher->StopWatching();
     33 
     34    delegate->OnObjectSignaled(object);
     35 
     36    return NS_OK;
     37  }
     38 };
     39 
     40 //-----------------------------------------------------------------------------
     41 
     42 ObjectWatcher::ObjectWatcher() : watch_(nullptr) {}
     43 
     44 ObjectWatcher::~ObjectWatcher() { StopWatching(); }
     45 
     46 bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {
     47  if (watch_) {
     48    NOTREACHED() << "Already watching an object";
     49    return false;
     50  }
     51 
     52  RefPtr<Watch> watch = new Watch;
     53  watch->watcher = this;
     54  watch->object = object;
     55  watch->origin_loop = MessageLoop::current();
     56  watch->delegate = delegate;
     57  watch->did_signal = false;
     58 
     59  // Since our job is to just notice when an object is signaled and report the
     60  // result back to this thread, we can just run on a Windows wait thread.
     61  DWORD wait_flags = WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE;
     62 
     63  if (!RegisterWaitForSingleObject(&watch->wait_object, object, DoneWaiting,
     64                                   watch.get(), INFINITE, wait_flags)) {
     65    NOTREACHED() << "RegisterWaitForSingleObject failed: " << GetLastError();
     66    return false;
     67  }
     68 
     69  watch_ = watch.forget();
     70 
     71  // We need to know if the current message loop is going away so we can
     72  // prevent the wait thread from trying to access a dead message loop.
     73  MessageLoop::current()->AddDestructionObserver(this);
     74  return true;
     75 }
     76 
     77 bool ObjectWatcher::StopWatching() {
     78  if (!watch_) 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  watch_ = nullptr;
    100 
    101  MessageLoop::current()->RemoveDestructionObserver(this);
    102  return true;
    103 }
    104 
    105 HANDLE ObjectWatcher::GetWatchedObject() {
    106  if (!watch_) return NULL;
    107 
    108  return watch_->object;
    109 }
    110 
    111 // static
    112 void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
    113  DCHECK(!timed_out);
    114 
    115  Watch* watch = static_cast<Watch*>(param);
    116  RefPtr<Watch> addrefedWatch = watch;
    117 
    118  // Record that we ran this function.
    119  watch->did_signal = true;
    120 
    121  // We rely on the locking in PostTask() to ensure that a memory barrier is
    122  // provided, which in turn ensures our change to did_signal can be observed
    123  // on the target thread.
    124  if (watch->origin_loop->IsAcceptingTasks()) {
    125    watch->origin_loop->PostTask(addrefedWatch.forget());
    126  }
    127 }
    128 
    129 void ObjectWatcher::WillDestroyCurrentMessageLoop() {
    130  // Need to shutdown the watch so that we don't try to access the MessageLoop
    131  // after this point.
    132  StopWatching();
    133 }
    134 
    135 }  // namespace base