Added (pretty limited) support for uncaught exceptions in coroutines.

This commit is contained in:
Patrick 2023-11-13 11:34:47 +01:00
parent dff7b30b2d
commit 0b8772c952

View File

@ -455,11 +455,15 @@ public:
std::function<void(StoredTask&)> setFuture; std::function<void(StoredTask&)> setFuture;
std::any resultData; std::any resultData;
}; };
using exception_handler_t = std::function<void(std::exception_ptr)>;
protected: protected:
using task_vector_t = std::vector<StoredTask>; using task_vector_t = std::vector<StoredTask>;
template<typename TTask> template<typename TTask>
using wrapped_task_ptr_t = std::unique_ptr<WrappedTask<TTask>>; using wrapped_task_ptr_t = std::unique_ptr<WrappedTask<TTask>>;
exception_handler_t uncaughtExceptionHandler_;
public: public:
TaskLoop() = default; TaskLoop() = default;
TaskLoop(const TaskLoop&) = delete; TaskLoop(const TaskLoop&) = delete;
@ -469,6 +473,8 @@ public:
TaskLoop& operator=(const TaskLoop&) = delete; TaskLoop& operator=(const TaskLoop&) = delete;
TaskLoop& operator=(TaskLoop&&) = delete; TaskLoop& operator=(TaskLoop&&) = delete;
void setUncaughtExceptionHandler(exception_handler_t handler) noexcept { uncaughtExceptionHandler_ = std::move(handler); }
template<typename TResult> template<typename TResult>
inline FuturePtr<TResult> addTask(TaskBase<TResult> task, TaskHandle* outHandle = nullptr) noexcept; inline FuturePtr<TResult> addTask(TaskBase<TResult> task, TaskHandle* outHandle = nullptr) noexcept;
@ -477,7 +483,7 @@ public:
[[nodiscard]] static TaskLoop& current() noexcept; [[nodiscard]] static TaskLoop& current() noexcept;
protected: protected:
inline TaskStatus tickTask(StoredTask& task) noexcept; inline TaskStatus tickTask(StoredTask& task);
protected: protected:
static inline TaskLoop*& currentLoopStorage() noexcept; static inline TaskLoop*& currentLoopStorage() noexcept;
template<typename TResult> template<typename TResult>
@ -502,8 +508,8 @@ public: // TaskLoop implementation
public: // public interface public: // public interface
[[nodiscard]] constexpr bool empty() const noexcept { return tasks_.empty() && newTasks_.empty(); } [[nodiscard]] constexpr bool empty() const noexcept { return tasks_.empty() && newTasks_.empty(); }
inline CanContinue tick() noexcept; inline CanContinue tick();
inline void runUntilDone(IgnoreWaiting ignoreWaiting = IgnoreWaiting::NO) noexcept; inline void runUntilDone(IgnoreWaiting ignoreWaiting = IgnoreWaiting::NO);
private: private:
inline void assertCorrectThread() { MIJIN_ASSERT(threadId_ == std::thread::id() || threadId_ == std::this_thread::get_id(), "Unsafe to TaskLoop from different thread!"); } inline void assertCorrectThread() { MIJIN_ASSERT(threadId_ == std::thread::id() || threadId_ == std::this_thread::get_id(), "Unsafe to TaskLoop from different thread!"); }
}; };
@ -582,7 +588,7 @@ inline FuturePtr<TResult> TaskLoop::addTask(TaskBase<TResult> task, TaskHandle*
return future; return future;
} }
inline TaskStatus TaskLoop::tickTask(StoredTask& task) noexcept inline TaskStatus TaskLoop::tickTask(StoredTask& task)
{ {
TaskStatus status = {}; TaskStatus status = {};
impl::gCurrentTask = &task; impl::gCurrentTask = &task;
@ -596,6 +602,23 @@ inline TaskStatus TaskLoop::tickTask(StoredTask& task) noexcept
if (task.task && task.task->exception()) if (task.task && task.task->exception())
{ {
try
{
std::rethrow_exception(task.task->exception());
}
catch(impl::TaskCancelled&) {} // ignore those
catch(...)
{
if (uncaughtExceptionHandler_)
{
uncaughtExceptionHandler_(std::current_exception());
}
else
{
throw;
}
}
// TODO: handle the exception somehow, others may be waiting // TODO: handle the exception somehow, others may be waiting
return TaskStatus::FINISHED; return TaskStatus::FINISHED;
} }
@ -644,7 +667,7 @@ inline std::suspend_always switchContext(TaskLoop& taskLoop)
return {}; return {};
} }
inline auto SimpleTaskLoop::tick() noexcept -> CanContinue inline auto SimpleTaskLoop::tick() -> CanContinue
{ {
// set current taskloop // set current taskloop
MIJIN_ASSERT(currentLoopStorage() == nullptr, "Trying to tick a loop from a coroutine, this is not supported."); MIJIN_ASSERT(currentLoopStorage() == nullptr, "Trying to tick a loop from a coroutine, this is not supported.");
@ -705,7 +728,7 @@ inline auto SimpleTaskLoop::tick() noexcept -> CanContinue
return canContinue; return canContinue;
} }
inline void SimpleTaskLoop::runUntilDone(IgnoreWaiting ignoreWaiting) noexcept inline void SimpleTaskLoop::runUntilDone(IgnoreWaiting ignoreWaiting)
{ {
while (!tasks_.empty() || !newTasks_.empty()) while (!tasks_.empty() || !newTasks_.empty())
{ {