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 <utility>
10
11 #include "base/functional/bind.h"
12 #include "base/logging.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/task/sequenced_task_runner.h"
15 #include "base/threading/thread_restrictions.h"
16
17 namespace base {
18 namespace win {
19
20 //-----------------------------------------------------------------------------
21
22 ObjectWatcher::ObjectWatcher() = default;
23
~ObjectWatcher()24 ObjectWatcher::~ObjectWatcher() {
25 StopWatching();
26 }
27
StartWatchingOnce(HANDLE object,Delegate * delegate,const Location & from_here)28 bool ObjectWatcher::StartWatchingOnce(HANDLE object,
29 Delegate* delegate,
30 const Location& from_here) {
31 return StartWatchingInternal(object, delegate, true, from_here);
32 }
33
StartWatchingMultipleTimes(HANDLE object,Delegate * delegate,const Location & from_here)34 bool ObjectWatcher::StartWatchingMultipleTimes(HANDLE object,
35 Delegate* delegate,
36 const Location& from_here) {
37 return StartWatchingInternal(object, delegate, false, from_here);
38 }
39
StopWatching()40 bool ObjectWatcher::StopWatching() {
41 if (!wait_object_)
42 return false;
43
44 // Make sure ObjectWatcher is used in a sequenced fashion.
45 DCHECK(task_runner_->RunsTasksInCurrentSequence());
46
47 // Allow blocking calls for historical reasons; see https://crbug.com/700335.
48 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_blocking;
49
50 // Cancel the wait; blocking on it being unregistered. Note that passing
51 // INVALID_HANDLE_VALUE to wait on all callback functions seemlingly waits
52 // on other callbacks in the threadpool; not just callbacks from
53 // RegisterWaitForSingleObject.
54 WaitableEvent event;
55 if (!UnregisterWaitEx(wait_object_, event.handle())) {
56 // ERROR_IO_PENDING is not a fatal error; see
57 // https://learn.microsoft.com/en-us/windows/win32/sync/unregisterwaitex.
58 if (const auto error = ::GetLastError(); error != ERROR_IO_PENDING) {
59 DPLOG(FATAL) << "UnregisterWaitEx failed";
60 return false;
61 }
62 }
63 // Wait for unregistration to complete.
64 event.Wait();
65 Reset();
66 return true;
67 }
68
IsWatching() const69 bool ObjectWatcher::IsWatching() const {
70 return object_ != nullptr;
71 }
72
GetWatchedObject() const73 HANDLE ObjectWatcher::GetWatchedObject() const {
74 return object_;
75 }
76
77 // static
DoneWaiting(void * param,BOOLEAN timed_out)78 void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
79 DCHECK(!timed_out);
80
81 // The destructor blocks on any callbacks that are in flight, so we know that
82 // that is always a pointer to a valid ObjectWater.
83 ObjectWatcher* that = static_cast<ObjectWatcher*>(param);
84
85 // `that` must not be touched once `PostTask` returns since the callback
86 // could delete the instance on another thread.
87 SequencedTaskRunner* const task_runner = that->task_runner_.get();
88 if (that->run_once_) {
89 task_runner->PostTask(that->location_, std::move(that->callback_));
90 } else {
91 task_runner->PostTask(that->location_, that->callback_);
92 }
93 }
94
StartWatchingInternal(HANDLE object,Delegate * delegate,bool execute_only_once,const Location & from_here)95 bool ObjectWatcher::StartWatchingInternal(HANDLE object,
96 Delegate* delegate,
97 bool execute_only_once,
98 const Location& from_here) {
99 DCHECK(delegate);
100 DCHECK(!wait_object_) << "Already watching an object";
101 DCHECK(SequencedTaskRunner::HasCurrentDefault());
102
103 location_ = from_here;
104 task_runner_ = SequencedTaskRunner::GetCurrentDefault();
105
106 run_once_ = execute_only_once;
107
108 // Since our job is to just notice when an object is signaled and report the
109 // result back to this sequence, we can just run on a Windows wait thread.
110 DWORD wait_flags = WT_EXECUTEINWAITTHREAD;
111 if (run_once_)
112 wait_flags |= WT_EXECUTEONLYONCE;
113
114 // DoneWaiting can be synchronously called from RegisterWaitForSingleObject,
115 // so set up all state now.
116 callback_ = BindRepeating(&ObjectWatcher::Signal, weak_factory_.GetWeakPtr(),
117 // For all non-test usages, the delegate's lifetime
118 // exceeds object_watcher's. This should be safe.
119 base::UnsafeDanglingUntriaged(delegate));
120 object_ = object;
121
122 if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting, this,
123 INFINITE, wait_flags)) {
124 DPLOG(FATAL) << "RegisterWaitForSingleObject failed";
125 Reset();
126 return false;
127 }
128
129 return true;
130 }
131
Signal(Delegate * delegate)132 void ObjectWatcher::Signal(Delegate* delegate) {
133 // Signaling the delegate may result in our destruction or a nested call to
134 // StartWatching(). As a result, we save any state we need and clear previous
135 // watcher state before signaling the delegate.
136 HANDLE object = object_;
137 if (run_once_)
138 StopWatching();
139 delegate->OnObjectSignaled(object);
140 }
141
Reset()142 void ObjectWatcher::Reset() {
143 callback_.Reset();
144 location_ = {};
145 object_ = nullptr;
146 wait_object_ = nullptr;
147 task_runner_ = nullptr;
148 run_once_ = true;
149 weak_factory_.InvalidateWeakPtrs();
150 }
151
152 } // namespace win
153 } // namespace base
154