• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 <windows.h>
8 
9 #include "base/functional/bind.h"
10 #include "base/logging.h"
11 #include "base/task/sequenced_task_runner.h"
12 
13 namespace base {
14 namespace win {
15 
16 //-----------------------------------------------------------------------------
17 
18 ObjectWatcher::ObjectWatcher() = default;
19 
~ObjectWatcher()20 ObjectWatcher::~ObjectWatcher() {
21   StopWatching();
22 }
23 
StartWatchingOnce(HANDLE object,Delegate * delegate,const Location & from_here)24 bool ObjectWatcher::StartWatchingOnce(HANDLE object,
25                                       Delegate* delegate,
26                                       const Location& from_here) {
27   return StartWatchingInternal(object, delegate, true, from_here);
28 }
29 
StartWatchingMultipleTimes(HANDLE object,Delegate * delegate,const Location & from_here)30 bool ObjectWatcher::StartWatchingMultipleTimes(HANDLE object,
31                                                Delegate* delegate,
32                                                const Location& from_here) {
33   return StartWatchingInternal(object, delegate, false, from_here);
34 }
35 
StopWatching()36 bool ObjectWatcher::StopWatching() {
37   if (!wait_object_)
38     return false;
39 
40   // Make sure ObjectWatcher is used in a sequenced fashion.
41   DCHECK(task_runner_->RunsTasksInCurrentSequence());
42 
43   // Blocking call to cancel the wait. Any callbacks already in progress will
44   // finish before we return from this call.
45   if (!UnregisterWaitEx(wait_object_, INVALID_HANDLE_VALUE)) {
46     DPLOG(FATAL) << "UnregisterWaitEx failed";
47     return false;
48   }
49 
50   Reset();
51   return true;
52 }
53 
IsWatching() const54 bool ObjectWatcher::IsWatching() const {
55   return object_ != nullptr;
56 }
57 
GetWatchedObject() const58 HANDLE ObjectWatcher::GetWatchedObject() const {
59   return object_;
60 }
61 
62 // static
DoneWaiting(void * param,BOOLEAN timed_out)63 void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
64   DCHECK(!timed_out);
65 
66   // The destructor blocks on any callbacks that are in flight, so we know that
67   // that is always a pointer to a valid ObjectWater.
68   ObjectWatcher* that = static_cast<ObjectWatcher*>(param);
69   that->task_runner_->PostTask(that->location_, that->callback_);
70   if (that->run_once_)
71     that->callback_.Reset();
72 }
73 
StartWatchingInternal(HANDLE object,Delegate * delegate,bool execute_only_once,const Location & from_here)74 bool ObjectWatcher::StartWatchingInternal(HANDLE object,
75                                           Delegate* delegate,
76                                           bool execute_only_once,
77                                           const Location& from_here) {
78   DCHECK(delegate);
79   DCHECK(!wait_object_) << "Already watching an object";
80   DCHECK(SequencedTaskRunner::HasCurrentDefault());
81 
82   location_ = from_here;
83   task_runner_ = SequencedTaskRunner::GetCurrentDefault();
84 
85   run_once_ = execute_only_once;
86 
87   // Since our job is to just notice when an object is signaled and report the
88   // result back to this sequence, we can just run on a Windows wait thread.
89   DWORD wait_flags = WT_EXECUTEINWAITTHREAD;
90   if (run_once_)
91     wait_flags |= WT_EXECUTEONLYONCE;
92 
93   // DoneWaiting can be synchronously called from RegisterWaitForSingleObject,
94   // so set up all state now.
95   callback_ = BindRepeating(&ObjectWatcher::Signal, weak_factory_.GetWeakPtr(),
96                             // For all non-test usages, the delegate's lifetime
97                             // exceeds object_watcher's. This should be safe.
98                             base::UnsafeDanglingUntriaged(delegate));
99   object_ = object;
100 
101   if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting, this,
102                                    INFINITE, wait_flags)) {
103     DPLOG(FATAL) << "RegisterWaitForSingleObject failed";
104     Reset();
105     return false;
106   }
107 
108   return true;
109 }
110 
Signal(Delegate * delegate)111 void ObjectWatcher::Signal(Delegate* delegate) {
112   // Signaling the delegate may result in our destruction or a nested call to
113   // StartWatching(). As a result, we save any state we need and clear previous
114   // watcher state before signaling the delegate.
115   HANDLE object = object_;
116   if (run_once_)
117     StopWatching();
118   delegate->OnObjectSignaled(object);
119 }
120 
Reset()121 void ObjectWatcher::Reset() {
122   callback_.Reset();
123   location_ = {};
124   object_ = nullptr;
125   wait_object_ = nullptr;
126   task_runner_ = nullptr;
127   run_once_ = true;
128   weak_factory_.InvalidateWeakPtrs();
129 }
130 
131 }  // namespace win
132 }  // namespace base
133