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