Переглянути джерело

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.
Lucas CHOLLET 2 роки тому
батько
коміт
ebb9c3a430

+ 10 - 6
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);
+            });
         });
     };
 

+ 6 - 2
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();
             }