[GTK] Use RunLoop in WorkQueue implementation
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Nov 2015 08:41:02 +0000 (08:41 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Nov 2015 08:41:02 +0000 (08:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150770

Reviewed by Darin Adler.

Source/WebKit2:

* Platform/IPC/unix/ConnectionUnix.cpp:
(IPC::Connection::open): Get the main context from the WorkQueue Runloop.

Source/WTF:

Instead of using GMainLoop directly. RunLoop already abstracts the
GMainLoop details and uses persistent sources making it more efficient.
For the dispatchAfter implementation we use a helper context class
and a GSource directly, since we are going to get rid of delete on
destroy GMainLoop soon and this is the only place where we still
use them.

* wtf/RunLoop.h:
(WTF::RunLoop::mainContext): Return the GMainContext.
* wtf/WorkQueue.h:
* wtf/glib/WorkQueueGLib.cpp:
(WTF::WorkQueue::platformInitialize): The RunLoop needs to be
created in the worker thread now, so we now use a mutex to wait
until the thread has started and the RunLoop has been created.
(WTF::WorkQueue::platformInvalidate): Stop the RunLoop and wait
until the thread finishes.
(WTF::WorkQueue::dispatch): Use RunLoop::dispatch().
(WTF::DispatchAfterContext::DispatchAfterContext):
(WTF::DispatchAfterContext::~DispatchAfterContext):
(WTF::DispatchAfterContext::dispatch):
(WTF::WorkQueue::dispatchAfter):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@191878 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WTF/ChangeLog
Source/WTF/wtf/RunLoop.h
Source/WTF/wtf/WorkQueue.h
Source/WTF/wtf/glib/WorkQueueGLib.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp

index 58b3c19a74b83adc7de89d2710d56ea9e6b40565..967c32f8af24199d488b74220cfcd4d550bda5ad 100644 (file)
@@ -1,3 +1,32 @@
+2015-11-01  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK] Use RunLoop in WorkQueue implementation
+        https://bugs.webkit.org/show_bug.cgi?id=150770
+
+        Reviewed by Darin Adler.
+
+        Instead of using GMainLoop directly. RunLoop already abstracts the
+        GMainLoop details and uses persistent sources making it more efficient.
+        For the dispatchAfter implementation we use a helper context class
+        and a GSource directly, since we are going to get rid of delete on
+        destroy GMainLoop soon and this is the only place where we still
+        use them.
+
+        * wtf/RunLoop.h:
+        (WTF::RunLoop::mainContext): Return the GMainContext.
+        * wtf/WorkQueue.h:
+        * wtf/glib/WorkQueueGLib.cpp:
+        (WTF::WorkQueue::platformInitialize): The RunLoop needs to be
+        created in the worker thread now, so we now use a mutex to wait
+        until the thread has started and the RunLoop has been created.
+        (WTF::WorkQueue::platformInvalidate): Stop the RunLoop and wait
+        until the thread finishes.
+        (WTF::WorkQueue::dispatch): Use RunLoop::dispatch().
+        (WTF::DispatchAfterContext::DispatchAfterContext):
+        (WTF::DispatchAfterContext::~DispatchAfterContext):
+        (WTF::DispatchAfterContext::dispatch):
+        (WTF::WorkQueue::dispatchAfter):
+
 2015-11-01  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [ES6] Support Generator Syntax
index 56ae6b1a726918384b92cd84ea4ce3e2bbeb8bb1..c84588760730628cf19b71b69fedb5f8d7a2cbbf 100644 (file)
@@ -67,7 +67,11 @@ public:
 #if PLATFORM(COCOA)
     WTF_EXPORT_PRIVATE void runForDuration(double duration);
 #endif
-    
+
+#if USE(GLIB) && !PLATFORM(EFL)
+    WTF_EXPORT_PRIVATE GMainContext* mainContext() const { return m_mainContext.get(); }
+#endif
+
     class TimerBase {
         friend class RunLoop;
     public:
index 51200bd8010e8c433d912da396a552452ce8d973..dda3cfdd01cfc12f9459935ee4198e952aaa425f 100644 (file)
@@ -39,7 +39,8 @@
 #endif
 
 #if PLATFORM(GTK)
-#include <wtf/glib/GMainLoopSource.h>
+#include <wtf/Condition.h>
+#include <wtf/RunLoop.h>
 #include <wtf/glib/GRefPtr.h>
 #elif PLATFORM(EFL)
 #include <DispatchQueueEfl.h>
@@ -74,7 +75,7 @@ public:
     WTF_EXPORT_PRIVATE static void concurrentApply(size_t iterations, const std::function<void (size_t index)>&);
 
 #if PLATFORM(GTK)
-    GMainContext* mainContext() const { return m_eventContext.get(); }
+    RunLoop& runLoop() const { return *m_runLoop; }
 #elif PLATFORM(EFL)
     void registerSocketEventHandler(int, std::function<void ()>);
     void unregisterSocketEventHandler(int);
@@ -103,8 +104,11 @@ private:
 
 #if PLATFORM(GTK)
     ThreadIdentifier m_workQueueThread;
-    GRefPtr<GMainContext> m_eventContext;
-    GRefPtr<GMainLoop> m_eventLoop;
+    Lock m_initializeRunLoopConditionMutex;
+    Condition m_initializeRunLoopCondition;
+    RunLoop* m_runLoop;
+    Lock m_terminateRunLoopConditionMutex;
+    Condition m_terminateRunLoopCondition;
 #elif PLATFORM(EFL)
     RefPtr<DispatchQueue> m_dispatchQueue;
 #elif OS(DARWIN)
index 39d3bf9311da6c61ffdec37c678f78f851b8f3e3..aea09730d3f531a3c9c0f5c05464071a72fb6c88 100644 (file)
@@ -37,11 +37,6 @@ static const size_t kVisualStudioThreadNameLimit = 31;
 
 void WorkQueue::platformInitialize(const char* name, Type, QOS)
 {
-    m_eventContext = adoptGRef(g_main_context_new());
-    ASSERT(m_eventContext);
-    m_eventLoop = adoptGRef(g_main_loop_new(m_eventContext.get(), FALSE));
-    ASSERT(m_eventLoop);
-
     // This name can be com.apple.WebKit.ProcessLauncher or com.apple.CoreIPC.ReceiveQueue.
     // We are using those names for the thread name, but both are longer than 31 characters,
     // which is the limit of Visual Studio for thread names.
@@ -55,47 +50,80 @@ void WorkQueue::platformInitialize(const char* name, Type, QOS)
     if (strlen(threadName) > kVisualStudioThreadNameLimit)
         threadName += strlen(threadName) - kVisualStudioThreadNameLimit;
 
-    GRefPtr<GMainLoop> eventLoop(m_eventLoop.get());
-    m_workQueueThread = createThread(threadName, [eventLoop] {
-        g_main_context_push_thread_default(g_main_loop_get_context(eventLoop.get()));
-        g_main_loop_run(eventLoop.get());
+    LockHolder locker(m_initializeRunLoopConditionMutex);
+    m_workQueueThread = createThread(threadName, [this] {
+        {
+            LockHolder locker(m_initializeRunLoopConditionMutex);
+            m_runLoop = &RunLoop::current();
+            m_initializeRunLoopCondition.notifyOne();
+        }
+        m_runLoop->run();
+        {
+            LockHolder locker(m_terminateRunLoopConditionMutex);
+            m_runLoop = nullptr;
+            m_terminateRunLoopCondition.notifyOne();
+        }
     });
+    m_initializeRunLoopCondition.wait(m_initializeRunLoopConditionMutex);
 }
 
 void WorkQueue::platformInvalidate()
 {
+    {
+        LockHolder locker(m_terminateRunLoopConditionMutex);
+        if (m_runLoop) {
+            m_runLoop->stop();
+            m_terminateRunLoopCondition.wait(m_terminateRunLoopConditionMutex);
+        }
+    }
+
     if (m_workQueueThread) {
         detachThread(m_workQueueThread);
         m_workQueueThread = 0;
     }
-
-    if (m_eventLoop) {
-        if (g_main_loop_is_running(m_eventLoop.get()))
-            g_main_loop_quit(m_eventLoop.get());
-        else {
-            // The thread hasn't started yet, so schedule a main loop quit to ensure the thread finishes.
-            GMainLoop* eventLoop = m_eventLoop.get();
-            GMainLoopSource::scheduleAndDeleteOnDestroy("[WebKit] WorkQueue quit main loop", [eventLoop] { g_main_loop_quit(eventLoop); },
-                G_PRIORITY_HIGH, nullptr, m_eventContext.get());
-        }
-        m_eventLoop = nullptr;
-    }
-
-    m_eventContext = nullptr;
 }
 
 void WorkQueue::dispatch(std::function<void ()> function)
 {
-    ref();
-    GMainLoopSource::scheduleAndDeleteOnDestroy("[WebKit] WorkQueue::dispatch", WTF::move(function), G_PRIORITY_DEFAULT,
-        [this] { deref(); }, m_eventContext.get());
+    RefPtr<WorkQueue> protector(this);
+    m_runLoop->dispatch([protector, function] { function(); });
 }
 
+class DispatchAfterContext {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    DispatchAfterContext(WorkQueue& queue, std::function<void ()> function)
+        : m_queue(&queue)
+        , m_function(WTF::move(function))
+    {
+    }
+
+    ~DispatchAfterContext()
+    {
+    }
+
+    void dispatch()
+    {
+        m_function();
+    }
+
+private:
+    RefPtr<WorkQueue> m_queue;
+    std::function<void ()> m_function;
+};
+
 void WorkQueue::dispatchAfter(std::chrono::nanoseconds duration, std::function<void ()> function)
 {
-    ref();
-    GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy("[WebKit] WorkQueue::dispatchAfter", WTF::move(function),
-        std::chrono::duration_cast<std::chrono::milliseconds>(duration), G_PRIORITY_DEFAULT, [this] { deref(); }, m_eventContext.get());
+    GRefPtr<GSource> source = adoptGRef(g_timeout_source_new(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count()));
+    g_source_set_name(source.get(), "[WebKit] WorkQueue dispatchAfter");
+
+    std::unique_ptr<DispatchAfterContext> context = std::make_unique<DispatchAfterContext>(*this, WTF::move(function));
+    g_source_set_callback(source.get(), [](gpointer userData) -> gboolean {
+        std::unique_ptr<DispatchAfterContext> context(static_cast<DispatchAfterContext*>(userData));
+        context->dispatch();
+        return G_SOURCE_REMOVE;
+    }, context.release(), nullptr);
+    g_source_attach(source.get(), m_runLoop->mainContext());
 }
 
 }
index 930fa1479fddca07c8c21b7a95bea79d8826a8ad..5914e3a068421c965479cf71ca431064523a5684 100644 (file)
@@ -1,3 +1,13 @@
+2015-11-01  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GTK] Use RunLoop in WorkQueue implementation
+        https://bugs.webkit.org/show_bug.cgi?id=150770
+
+        Reviewed by Darin Adler.
+
+        * Platform/IPC/unix/ConnectionUnix.cpp:
+        (IPC::Connection::open): Get the main context from the WorkQueue Runloop.
+
 2015-11-01  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [ES6] Support Generator Syntax
index 69da26f8b012b8d987ffec5557729c3e6206ec06..12ba1ffc41841b0e7d1053393e41b4271be296f3 100644 (file)
@@ -390,7 +390,7 @@ bool Connection::open()
 
         ASSERT_NOT_REACHED();
         return GMainLoopSource::Stop;
-    }, socket.get(), G_IO_IN, nullptr, m_connectionQueue->mainContext());
+    }, socket.get(), G_IO_IN, nullptr, m_connectionQueue->runLoop().mainContext());
 #elif PLATFORM(EFL)
     m_connectionQueue->registerSocketEventHandler(m_socketDescriptor,
         [protectedThis] {