From ebb9c3a4304e9860386189bc6ac43a11f84f6ec1 Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Sat, 18 Mar 2023 16:05:46 -0400 Subject: [PATCH] LibThreading: Execute `on_error` on the original `EventLoop` As the user might want to have interactions with LibGUI while handling errors, this code should be executed in the original `EventLoop`. Similarly to what is done with the error-free path. --- Userland/Libraries/LibGUI/FileSystemModel.cpp | 16 ++++++++++------ .../Libraries/LibThreading/BackgroundAction.h | 8 ++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Userland/Libraries/LibGUI/FileSystemModel.cpp b/Userland/Libraries/LibGUI/FileSystemModel.cpp index ee06238e94..99a8a8a50a 100644 --- a/Userland/Libraries/LibGUI/FileSystemModel.cpp +++ b/Userland/Libraries/LibGUI/FileSystemModel.cpp @@ -720,12 +720,16 @@ bool FileSystemModel::fetch_thumbnail_for(Node const& node) }; auto const on_error = [path](Error error) -> void { - s_thumbnail_cache.with_locked([path, error = move(error)](auto& cache) { - if (error != Error::from_errno(ECANCELED)) { - cache.thumbnail_cache.set(path, nullptr); - dbgln("Failed to load thumbnail for {}: {}", path, error); - } - cache.loading_thumbnails.remove(path); + // Note: We need to defer that to avoid the function removing its last reference + // i.e. trying to destroy itself, which is prohibited. + Core::EventLoop::current().deferred_invoke([&] { + s_thumbnail_cache.with_locked([path, error = move(error)](auto& cache) { + if (error != Error::from_errno(ECANCELED)) { + cache.thumbnail_cache.set(path, nullptr); + dbgln("Failed to load thumbnail for {}: {}", path, error); + } + cache.loading_thumbnails.remove(path); + }); }); }; diff --git a/Userland/Libraries/LibThreading/BackgroundAction.h b/Userland/Libraries/LibThreading/BackgroundAction.h index 02aa6b3408..1d12128f8e 100644 --- a/Userland/Libraries/LibThreading/BackgroundAction.h +++ b/Userland/Libraries/LibThreading/BackgroundAction.h @@ -98,8 +98,12 @@ private: error = result.release_error(); m_promise->cancel(Error::from_errno(ECANCELED)); - if (m_on_error) - m_on_error(move(error)); + if (m_on_error) { + origin_event_loop->deferred_invoke([this, error = move(error)]() mutable { + m_on_error(move(error)); + }); + origin_event_loop->wake(); + } remove_from_parent(); }