blob: f9b0332d64b0238e8e6c4717a6703f0ac85cd18d [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, CrashCounter crash_counter,
size_t max_num_handlers, zx::duration exception_ttl)
: dispatcher_(dispatcher),
crash_counter_(std::move(crash_counter)),
exception_ttl_(exception_ttl) {
handlers_.reserve(max_num_handlers);
for (size_t i = 0; i < max_num_handlers; ++i) {
handlers_.emplace_back(
dispatcher_, /*log_moniker=*/
[crash_counter = &crash_counter_](const std::string& moniker) {
crash_counter->Increment(std::move(moniker));
},
/*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