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 154 155 156 157 158 159 160 161 162 163
|
// 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"
#include "base/trace_event/trace_event.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.
{
// Measure the total cost of calling UnregisterWaitEx, including creation of
// and waiting on the event.
TRACE_EVENT("base", "UnregisterWaitEx");
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;
TRACE_EVENT("base", "RegisterWaitForSingleObject");
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
|