blob: 0d35fa77a76bc42692d072f6112dc6a5f8cbc127 [file] [log] [blame]
// Copyright 2017 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 "garnet/bin/cobalt/app/cobalt_controller_impl.h"
#include <memory>
#include <mutex>
#include <vector>
namespace cobalt {
using encoder::ShippingManager;
CobaltControllerImpl::CobaltControllerImpl(
async_dispatcher_t* dispatcher,
std::vector<encoder::ShippingManager*> shipping_managers)
: dispatcher_(dispatcher),
shipping_managers_(std::move(shipping_managers)) {}
// This struct is used in the method RequestSendSoon() below in order
// to coordinate the results of multiple callbacks. We invoke RequestSendSoon()
// on each ShippingManager, passing in a callback that accepts a success bool.
// When each of those callbacks have completed we invoke the FIDL callback
// on the main thread with the final result which is the conjunction of each
// of the success bools.
struct RequestSendSoonCoordinator {
explicit RequestSendSoonCoordinator(
size_t num_to_wait_for,
CobaltControllerImpl::RequestSendSoonCallback result_callback)
: callbacks_waiting(num_to_wait_for),
result_callback(std::move(result_callback)) {}
// How many callbacks are we waiting for?
const size_t callbacks_waiting;
// Protects all of the rest of the values of this struct.
std::mutex mu;
// Incremented when a callback completes.
size_t callbacks_completed = 0;
// Set to the conjuction of each of the callback's results.
bool result = true;
// This is the FIDL callback that should be invoked with the final result.
CobaltControllerImpl::RequestSendSoonCallback result_callback;
};
void CobaltControllerImpl::RequestSendSoon(RequestSendSoonCallback callback) {
std::shared_ptr<RequestSendSoonCoordinator> coordinator(
new RequestSendSoonCoordinator(shipping_managers_.size(),
std::move(callback)));
for (auto* shipping_manager : shipping_managers_) {
shipping_manager->RequestSendSoon([coordinator,
dispatcher = dispatcher_](bool s) {
std::lock_guard<std::mutex> lock(coordinator->mu);
coordinator->callbacks_completed++;
coordinator->result &= s;
if (coordinator->callbacks_completed == coordinator->callbacks_waiting) {
// Invoke the final result callback on the main thread.
async::PostTask(dispatcher,
[callback = std::move(coordinator->result_callback),
success = coordinator->result] { callback(success); });
}
});
}
}
void CobaltControllerImpl::BlockUntilEmpty(uint32_t max_wait_seconds,
BlockUntilEmptyCallback callback) {
for (auto* shipping_manager : shipping_managers_) {
shipping_manager->WaitUntilIdle(std::chrono::seconds(max_wait_seconds));
}
callback();
}
void CobaltControllerImpl::GetNumSendAttempts(
GetNumSendAttemptsCallback callback) {
int num_send_attempts = 0;
for (auto* shipping_manager : shipping_managers_) {
num_send_attempts += shipping_manager->num_send_attempts();
}
callback(num_send_attempts);
}
void CobaltControllerImpl::GetFailedSendAttempts(
GetFailedSendAttemptsCallback callback) {
int num_failed_attempts = 0;
for (auto* shipping_manager : shipping_managers_) {
num_failed_attempts += shipping_manager->num_failed_attempts();
}
callback(num_failed_attempts);
}
} // namespace cobalt