blob: 29a0d7bf846e983bebe3fd1d5b6468af37302eb0 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/async/cpp/operation.h>
#include <utility>
#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
#include <lib/fxl/logging.h>
#include <trace/event.h>
namespace modular {
constexpr char kModularTraceCategory[] = "modular";
constexpr char kTraceIdKey[] = "id";
constexpr char kTraceInfoKey[] = "info";
OperationContainer::OperationContainer() = default;
OperationContainer::~OperationContainer() = default;
void OperationContainer::Add(OperationBase* const o) {
FXL_DCHECK(o != nullptr);
o->SetOwner(this);
Hold(o); // Takes ownership.
}
void OperationContainer::Schedule(OperationBase* const o) { o->Schedule(); }
void OperationContainer::InvalidateWeakPtrs(OperationBase* const o) {
o->InvalidateWeakPtrs();
}
OperationCollection::OperationCollection() : weak_ptr_factory_(this) {}
OperationCollection::~OperationCollection() {
// We invalidate weakptrs to all Operation<>s first before destroying them, so
// that an outstanding FlowToken<> that gets destroyed in the process doesn't
// erroneously call Operation<>::Done.
for (auto& operation : operations_) {
InvalidateWeakPtrs(operation.get());
}
}
fxl::WeakPtr<OperationContainer> OperationCollection::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void OperationCollection::Hold(OperationBase* const o) {
operations_.emplace_back(o);
Schedule(o);
}
void OperationCollection::Drop(OperationBase* const o) {
auto it = std::remove_if(
operations_.begin(), operations_.end(),
[o](const std::unique_ptr<OperationBase>& p) { return p.get() == o; });
FXL_DCHECK(it != operations_.end());
operations_.erase(it, operations_.end());
}
void OperationCollection::Cont() {
// no-op for operation collection.
}
OperationQueue::OperationQueue() : weak_ptr_factory_(this) {}
OperationQueue::~OperationQueue() {
// We invalidate weakptrs to all Operation<>s first before destroying them, so
// that an outstanding FlowToken<> that gets destroyed in the process doesn't
// erroneously call Operation<>::Done.
while (!operations_.empty()) {
InvalidateWeakPtrs(operations_.front().get());
operations_.pop();
}
}
fxl::WeakPtr<OperationContainer> OperationQueue::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void OperationQueue::Hold(OperationBase* const o) {
operations_.emplace(o);
if (idle_) {
FXL_DCHECK(operations_.size() == 1);
idle_ = false;
Schedule(o);
}
}
void OperationQueue::Drop(OperationBase* const o) {
FXL_DCHECK(!operations_.empty());
FXL_DCHECK(operations_.front().get() == o);
operations_.pop();
}
void OperationQueue::Cont() {
if (!operations_.empty()) {
auto o = operations_.front().get();
Schedule(o);
} else {
idle_ = true;
}
}
OperationBase::OperationBase(const char* const trace_name,
std::string trace_info)
// While we transition all operations to be explicitly added to containers
// with OperationContainer::Add(), some |c|'s are going to be null.
: weak_ptr_factory_(this),
trace_name_(trace_name),
trace_id_(TRACE_NONCE()),
trace_info_(std::move(trace_info)) {}
OperationBase::~OperationBase() = default;
fxl::WeakPtr<OperationBase> OperationBase::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void OperationBase::SetOwner(OperationContainer* c) {
FXL_DCHECK(!container_);
container_ = c->GetWeakPtr();
}
void OperationBase::Schedule() {
TraceAsyncBegin();
async::PostTask(async_get_default_dispatcher(),
[this, weak = weak_ptr_factory_.GetWeakPtr()] {
if (weak) {
Run();
}
});
}
void OperationBase::InvalidateWeakPtrs() {
weak_ptr_factory_.InvalidateWeakPtrs();
}
void OperationBase::TraceAsyncBegin() {
TRACE_ASYNC_BEGIN(kModularTraceCategory, trace_name_, trace_id_, kTraceIdKey,
trace_id_, kTraceInfoKey, trace_info_);
}
void OperationBase::TraceAsyncEnd() {
TRACE_ASYNC_END(kModularTraceCategory, trace_name_, trace_id_, kTraceIdKey,
trace_id_, kTraceInfoKey, trace_info_);
}
OperationBase::FlowTokenBase::FlowTokenBase(OperationBase* const op)
: refcount_(new int), weak_op_(op->weak_ptr_factory_.GetWeakPtr()) {
*refcount_ = 1;
}
OperationBase::FlowTokenBase::FlowTokenBase(const FlowTokenBase& other)
: refcount_(other.refcount_), weak_op_(other.weak_op_) {
++*refcount_;
}
OperationBase::FlowTokenBase::~FlowTokenBase() {
--*refcount_;
if (*refcount_ == 0) {
delete refcount_;
}
}
} // namespace modular