瀏覽代碼

LibCore: Add Core::deferred_invoke_if(F, Condition)

This will invoke the function F only if the provided Condition is met,
otherwise the execution of the function F will be further deferred.
Ali Mohammad Pur 1 年之前
父節點
當前提交
a362c37c8b

+ 14 - 1
Userland/Libraries/LibCore/DeferredInvocationContext.h

@@ -13,8 +13,21 @@ namespace Core {
 
 class DeferredInvocationContext final : public Core::EventReceiver {
     C_OBJECT(DeferredInvocationContext)
+public:
+    bool should_invoke() const { return m_condition(); }
+
 private:
-    DeferredInvocationContext() = default;
+    DeferredInvocationContext()
+        : m_condition([] { return true; })
+    {
+    }
+
+    DeferredInvocationContext(Function<bool()> condition)
+        : m_condition(move(condition))
+    {
+    }
+
+    Function<bool()> m_condition;
 };
 
 }

+ 11 - 0
Userland/Libraries/LibCore/EventLoop.cpp

@@ -156,11 +156,22 @@ void EventLoop::deferred_invoke(Function<void()> invokee)
     post_event(context, make<Core::DeferredInvocationEvent>(context, move(invokee)));
 }
 
+void EventLoop::deferred_invoke_if(Function<void()> invokee, Function<bool()> condition)
+{
+    auto context = DeferredInvocationContext::construct(move(condition));
+    post_event(context, make<Core::DeferredInvocationEvent>(context, move(invokee)));
+}
+
 void deferred_invoke(Function<void()> invokee)
 {
     EventLoop::current().deferred_invoke(move(invokee));
 }
 
+void deferred_invoke_if(Function<void()> invokee, Function<bool()> condition)
+{
+    EventLoop::current().deferred_invoke_if(move(invokee), move(condition));
+}
+
 bool EventLoop::was_exit_requested() const
 {
     return m_impl->was_exit_requested();

+ 2 - 1
Userland/Libraries/LibCore/EventLoop.h

@@ -68,6 +68,7 @@ public:
     void add_job(NonnullRefPtr<Promise<NonnullRefPtr<EventReceiver>>> job_promise);
 
     void deferred_invoke(Function<void()>);
+    void deferred_invoke_if(Function<void()>, Function<bool()>);
 
     void wake();
 
@@ -102,5 +103,5 @@ private:
 };
 
 void deferred_invoke(Function<void()>);
-
+void deferred_invoke_if(Function<void()>, Function<bool()>);
 }

+ 7 - 1
Userland/Libraries/LibCore/ThreadEventQueue.cpp

@@ -84,6 +84,7 @@ void ThreadEventQueue::cancel_all_pending_jobs()
 size_t ThreadEventQueue::process()
 {
     decltype(m_private->queued_events) events;
+    decltype(m_private->queued_events) future_events;
     {
         Threading::MutexLocker locker(m_private->mutex);
         events = move(m_private->queued_events);
@@ -105,7 +106,10 @@ size_t ThreadEventQueue::process()
                 break;
             }
         } else if (event.type() == Event::Type::DeferredInvoke) {
-            static_cast<DeferredInvocationEvent&>(event).m_invokee();
+            if (static_cast<DeferredInvocationContext&>(*receiver).should_invoke())
+                static_cast<DeferredInvocationEvent&>(event).m_invokee();
+            else
+                future_events.append(move(queued_event));
         } else {
             NonnullRefPtr<EventReceiver> protector(*receiver);
             receiver->dispatch_event(event);
@@ -115,6 +119,8 @@ size_t ThreadEventQueue::process()
 
     {
         Threading::MutexLocker locker(m_private->mutex);
+        if (!future_events.is_empty())
+            m_private->queued_events.extend(move(future_events));
         if (m_private->pending_promises.size() > 30 && !m_private->warned_promise_count) {
             m_private->warned_promise_count = true;
             dbgln("ThreadEventQueue::process: Job queue wasn't designed for this load ({} promises)", m_private->pending_promises.size());