blob: 0fb37ddb3511f8d7dc230cecf93992477b3f74ec [file] [log] [blame]
// Copyright 2020 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 "src/developer/forensics/exceptions/handler_manager.h"
namespace forensics {
namespace exceptions {
HandlerManager::HandlerManager(async_dispatcher_t* dispatcher, size_t max_num_handlers,
zx::duration exception_ttl)
: dispatcher_(dispatcher), exception_ttl_(exception_ttl) {
handlers_.reserve(max_num_handlers);
for (size_t i = 0; i < max_num_handlers; ++i) {
handlers_.emplace_back(dispatcher_, /*on_available=*/[i, this] {
// Push to the front so already initialized handlers are used first.
available_handlers_.push_front(i);
HandleNextPendingException();
});
available_handlers_.emplace_back(i);
}
}
void HandlerManager::Handle(zx::exception exception) {
pending_exceptions_.emplace_back(dispatcher_, exception_ttl_, std::move(exception));
HandleNextPendingException();
}
void HandlerManager::HandleNextPendingException() {
if (pending_exceptions_.empty() || available_handlers_.empty()) {
return;
}
// We must reserve all state needed to handle the exception (the handler and the exception) and
// remove it from the queues prior to actually handling the exception. This is done to prevent
// that state from being erroneously being reused when ProcessHandler::Handle ends up calling
// HandleNextPendingException on a failure.
const size_t handler_idx = available_handlers_.front();
available_handlers_.pop_front();
zx::exception exception = pending_exceptions_.front().TakeException();
zx::process process = pending_exceptions_.front().TakeProcess();
zx::thread thread = pending_exceptions_.front().TakeThread();
pending_exceptions_.pop_front();
handlers_[handler_idx].Handle(std::move(exception), std::move(process), std::move(thread));
}
} // namespace exceptions
} // namespace forensics