xref: /aosp_15_r20/external/cronet/base/win/object_watcher.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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