blob: 6d17c7b78696772ee0b3e787a36af7f3083e1aa2 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/public/cpp/bindings/sync_event_watcher.h"
#include <utility>
#include "base/check_op.h"
#include "base/containers/span.h"
#include "base/memory/scoped_refptr.h"
#include "base/synchronization/waitable_event.h"
#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
namespace mojo {
SyncEventWatcher::SyncEventWatcher(base::WaitableEvent* event,
base::RepeatingClosure callback)
: event_(event),
callback_(std::move(callback)),
registry_(SyncHandleRegistry::current()),
destroyed_(base::MakeRefCounted<base::RefCountedData<bool>>(false)) {}
SyncEventWatcher::~SyncEventWatcher() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
destroyed_->data = true;
}
void SyncEventWatcher::AllowWokenUpBySyncWatchOnSameThread() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
IncrementRegisterCount();
}
bool SyncEventWatcher::SyncWatch(
base::span<const bool*> stop_flags,
size_t spanification_suspected_redundant_num_stop_flags) {
// TODO(crbug.com/431824301): Remove unneeded parameter once validated to be
// redundant in M143.
CHECK(spanification_suspected_redundant_num_stop_flags == stop_flags.size(),
base::NotFatalUntil::M143);
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
IncrementRegisterCount();
// This object may be destroyed during the Wait() call. So we have to preserve
// the boolean that Wait uses.
auto destroyed = destroyed_;
constexpr size_t kFlagStackCapacity = 4;
absl::InlinedVector<const bool*, kFlagStackCapacity> should_stop_array;
should_stop_array.push_back(&destroyed->data);
std::copy(stop_flags.data(),
stop_flags.subspan(spanification_suspected_redundant_num_stop_flags)
.data(),
std::back_inserter(should_stop_array));
bool result = registry_->Wait(should_stop_array, should_stop_array.size());
// This object has been destroyed.
if (destroyed->data)
return false;
DecrementRegisterCount();
return result;
}
void SyncEventWatcher::IncrementRegisterCount() {
if (register_request_count_++ == 0)
subscription_ = registry_->RegisterEvent(event_, callback_);
}
void SyncEventWatcher::DecrementRegisterCount() {
DCHECK_GT(register_request_count_, 0u);
if (--register_request_count_ == 0)
subscription_.reset();
}
} // namespace mojo