[gjs/ewlsh/implicit-mainloop: 3/3] Promise: Replace the cancellable (and its source) on reset




commit 521b6cb1318085cd05684de95249de983b70ab8b
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Tue Sep 28 20:10:58 2021 +0200

    Promise: Replace the cancellable (and its source) on reset
    
    We only need to reset a cancellable in case this has been cancelled
    previously, in such case it's better not to use its native reset
    function though, as that may lead to undefined behaviors.
    
    It's instead safer to replace the cancellable with a new one.

 gjs/promise.cpp | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)
---
diff --git a/gjs/promise.cpp b/gjs/promise.cpp
index 0c7e2f46..6a197c48 100644
--- a/gjs/promise.cpp
+++ b/gjs/promise.cpp
@@ -44,6 +44,7 @@ class PromiseJobDispatcher::Source : public GSource {
     GjsAutoMainContext m_main_context;
     // The cancellable that stops this source.
     GjsAutoUnref<GCancellable> m_cancellable;
+    GjsAutoPointer<GSource, GSource, g_source_unref> m_cancellable_source;
 
     // G_PRIORITY_HIGH is -100, we set -1000 to ensure our source
     // always has the greatest priority. This means our prepare will
@@ -69,7 +70,9 @@ class PromiseJobDispatcher::Source : public GSource {
         g_source_set_ready_time(this, -1);
 
         // Drain the job queue.
-        m_gjs->runJobs(m_gjs->context(), m_cancellable);
+        GjsAutoUnref<GCancellable> cancellable(m_cancellable,
+                                               GjsAutoTakeOwnership());
+        m_gjs->runJobs(m_gjs->context(), cancellable);
 
         return G_SOURCE_CONTINUE;
     }
@@ -85,7 +88,8 @@ class PromiseJobDispatcher::Source : public GSource {
     Source(GjsContextPrivate* gjs, GMainContext* main_context)
         : m_gjs(gjs),
           m_main_context(main_context, GjsAutoTakeOwnership()),
-          m_cancellable(g_cancellable_new()) {
+          m_cancellable(g_cancellable_new()),
+          m_cancellable_source(g_cancellable_source_new(m_cancellable)) {
         g_source_set_priority(this, PRIORITY);
 #if GLIB_CHECK_VERSION(2, 70, 0)
         g_source_set_static_name(this, "GjsPromiseJobQueueSource");
@@ -107,6 +111,8 @@ class PromiseJobDispatcher::Source : public GSource {
     }
     void operator delete(void* p) { g_source_unref(static_cast<GSource*>(p)); }
 
+    bool is_running() { return !!g_source_get_context(this); }
+
     /**
      * @brief Trigger the cancellable, detaching our source.
      */
@@ -117,7 +123,20 @@ class PromiseJobDispatcher::Source : public GSource {
      * start() in PromiseQueueJobDispatcher to ensure the
      * custom source will start.
      */
-    void reset() { g_cancellable_reset(m_cancellable); }
+    void reset() {
+        if (!g_cancellable_is_cancelled(m_cancellable))
+            return;
+
+        if (is_running())
+            g_source_remove_child_source(this, m_cancellable_source);
+        else
+            g_source_destroy(m_cancellable_source);
+
+        m_cancellable = g_cancellable_new();
+        m_cancellable_source = g_cancellable_source_new(m_cancellable);
+        g_source_add_child_source(this, m_cancellable_source);
+        g_source_set_dummy_callback(m_cancellable_source);
+    }
 };
 
 GSourceFuncs PromiseJobDispatcher::Source::source_funcs = {
@@ -141,9 +160,7 @@ PromiseJobDispatcher::~PromiseJobDispatcher() {
     g_source_destroy(m_source.get());
 }
 
-bool PromiseJobDispatcher::is_running() {
-    return !!g_source_get_context(m_source.get());
-}
+bool PromiseJobDispatcher::is_running() { return m_source->is_running(); }
 
 void PromiseJobDispatcher::start() {
     // Reset the cancellable


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]