Home | History | Annotate | Download | only in win
      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