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