错误处理统一模式
This commit is contained in:
@@ -0,0 +1,51 @@
|
|||||||
|
#include "Error_Policy.hpp"
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
namespace renderive::error {
|
||||||
|
namespace {
|
||||||
|
Mode read_mode() noexcept {
|
||||||
|
const char* value = std::getenv("RENDERIVE_ERROR_MODE");
|
||||||
|
if (value && std::strcmp(value, "exception") == 0)
|
||||||
|
return Mode::exception;
|
||||||
|
return Mode::fast_fail;
|
||||||
|
}
|
||||||
|
void print_exception(std::exception_ptr exception) noexcept {
|
||||||
|
if (!exception)
|
||||||
|
return;
|
||||||
|
try {
|
||||||
|
std::rethrow_exception(exception);
|
||||||
|
} catch (const std::exception& value) {
|
||||||
|
std::fprintf(stderr, ": %s", value.what());
|
||||||
|
} catch (...) {
|
||||||
|
std::fprintf(stderr, ": unknown exception");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mode mode() noexcept {
|
||||||
|
static const Mode value = read_mode();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
[[noreturn]] void fast_fail(std::string_view message) noexcept {
|
||||||
|
std::fprintf(stderr, "Renderive unexpected error: %.*s\n", static_cast<int>(message.size()), message.data());
|
||||||
|
std::fflush(stderr);
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
[[noreturn]] void fast_fail(std::string_view context, std::exception_ptr exception) noexcept {
|
||||||
|
std::fprintf(stderr, "Renderive unexpected error");
|
||||||
|
if (!context.empty())
|
||||||
|
std::fprintf(stderr, " during %.*s", static_cast<int>(context.size()), context.data());
|
||||||
|
print_exception(exception);
|
||||||
|
std::fprintf(stderr, "\n");
|
||||||
|
std::fflush(stderr);
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
[[noreturn]] void unexpected(std::string_view context, std::exception_ptr exception) {
|
||||||
|
if (mode() == Mode::exception) {
|
||||||
|
if (exception)
|
||||||
|
std::rethrow_exception(exception);
|
||||||
|
throw std::runtime_error(context.empty() ? "Renderive unexpected error" : std::string(context));
|
||||||
|
}
|
||||||
|
fast_fail(context, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
namespace renderive::error {
|
||||||
|
enum class Mode {
|
||||||
|
fast_fail,
|
||||||
|
exception
|
||||||
|
};
|
||||||
|
[[nodiscard]] Mode mode() noexcept;
|
||||||
|
[[noreturn]] void fast_fail(std::string_view message) noexcept;
|
||||||
|
[[noreturn]] void fast_fail(std::string_view context, std::exception_ptr exception) noexcept;
|
||||||
|
[[noreturn]] void unexpected(std::string_view context, std::exception_ptr exception);
|
||||||
|
template <class Exception = std::runtime_error, class... Arguments>
|
||||||
|
[[noreturn]] void unexpected(Arguments&&... arguments) {
|
||||||
|
if (mode() == Mode::exception)
|
||||||
|
throw Exception(std::forward<Arguments>(arguments)...);
|
||||||
|
try {
|
||||||
|
Exception exception(std::forward<Arguments>(arguments)...);
|
||||||
|
fast_fail(exception.what());
|
||||||
|
} catch (...) {
|
||||||
|
fast_fail("Renderive unexpected error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "Scene_Base.hpp"
|
#include "Scene_Base.hpp"
|
||||||
|
#include "renderive/error/Error_Policy.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -86,7 +87,7 @@ public:
|
|||||||
const std::size_t queued = queued_.fetch_add(1, std::memory_order_relaxed) + 1;
|
const std::size_t queued = queued_.fetch_add(1, std::memory_order_relaxed) + 1;
|
||||||
update_peak(peak_queued_, queued);
|
update_peak(peak_queued_, queued);
|
||||||
if (!operations_.try_push(std::move(operation)))
|
if (!operations_.try_push(std::move(operation)))
|
||||||
std::terminate();
|
renderive::error::unexpected<std::logic_error>("scene execution queue rejected admitted operation");
|
||||||
schedule();
|
schedule();
|
||||||
}
|
}
|
||||||
void wait() noexcept {
|
void wait() noexcept {
|
||||||
@@ -1124,9 +1125,9 @@ const Frame_Control_Strategy_Base& Scene_Base::frame_control_strategy() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Scene_Base::bind_raster_capabilities(
|
void Scene_Base::bind_raster_capabilities(
|
||||||
renderive::scene::detail::Raster_Capabilities& capabilities) noexcept {
|
renderive::scene::detail::Raster_Capabilities& capabilities) {
|
||||||
if (raster_capabilities_ != nullptr)
|
if (raster_capabilities_ != nullptr)
|
||||||
std::terminate();
|
renderive::error::unexpected<std::logic_error>("scene raster capabilities are already bound");
|
||||||
raster_capabilities_ = &capabilities;
|
raster_capabilities_ = &capabilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ private:
|
|||||||
[[nodiscard]] Scene_Edit_Error validate_structure_locked() const;
|
[[nodiscard]] Scene_Edit_Error validate_structure_locked() const;
|
||||||
[[nodiscard]] Scene_Edit_Error cleanup_detached_topology_locked();
|
[[nodiscard]] Scene_Edit_Error cleanup_detached_topology_locked();
|
||||||
void bind_raster_capabilities(
|
void bind_raster_capabilities(
|
||||||
renderive::scene::detail::Raster_Capabilities& capabilities) noexcept;
|
renderive::scene::detail::Raster_Capabilities& capabilities);
|
||||||
|
|
||||||
inline static thread_local Scene_Base* active_execution_scene_{};
|
inline static thread_local Scene_Base* active_execution_scene_{};
|
||||||
inline static thread_local Scene_Base* active_renderable_edit_scene_{};
|
inline static thread_local Scene_Base* active_renderable_edit_scene_{};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "Gpu_Completion_Service.h"
|
#include "Gpu_Completion_Service.h"
|
||||||
|
#include "renderive/error/Error_Policy.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -27,13 +28,13 @@ Gpu_Completion_Service::Reservation::Reservation(Reservation&& other) noexcept
|
|||||||
void Gpu_Completion_Service::Reservation::watch(VkDevice device,
|
void Gpu_Completion_Service::Reservation::watch(VkDevice device,
|
||||||
VkFence fence) {
|
VkFence fence) {
|
||||||
if (!pending_ || device == VK_NULL_HANDLE || fence == VK_NULL_HANDLE)
|
if (!pending_ || device == VK_NULL_HANDLE || fence == VK_NULL_HANDLE)
|
||||||
throw std::logic_error("GPU completion reservation or fence is invalid");
|
renderive::error::unexpected<std::logic_error>("GPU completion reservation or fence is invalid");
|
||||||
auto pending = std::exchange(pending_, {});
|
auto pending = std::exchange(pending_, {});
|
||||||
auto* const service = pending->service;
|
auto* const service = pending->service;
|
||||||
{
|
{
|
||||||
std::lock_guard lock(pending->mutex);
|
std::lock_guard lock(pending->mutex);
|
||||||
if (pending->status != Pending_Fence::Status::reserved)
|
if (pending->status != Pending_Fence::Status::reserved)
|
||||||
throw std::logic_error("GPU completion reservation is not reserved");
|
renderive::error::unexpected<std::logic_error>("GPU completion reservation is not reserved");
|
||||||
pending->device = device;
|
pending->device = device;
|
||||||
pending->fence = fence;
|
pending->fence = fence;
|
||||||
// This timestamp is part of correctness, not only observability: it
|
// This timestamp is part of correctness, not only observability: it
|
||||||
@@ -92,7 +93,7 @@ void Gpu_Completion_Service::release_slot() noexcept {
|
|||||||
Gpu_Completion_Service::Prepare_Result Gpu_Completion_Service::prepare(
|
Gpu_Completion_Service::Prepare_Result Gpu_Completion_Service::prepare(
|
||||||
Completion completion, bool observe) {
|
Completion completion, bool observe) {
|
||||||
if (!completion)
|
if (!completion)
|
||||||
throw std::invalid_argument("GPU completion callback is empty");
|
renderive::error::unexpected<std::invalid_argument>("GPU completion callback is empty");
|
||||||
if (stopping_.load(std::memory_order_acquire))
|
if (stopping_.load(std::memory_order_acquire))
|
||||||
return {{}, Error::stopping};
|
return {{}, Error::stopping};
|
||||||
auto pending = std::make_shared<Pending_Fence>();
|
auto pending = std::make_shared<Pending_Fence>();
|
||||||
@@ -106,7 +107,7 @@ Gpu_Completion_Service::Prepare_Result Gpu_Completion_Service::prepare(
|
|||||||
}
|
}
|
||||||
if (!pending_.try_push(pending)) {
|
if (!pending_.try_push(pending)) {
|
||||||
release_slot();
|
release_slot();
|
||||||
throw std::logic_error("GPU completion admission invariant violated");
|
renderive::error::unexpected<std::logic_error>("GPU completion admission invariant violated");
|
||||||
}
|
}
|
||||||
wake();
|
wake();
|
||||||
return {Reservation(std::move(pending)), Error::none};
|
return {Reservation(std::move(pending)), Error::none};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "Render_Domain.h"
|
#include "Render_Domain.h"
|
||||||
|
#include "renderive/error/Error_Policy.hpp"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
namespace renderive::render_3d::detail {
|
namespace renderive::render_3d::detail {
|
||||||
@@ -69,7 +70,7 @@ void Render_Domain::request_stop() noexcept {
|
|||||||
return;
|
return;
|
||||||
slots_.acquire();
|
slots_.acquire();
|
||||||
if (!tasks_.try_push(std::unique_ptr<Task>{}))
|
if (!tasks_.try_push(std::unique_ptr<Task>{}))
|
||||||
std::terminate();
|
renderive::error::fast_fail("render domain stop marker queue rejected admitted task");
|
||||||
}
|
}
|
||||||
void Render_Domain::update_peak(std::atomic_size_t& peak, std::size_t value) noexcept {
|
void Render_Domain::update_peak(std::atomic_size_t& peak, std::size_t value) noexcept {
|
||||||
std::size_t current = peak.load(std::memory_order_relaxed);
|
std::size_t current = peak.load(std::memory_order_relaxed);
|
||||||
@@ -94,7 +95,7 @@ void Render_Domain::release_admission() noexcept {
|
|||||||
}
|
}
|
||||||
Render_Domain::Prepare_Result Render_Domain::prepare(std::function<void()> function) {
|
Render_Domain::Prepare_Result Render_Domain::prepare(std::function<void()> function) {
|
||||||
if (!function)
|
if (!function)
|
||||||
throw std::invalid_argument("render domain task is empty");
|
renderive::error::unexpected<std::invalid_argument>("render domain task is empty");
|
||||||
if (stopping_.load(std::memory_order_acquire))
|
if (stopping_.load(std::memory_order_acquire))
|
||||||
return {{}, Error::stopping};
|
return {{}, Error::stopping};
|
||||||
acquire_admission();
|
acquire_admission();
|
||||||
@@ -117,11 +118,11 @@ Render_Domain::Error Render_Domain::post(std::function<void()> function) {
|
|||||||
}
|
}
|
||||||
Render_Domain::Error Render_Domain::post(Prepared_Task task) {
|
Render_Domain::Error Render_Domain::post(Prepared_Task task) {
|
||||||
if (!task.task_ || task.domain_.get() != this)
|
if (!task.task_ || task.domain_.get() != this)
|
||||||
throw std::logic_error("render domain prepared task is invalid");
|
renderive::error::unexpected<std::logic_error>("render domain prepared task is invalid");
|
||||||
if (stopping_.load(std::memory_order_acquire))
|
if (stopping_.load(std::memory_order_acquire))
|
||||||
return Error::stopping;
|
return Error::stopping;
|
||||||
if (!tasks_.try_push(std::move(task.task_)))
|
if (!tasks_.try_push(std::move(task.task_)))
|
||||||
throw std::logic_error("render domain admission invariant violated");
|
renderive::error::unexpected<std::logic_error>("render domain admission invariant violated");
|
||||||
const std::size_t queued = queued_.fetch_add(1, std::memory_order_relaxed) + 1;
|
const std::size_t queued = queued_.fetch_add(1, std::memory_order_relaxed) + 1;
|
||||||
update_peak(peak_queued_, queued);
|
update_peak(peak_queued_, queued);
|
||||||
task.domain_.reset();
|
task.domain_.reset();
|
||||||
|
|||||||
Reference in New Issue
Block a user