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




commit dd51febbd06b3fa09ca0f601ed9b227f88df522b
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 ffb80ad9..482929f2 100644
--- a/gjs/promise.cpp
+++ b/gjs/promise.cpp
@@ -51,6 +51,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
@@ -76,7 +77,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;
     }
@@ -92,7 +95,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");
@@ -114,6 +118,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.
      */
@@ -124,7 +130,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 = {
@@ -148,9 +167,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]