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