• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Runbase::ObjectWatcher::Watch21   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 
ObjectWatcher()36 ObjectWatcher::ObjectWatcher() : watch_(NULL) {
37 }
38 
~ObjectWatcher()39 ObjectWatcher::~ObjectWatcher() {
40   StopWatching();
41 }
42 
StartWatching(HANDLE object,Delegate * delegate)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 
StopWatching()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 
GetWatchedObject()110 HANDLE ObjectWatcher::GetWatchedObject() {
111   if (!watch_)
112     return NULL;
113 
114   return watch_->object;
115 }
116 
117 // static
DoneWaiting(void * param,BOOLEAN timed_out)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 
WillDestroyCurrentMessageLoop()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
139