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