[JSCOnly] Implement RunLoop and remove glib dependency
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Apr 2016 22:59:31 +0000 (22:59 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Apr 2016 22:59:31 +0000 (22:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=155706

Reviewed by Michael Catanzaro.

.:

* Source/cmake/OptionsJSCOnly.cmake:

Source/WTF:

Add missing RunLoop and WorkQueue platform code for JSCOnly port.
The implementation does not use platform specific things. Instead, we
implement them on WTF framework; using condition variables to construct
the run loop and timers.

Since the fallback is implemented, it is not necessary for JSCOnly port
to depend on GLib's RunLoop abstraction. So this patch removes its
dependency. As a result, now, JSCOnly port removes dependencies except for the system ICU.

We clean up event loop ifdefs by introducing USE_XXX_EVENT_LOOP flags.
USE(XXX_EVENT_LOOP) is exclusive to each other. So from now, we do not need to take care
of the order of if-defs for the event loops. (For example, USE(GLIB) should have lead before
OS(DARWIN) in WorkQueue.h for WebKitGTK on Darwin.)

EVENT_LOOP determination is done in Platform.h. This follows the style of WTF PLATFORM.

* wtf/Platform.h:
* wtf/PlatformJSCOnly.cmake:
* wtf/RunLoop.h:
* wtf/WorkQueue.h:
* wtf/generic/MainThreadGeneric.cpp: Renamed from Source/WTF/wtf/none/MainThreadNone.cpp.
(WTF::initializeMainThreadPlatform):
(WTF::scheduleDispatchFunctionsOnMainThread):
* wtf/generic/RunLoopGeneric.cpp: Added.
(WTF::RunLoop::TimerBase::ScheduledTask::create):
(WTF::RunLoop::TimerBase::ScheduledTask::ScheduledTask):
(WTF::RunLoop::TimerBase::ScheduledTask::fired):
(WTF::RunLoop::TimerBase::ScheduledTask::scheduledTimePoint):
(WTF::RunLoop::TimerBase::ScheduledTask::updateReadyTime):
(WTF::RunLoop::TimerBase::ScheduledTask::EarliestSchedule::operator()):
(WTF::RunLoop::TimerBase::ScheduledTask::isActive):
(WTF::RunLoop::TimerBase::ScheduledTask::deactivate):
(WTF::RunLoop::RunLoop):
(WTF::RunLoop::~RunLoop):
(WTF::RunLoop::populateTasks):
(WTF::RunLoop::runImpl):
(WTF::RunLoop::run):
(WTF::RunLoop::iterate):
(WTF::RunLoop::stop):
(WTF::RunLoop::wakeUp):
(WTF::RunLoop::schedule):
(WTF::RunLoop::scheduleAndWakeUp):
(WTF::RunLoop::dispatchAfter):
(WTF::RunLoop::TimerBase::TimerBase):
(WTF::RunLoop::TimerBase::~TimerBase):
(WTF::RunLoop::TimerBase::start):
(WTF::RunLoop::TimerBase::stop):
(WTF::RunLoop::TimerBase::isActive):
* wtf/generic/WorkQueueGeneric.cpp: Added.
(WorkQueue::platformInitialize):
(WorkQueue::platformInvalidate):
(WorkQueue::dispatch):
(WorkQueue::dispatchAfter):
* wtf/none/MainThreadNone.cpp:
(WTF::initializeMainThreadPlatform): Deleted.
(WTF::scheduleDispatchFunctionsOnMainThread): Deleted.
* wtf/none/RunLoopNone.cpp:
(WTF::RunLoop::RunLoop): Deleted.
(WTF::RunLoop::~RunLoop): Deleted.
(WTF::RunLoop::run): Deleted.
(WTF::RunLoop::stop): Deleted.
(WTF::RunLoop::wakeUp): Deleted.
(WTF::RunLoop::TimerBase::TimerBase): Deleted.
(WTF::RunLoop::TimerBase::~TimerBase): Deleted.
(WTF::RunLoop::TimerBase::start): Deleted.
(WTF::RunLoop::TimerBase::stop): Deleted.
(WTF::RunLoop::TimerBase::isActive): Deleted.
* wtf/none/WorkQueueNone.cpp:
(WorkQueue::platformInitialize): Deleted.
(WorkQueue::platformInvalidate): Deleted.
(WorkQueue::dispatch): Deleted.
(WorkQueue::dispatchAfter): Deleted.

Tools:

Add TestWTF to JSCOnly port to test WorkQueue and RunLoop.
Platform specific ones locate under jsconly directory since
it is not `generic` (Since it includes the GLIB event loop case).

* CMakeLists.txt:
* TestWebKitAPI/PlatformJSCOnly.cmake: Added.
* TestWebKitAPI/PlatformUtilities.h:
* TestWebKitAPI/Tests/WTF/RunLoop.cpp:
(TestWebKitAPI::TEST):
* TestWebKitAPI/config.h:
* TestWebKitAPI/jsconly/PlatformUtilitiesJSCOnly.cpp: Renamed from Source/WTF/wtf/none/RunLoopNone.cpp.
(TestWebKitAPI::Util::run):
(TestWebKitAPI::Util::sleep):
* TestWebKitAPI/jsconly/main.cpp: Renamed from Source/WTF/wtf/none/WorkQueueNone.cpp.
(main):

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

18 files changed:
ChangeLog
Source/WTF/ChangeLog
Source/WTF/wtf/Platform.h
Source/WTF/wtf/PlatformJSCOnly.cmake
Source/WTF/wtf/RunLoop.h
Source/WTF/wtf/WorkQueue.h
Source/WTF/wtf/generic/MainThreadGeneric.cpp [moved from Source/WTF/wtf/none/MainThreadNone.cpp with 89% similarity]
Source/WTF/wtf/generic/RunLoopGeneric.cpp [new file with mode: 0644]
Source/WTF/wtf/generic/WorkQueueGeneric.cpp [new file with mode: 0644]
Source/cmake/OptionsJSCOnly.cmake
Tools/CMakeLists.txt
Tools/ChangeLog
Tools/TestWebKitAPI/PlatformJSCOnly.cmake [new file with mode: 0644]
Tools/TestWebKitAPI/PlatformUtilities.h
Tools/TestWebKitAPI/Tests/WTF/RunLoop.cpp
Tools/TestWebKitAPI/config.h
Tools/TestWebKitAPI/jsconly/PlatformUtilitiesJSCOnly.cpp [moved from Source/WTF/wtf/none/RunLoopNone.cpp with 69% similarity]
Tools/TestWebKitAPI/jsconly/main.cpp [moved from Source/WTF/wtf/none/WorkQueueNone.cpp with 77% similarity]

index 06c7b40..1b4f5e6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2016-04-18  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSCOnly] Implement RunLoop and remove glib dependency
+        https://bugs.webkit.org/show_bug.cgi?id=155706
+
+        Reviewed by Michael Catanzaro.
+
+        * Source/cmake/OptionsJSCOnly.cmake:
+
 2016-04-18  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [GTK] Menu list button doesn't use the text color from the theme
index 31cd7c8..79288f8 100644 (file)
@@ -1,3 +1,83 @@
+2016-04-18  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSCOnly] Implement RunLoop and remove glib dependency
+        https://bugs.webkit.org/show_bug.cgi?id=155706
+
+        Reviewed by Michael Catanzaro.
+
+        Add missing RunLoop and WorkQueue platform code for JSCOnly port.
+        The implementation does not use platform specific things. Instead, we
+        implement them on WTF framework; using condition variables to construct
+        the run loop and timers.
+
+        Since the fallback is implemented, it is not necessary for JSCOnly port
+        to depend on GLib's RunLoop abstraction. So this patch removes its
+        dependency. As a result, now, JSCOnly port removes dependencies except for the system ICU.
+
+        We clean up event loop ifdefs by introducing USE_XXX_EVENT_LOOP flags.
+        USE(XXX_EVENT_LOOP) is exclusive to each other. So from now, we do not need to take care
+        of the order of if-defs for the event loops. (For example, USE(GLIB) should have lead before
+        OS(DARWIN) in WorkQueue.h for WebKitGTK on Darwin.)
+
+        EVENT_LOOP determination is done in Platform.h. This follows the style of WTF PLATFORM.
+
+        * wtf/Platform.h:
+        * wtf/PlatformJSCOnly.cmake:
+        * wtf/RunLoop.h:
+        * wtf/WorkQueue.h:
+        * wtf/generic/MainThreadGeneric.cpp: Renamed from Source/WTF/wtf/none/MainThreadNone.cpp.
+        (WTF::initializeMainThreadPlatform):
+        (WTF::scheduleDispatchFunctionsOnMainThread):
+        * wtf/generic/RunLoopGeneric.cpp: Added.
+        (WTF::RunLoop::TimerBase::ScheduledTask::create):
+        (WTF::RunLoop::TimerBase::ScheduledTask::ScheduledTask):
+        (WTF::RunLoop::TimerBase::ScheduledTask::fired):
+        (WTF::RunLoop::TimerBase::ScheduledTask::scheduledTimePoint):
+        (WTF::RunLoop::TimerBase::ScheduledTask::updateReadyTime):
+        (WTF::RunLoop::TimerBase::ScheduledTask::EarliestSchedule::operator()):
+        (WTF::RunLoop::TimerBase::ScheduledTask::isActive):
+        (WTF::RunLoop::TimerBase::ScheduledTask::deactivate):
+        (WTF::RunLoop::RunLoop):
+        (WTF::RunLoop::~RunLoop):
+        (WTF::RunLoop::populateTasks):
+        (WTF::RunLoop::runImpl):
+        (WTF::RunLoop::run):
+        (WTF::RunLoop::iterate):
+        (WTF::RunLoop::stop):
+        (WTF::RunLoop::wakeUp):
+        (WTF::RunLoop::schedule):
+        (WTF::RunLoop::scheduleAndWakeUp):
+        (WTF::RunLoop::dispatchAfter):
+        (WTF::RunLoop::TimerBase::TimerBase):
+        (WTF::RunLoop::TimerBase::~TimerBase):
+        (WTF::RunLoop::TimerBase::start):
+        (WTF::RunLoop::TimerBase::stop):
+        (WTF::RunLoop::TimerBase::isActive):
+        * wtf/generic/WorkQueueGeneric.cpp: Added.
+        (WorkQueue::platformInitialize):
+        (WorkQueue::platformInvalidate):
+        (WorkQueue::dispatch):
+        (WorkQueue::dispatchAfter):
+        * wtf/none/MainThreadNone.cpp:
+        (WTF::initializeMainThreadPlatform): Deleted.
+        (WTF::scheduleDispatchFunctionsOnMainThread): Deleted.
+        * wtf/none/RunLoopNone.cpp:
+        (WTF::RunLoop::RunLoop): Deleted.
+        (WTF::RunLoop::~RunLoop): Deleted.
+        (WTF::RunLoop::run): Deleted.
+        (WTF::RunLoop::stop): Deleted.
+        (WTF::RunLoop::wakeUp): Deleted.
+        (WTF::RunLoop::TimerBase::TimerBase): Deleted.
+        (WTF::RunLoop::TimerBase::~TimerBase): Deleted.
+        (WTF::RunLoop::TimerBase::start): Deleted.
+        (WTF::RunLoop::TimerBase::stop): Deleted.
+        (WTF::RunLoop::TimerBase::isActive): Deleted.
+        * wtf/none/WorkQueueNone.cpp:
+        (WorkQueue::platformInitialize): Deleted.
+        (WorkQueue::platformInvalidate): Deleted.
+        (WorkQueue::dispatch): Deleted.
+        (WorkQueue::dispatchAfter): Deleted.
+
 2016-04-18  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r199621.
index d290e74..f0b9b4d 100644 (file)
 #endif
 #endif
 
+
+#if !defined(WTF_DEFAULT_EVENT_LOOP)
+#define WTF_DEFAULT_EVENT_LOOP 1
+#endif
+
+#if WTF_DEFAULT_EVENT_LOOP
+#if PLATFORM(WIN)
+/* Use Windows message pump abstraction.
+ * Even if the port is AppleWin, we use the Windows message pump system for the event loop,
+ * so that USE(WINDOWS_EVENT_LOOP) && USE(CF) can be true.
+ * And PLATFORM(WIN), PLATFORM(EFL) and PLATFORM(GTK) are exclusive. If the port is GTK,
+ * PLATFORM(WIN) should be false. And in that case, GLib's event loop is used.
+ */
+#define USE_WINDOWS_EVENT_LOOP 1
+#elif PLATFORM(COCOA)
+/* OS X and IOS. Use CoreFoundation & GCD abstraction. */
+#define USE_COCOA_EVENT_LOOP 1
+#elif PLATFORM(EFL)
+/* EFL port uses GLib. But it uses its own event loop abstraction.
+ * Thus, USE(EFL_EVENT_LOOP) && USE(GLIB) can be true.
+ */
+#define USE_EFL_EVENT_LOOP 1
+#elif USE(GLIB)
+/* Use GLib's event loop abstraction. Primarily GTK port uses it. */
+#define USE_GLIB_EVENT_LOOP 1
+#else
+#define USE_GENERIC_EVENT_LOOP 1
+#endif
+#endif
+
 #endif /* WTF_Platform_h */
index 1aae46e..9c0a10c 100644 (file)
@@ -1,4 +1,4 @@
-if (LOWERCASE_EVENTLOOP_TYPE STREQUAL "glib")
+if (LOWERCASE_EVENT_LOOP_TYPE STREQUAL "glib")
     list(APPEND WTF_SOURCES
         glib/GRefPtr.cpp
         glib/MainThreadGLib.cpp
@@ -15,9 +15,9 @@ if (LOWERCASE_EVENTLOOP_TYPE STREQUAL "glib")
     )
 else ()
     list(APPEND WTF_SOURCES
-        none/MainThreadNone.cpp
-        none/RunLoopNone.cpp
-        none/WorkQueueNone.cpp
+        generic/MainThreadGeneric.cpp
+        generic/RunLoopGeneric.cpp
+        generic/WorkQueueGeneric.cpp
     )
 endif ()
 
index faeb9b1..fc85a2b 100644 (file)
@@ -28,6 +28,7 @@
 #ifndef RunLoop_h
 #define RunLoop_h
 
+#include <wtf/Condition.h>
 #include <wtf/Deque.h>
 #include <wtf/Forward.h>
 #include <wtf/FunctionDispatcher.h>
 #include <wtf/RetainPtr.h>
 #include <wtf/Threading.h>
 
-#if USE(GLIB)
+#if USE(GLIB_EVENT_LOOP)
 #include <wtf/glib/GRefPtr.h>
 #endif
 
-#if PLATFORM(EFL)
+#if USE(EFL_EVENT_LOOP)
 #include <Ecore.h>
 #include <wtf/efl/UniquePtrEfl.h>
 #endif
@@ -64,14 +65,20 @@ public:
     WTF_EXPORT_PRIVATE void stop();
     WTF_EXPORT_PRIVATE void wakeUp();
 
-#if PLATFORM(COCOA)
+#if USE(COCOA_EVENT_LOOP)
     WTF_EXPORT_PRIVATE void runForDuration(double duration);
 #endif
 
-#if USE(GLIB) && !PLATFORM(EFL)
+#if USE(GLIB_EVENT_LOOP)
     WTF_EXPORT_PRIVATE GMainContext* mainContext() const { return m_mainContext.get(); }
 #endif
 
+#if USE(GENERIC_EVENT_LOOP)
+    // Run the single iteration of the RunLoop. It consumes the pending tasks and expired timers, but it won't be blocked.
+    WTF_EXPORT_PRIVATE static void iterate();
+    WTF_EXPORT_PRIVATE void dispatchAfter(std::chrono::nanoseconds, std::function<void()>);
+#endif
+
     class TimerBase {
         friend class RunLoop;
     public:
@@ -87,7 +94,7 @@ public:
 
         virtual void fired() = 0;
 
-#if USE(GLIB) && !PLATFORM(EFL)
+#if USE(GLIB_EVENT_LOOP)
         void setPriority(int);
 #endif
 
@@ -96,22 +103,25 @@ public:
 
         RunLoop& m_runLoop;
 
-#if PLATFORM(WIN)
+#if USE(WINDOWS_EVENT_LOOP)
         static void timerFired(RunLoop*, uint64_t ID);
         uint64_t m_ID;
         bool m_isRepeating;
-#elif PLATFORM(COCOA)
+#elif USE(COCOA_EVENT_LOOP)
         static void timerFired(CFRunLoopTimerRef, void*);
         RetainPtr<CFRunLoopTimerRef> m_timer;
-#elif PLATFORM(EFL)
+#elif USE(EFL_EVENT_LOOP)
         static bool timerFired(void* data);
         Ecore_Timer* m_timer;
         bool m_isRepeating;
-#elif USE(GLIB)
+#elif USE(GLIB_EVENT_LOOP)
         void updateReadyTime();
         GRefPtr<GSource> m_source;
         bool m_isRepeating { false };
         std::chrono::microseconds m_fireInterval { 0 };
+#elif USE(GENERIC_EVENT_LOOP)
+        class ScheduledTask;
+        RefPtr<ScheduledTask> m_scheduledTask;
 #endif
     };
 
@@ -144,7 +154,7 @@ private:
     Mutex m_functionQueueLock;
     Deque<std::function<void ()>> m_functionQueue;
 
-#if PLATFORM(WIN)
+#if USE(WINDOWS_EVENT_LOOP)
     static bool registerRunLoopMessageWindowClass();
     static LRESULT CALLBACK RunLoopWndProc(HWND, UINT, WPARAM, LPARAM);
     LRESULT wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
@@ -152,12 +162,12 @@ private:
 
     typedef HashMap<uint64_t, TimerBase*> TimerMap;
     TimerMap m_activeTimers;
-#elif PLATFORM(COCOA)
+#elif USE(COCOA_EVENT_LOOP)
     static void performWork(void*);
     RetainPtr<CFRunLoopRef> m_runLoop;
     RetainPtr<CFRunLoopSourceRef> m_runLoopSource;
     int m_nestingLevel;
-#elif PLATFORM(EFL)
+#elif USE(EFL_EVENT_LOOP)
     Mutex m_pipeLock;
     EflUniquePtr<Ecore_Pipe> m_pipe;
 
@@ -165,10 +175,35 @@ private:
     bool m_wakeUpEventRequested;
 
     static void wakeUpEvent(void* data, void*, unsigned);
-#elif USE(GLIB)
+#elif USE(GLIB_EVENT_LOOP)
     GRefPtr<GMainContext> m_mainContext;
     Vector<GRefPtr<GMainLoop>> m_mainLoops;
     GRefPtr<GSource> m_source;
+#elif USE(GENERIC_EVENT_LOOP)
+    void schedule(RefPtr<TimerBase::ScheduledTask>&&);
+    void schedule(const LockHolder&, RefPtr<TimerBase::ScheduledTask>&&);
+    void wakeUp(const LockHolder&);
+    void scheduleAndWakeUp(RefPtr<TimerBase::ScheduledTask>);
+
+    enum class RunMode {
+        Iterate,
+        Drain
+    };
+
+    enum class Status {
+        Clear,
+        Stopping,
+    };
+    void runImpl(RunMode);
+    bool populateTasks(RunMode, Status&, Deque<RefPtr<TimerBase::ScheduledTask>>&);
+
+    Lock m_loopLock;
+    Condition m_readyToRun;
+    Condition m_stopCondition;
+    Vector<RefPtr<TimerBase::ScheduledTask>> m_schedules;
+    Vector<Status*> m_mainLoops;
+    bool m_shutdown { false };
+    bool m_pendingTasks { false };
 #endif
 };
 
index d2675c1..78cdac9 100644 (file)
 #include <wtf/RefCounted.h>
 #include <wtf/Threading.h>
 
-#if OS(DARWIN) && !PLATFORM(GTK)
+#if USE(COCOA_EVENT_LOOP)
 #include <dispatch/dispatch.h>
 #endif
 
-#if PLATFORM(EFL)
+#if USE(EFL_EVENT_LOOP)
 #include <DispatchQueueEfl.h>
-#elif USE(GLIB)
-#include <wtf/Condition.h>
-#include <wtf/RunLoop.h>
-#include <wtf/glib/GRefPtr.h>
-#elif OS(WINDOWS)
+#endif
+
+#if USE(WINDOWS_EVENT_LOOP)
 #include <wtf/HashMap.h>
 #include <wtf/Vector.h>
 #include <wtf/win/WorkItemWin.h>
 #endif
 
+#if USE(GLIB_EVENT_LOOP)
+#include <wtf/glib/GRefPtr.h>
+#endif
+
+#if USE(GLIB_EVENT_LOOP) || USE(GENERIC_EVENT_LOOP)
+#include <wtf/Condition.h>
+#include <wtf/RunLoop.h>
+#endif
+
 namespace WTF {
 
 class WorkQueue final : public FunctionDispatcher {
@@ -74,13 +81,13 @@ public:
 
     WTF_EXPORT_PRIVATE static void concurrentApply(size_t iterations, const std::function<void (size_t index)>&);
 
-#if PLATFORM(EFL)
+#if USE(EFL_EVENT_LOOP)
     void registerSocketEventHandler(int, std::function<void ()>);
     void unregisterSocketEventHandler(int);
-#elif USE(GLIB)
-    RunLoop& runLoop() const { return *m_runLoop; }
-#elif OS(DARWIN)
+#elif USE(COCOA_EVENT_LOOP)
     dispatch_queue_t dispatchQueue() const { return m_dispatchQueue; }
+#elif USE(GLIB_EVENT_LOOP) || USE(GENERIC_EVENT_LOOP)
+    RunLoop& runLoop() const { return *m_runLoop; }
 #endif
 
 private:
@@ -89,7 +96,7 @@ private:
     void platformInitialize(const char* name, Type, QOS);
     void platformInvalidate();
 
-#if OS(WINDOWS)
+#if USE(WINDOWS_EVENT_LOOP)
     static void CALLBACK handleCallback(void* context, BOOLEAN timerOrWaitFired);
     static void CALLBACK timerCallback(void* context, BOOLEAN timerOrWaitFired);
     static DWORD WINAPI workThreadCallback(void* context);
@@ -102,19 +109,12 @@ private:
     static DWORD WINAPI unregisterWaitAndDestroyItemCallback(void* context);
 #endif
 
-#if PLATFORM(EFL)
+#if USE(EFL_EVENT_LOOP)
     RefPtr<DispatchQueue> m_dispatchQueue;
-#elif USE(GLIB)
-    ThreadIdentifier m_workQueueThread;
-    Lock m_initializeRunLoopConditionMutex;
-    Condition m_initializeRunLoopCondition;
-    RunLoop* m_runLoop;
-    Lock m_terminateRunLoopConditionMutex;
-    Condition m_terminateRunLoopCondition;
-#elif OS(DARWIN)
+#elif USE(COCOA_EVENT_LOOP)
     static void executeFunction(void*);
     dispatch_queue_t m_dispatchQueue;
-#elif OS(WINDOWS)
+#elif USE(WINDOWS_EVENT_LOOP)
     volatile LONG m_isWorkThreadRegistered;
 
     Mutex m_workItemQueueLock;
@@ -124,6 +124,13 @@ private:
     HashMap<HANDLE, RefPtr<HandleWorkItem>> m_handles;
 
     HANDLE m_timerQueue;
+#elif USE(GLIB_EVENT_LOOP) || USE(GENERIC_EVENT_LOOP)
+    ThreadIdentifier m_workQueueThread;
+    Lock m_initializeRunLoopConditionMutex;
+    Condition m_initializeRunLoopCondition;
+    RunLoop* m_runLoop;
+    Lock m_terminateRunLoopConditionMutex;
+    Condition m_terminateRunLoopCondition;
 #endif
 };
 
similarity index 89%
rename from Source/WTF/wtf/none/MainThreadNone.cpp
rename to Source/WTF/wtf/generic/MainThreadGeneric.cpp
index e3cb6ba..c849c69 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2016 Konstantin Tokavev <annulen@yandex.ru>
+ * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,6 +27,8 @@
 #include "config.h"
 #include "MainThread.h"
 
+#include <wtf/RunLoop.h>
+
 namespace WTF {
 
 void initializeMainThreadPlatform()
@@ -34,6 +37,7 @@ void initializeMainThreadPlatform()
 
 void scheduleDispatchFunctionsOnMainThread()
 {
+    RunLoop::main().dispatch(std::function<void()>(dispatchFunctionsFromMainThread));
 }
 
 }
diff --git a/Source/WTF/wtf/generic/RunLoopGeneric.cpp b/Source/WTF/wtf/generic/RunLoopGeneric.cpp
new file mode 100644 (file)
index 0000000..81ee21a
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2016 Konstantin Tokavev <annulen@yandex.ru>
+ * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RunLoop.h"
+
+namespace WTF {
+
+class RunLoop::TimerBase::ScheduledTask : public ThreadSafeRefCounted<ScheduledTask> {
+WTF_MAKE_NONCOPYABLE(ScheduledTask);
+public:
+    template<typename Lambda>
+    static RefPtr<ScheduledTask> create(Lambda&& lambda, double interval, bool repeating)
+    {
+        return adoptRef(new ScheduledTask(std::forward<Lambda>(lambda), interval, repeating));
+    }
+
+    template<typename Lambda>
+    ScheduledTask(Lambda&& lambda, double interval, bool repeating)
+        : m_function(std::forward<Lambda>(lambda))
+        , m_fireInterval(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(interval)))
+        , m_isRepeating(repeating)
+    {
+        updateReadyTime();
+    }
+
+    bool fired()
+    {
+        if (!isActive())
+            return false;
+
+        m_function();
+
+        if (!m_isRepeating)
+            return false;
+
+        updateReadyTime();
+        return isActive();
+    }
+
+    Condition::Clock::time_point scheduledTimePoint() const
+    {
+        return m_scheduledTimePoint;
+    }
+
+    void updateReadyTime()
+    {
+        m_scheduledTimePoint = Condition::Clock::now();
+        if (!m_fireInterval.count())
+            return;
+        m_scheduledTimePoint += m_fireInterval;
+    }
+
+    struct EarliestSchedule {
+        bool operator()(const RefPtr<ScheduledTask>& lhs, const RefPtr<ScheduledTask>& rhs)
+        {
+            return lhs->scheduledTimePoint() > rhs->scheduledTimePoint();
+        }
+    };
+
+    bool isActive() const
+    {
+        return m_isActive.load();
+    }
+
+    void deactivate()
+    {
+        m_isActive.store(false);
+    }
+
+private:
+    std::function<void()> m_function;
+    Condition::Clock::time_point m_scheduledTimePoint;
+    std::chrono::microseconds m_fireInterval;
+    std::atomic<bool> m_isActive { true };
+    bool m_isRepeating;
+};
+
+RunLoop::RunLoop()
+{
+}
+
+RunLoop::~RunLoop()
+{
+    LockHolder locker(m_loopLock);
+    m_shutdown = true;
+    m_readyToRun.notifyOne();
+
+    // Here is running main loops. Wait until all the main loops are destroyed.
+    if (!m_mainLoops.isEmpty())
+        m_stopCondition.wait(m_loopLock);
+}
+
+inline bool RunLoop::populateTasks(RunMode runMode, Status& statusOfThisLoop, Deque<RefPtr<TimerBase::ScheduledTask>>& firedTimers)
+{
+    LockHolder locker(m_loopLock);
+
+    if (runMode == RunMode::Drain) {
+        Condition::Clock::time_point sleepUntil = Condition::Clock::time_point::max();
+        if (!m_schedules.isEmpty())
+            sleepUntil = m_schedules.first()->scheduledTimePoint();
+
+        m_readyToRun.waitUntil(m_loopLock, sleepUntil, [&] {
+            return m_shutdown || m_pendingTasks || statusOfThisLoop == Status::Stopping;
+        });
+    }
+
+    if (statusOfThisLoop == Status::Stopping || m_shutdown) {
+        m_mainLoops.removeLast();
+        if (m_mainLoops.isEmpty())
+            m_stopCondition.notifyOne();
+        return false;
+    }
+    m_pendingTasks = false;
+    if (runMode == RunMode::Iterate)
+        statusOfThisLoop = Status::Stopping;
+
+    // Check expired timers.
+    Condition::Clock::time_point now = Condition::Clock::now();
+    while (!m_schedules.isEmpty()) {
+        RefPtr<TimerBase::ScheduledTask> earliest = m_schedules.first();
+        if (earliest->scheduledTimePoint() > now)
+            break;
+        std::pop_heap(m_schedules.begin(), m_schedules.end(), TimerBase::ScheduledTask::EarliestSchedule());
+        m_schedules.removeLast();
+        firedTimers.append(earliest);
+    }
+
+    return true;
+}
+
+void RunLoop::runImpl(RunMode runMode)
+{
+    ASSERT(this == &RunLoop::current());
+
+    Status statusOfThisLoop = Status::Clear;
+    {
+        LockHolder locker(m_loopLock);
+        m_mainLoops.append(&statusOfThisLoop);
+    }
+
+    Deque<RefPtr<TimerBase::ScheduledTask>> firedTimers;
+    while (true) {
+        if (!populateTasks(runMode, statusOfThisLoop, firedTimers))
+            return;
+
+        // Dispatch scheduled timers.
+        while (!firedTimers.isEmpty()) {
+            RefPtr<TimerBase::ScheduledTask> task = firedTimers.takeFirst();
+            if (task->fired()) {
+                // Reschedule because the timer requires repeating.
+                // Since we will query the timers' time points before sleeping,
+                // we do not call wakeUp() here.
+                schedule(WTFMove(task));
+            }
+        }
+        performWork();
+    }
+}
+
+void RunLoop::run()
+{
+    RunLoop::current().runImpl(RunMode::Drain);
+}
+
+void RunLoop::iterate()
+{
+    RunLoop::current().runImpl(RunMode::Iterate);
+}
+
+// RunLoop operations are thread-safe. These operations can be called from outside of the RunLoop's thread.
+// For example, WorkQueue::{dispatch, dispatchAfter} call the operations of the WorkQueue thread's RunLoop
+// from the caller's thread.
+
+void RunLoop::stop()
+{
+    LockHolder locker(m_loopLock);
+    if (m_mainLoops.isEmpty())
+        return;
+
+    Status* status = m_mainLoops.last();
+    if (*status != Status::Stopping) {
+        *status = Status::Stopping;
+        m_readyToRun.notifyOne();
+    }
+}
+
+void RunLoop::wakeUp(const LockHolder&)
+{
+    m_pendingTasks = true;
+    m_readyToRun.notifyOne();
+}
+
+void RunLoop::wakeUp()
+{
+    LockHolder locker(m_loopLock);
+    wakeUp(locker);
+}
+
+void RunLoop::schedule(const LockHolder&, RefPtr<TimerBase::ScheduledTask>&& task)
+{
+    m_schedules.append(WTFMove(task));
+    std::push_heap(m_schedules.begin(), m_schedules.end(), TimerBase::ScheduledTask::EarliestSchedule());
+}
+
+void RunLoop::schedule(RefPtr<TimerBase::ScheduledTask>&& task)
+{
+    LockHolder locker(m_loopLock);
+    schedule(locker, WTFMove(task));
+}
+
+void RunLoop::scheduleAndWakeUp(RefPtr<TimerBase::ScheduledTask> task)
+{
+    LockHolder locker(m_loopLock);
+    schedule(locker, WTFMove(task));
+    wakeUp(locker);
+}
+
+void RunLoop::dispatchAfter(std::chrono::nanoseconds delay, std::function<void()> function)
+{
+    LockHolder locker(m_loopLock);
+    bool repeating = false;
+    schedule(locker, TimerBase::ScheduledTask::create(function, delay.count() / 1000.0 / 1000.0 / 1000.0, repeating));
+    wakeUp(locker);
+}
+
+// Since RunLoop does not own the registered TimerBase,
+// TimerBase and its owner should manage these lifetime.
+//
+// And more importantly, TimerBase operations are not thread-safe.
+// So threads that do not belong to the ScheduledTask's RunLoop
+// should not operate the RunLoop::TimerBase.
+// This is the same to the RunLoopWin, which is RunLoop for Windows.
+RunLoop::TimerBase::TimerBase(RunLoop& runLoop)
+    : m_runLoop(runLoop)
+    , m_scheduledTask(nullptr)
+{
+}
+
+RunLoop::TimerBase::~TimerBase()
+{
+    stop();
+}
+
+void RunLoop::TimerBase::start(double interval, bool repeating)
+{
+    stop();
+    m_scheduledTask = ScheduledTask::create([this] {
+        fired();
+    }, interval, repeating);
+    m_runLoop.scheduleAndWakeUp(m_scheduledTask);
+}
+
+void RunLoop::TimerBase::stop()
+{
+    if (m_scheduledTask) {
+        m_scheduledTask->deactivate();
+        m_scheduledTask = nullptr;
+    }
+}
+
+bool RunLoop::TimerBase::isActive() const
+{
+    return m_scheduledTask;
+}
+
+} // namespace WTF
diff --git a/Source/WTF/wtf/generic/WorkQueueGeneric.cpp b/Source/WTF/wtf/generic/WorkQueueGeneric.cpp
new file mode 100644 (file)
index 0000000..e1b6c4b
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 Konstantin Tokavev <annulen@yandex.ru>
+ * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>
+ * Copyright (C) 2011 Igalia S.L.
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WorkQueue.h"
+
+#include <wtf/text/WTFString.h>
+
+static const size_t kVisualStudioThreadNameLimit = 31;
+
+void WorkQueue::platformInitialize(const char* name, Type, QOS)
+{
+    // 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.
+    // When log is enabled createThread() will assert instead of truncate the name, so we need
+    // to make sure we don't use a name longer than 31 characters.
+    String threadName(name);
+    size_t size = threadName.reverseFind('.');
+    if (size != notFound)
+        threadName = threadName.substring(size + 1);
+    if (threadName.length() > kVisualStudioThreadNameLimit)
+        threadName = threadName.right(kVisualStudioThreadNameLimit);
+
+    LockHolder locker(m_initializeRunLoopConditionMutex);
+    m_workQueueThread = createThread(threadName.ascii().data(), [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;
+    }
+}
+
+void WorkQueue::dispatch(std::function<void()> function)
+{
+    RefPtr<WorkQueue> protect(this);
+    m_runLoop->dispatch([protect, function] {
+        function();
+    });
+}
+
+void WorkQueue::dispatchAfter(std::chrono::nanoseconds delay, std::function<void()> function)
+{
+    RefPtr<WorkQueue> protect(this);
+    m_runLoop->dispatchAfter(delay, [protect, function] {
+        function();
+    });
+}
index 4d5677e..de649c4 100644 (file)
@@ -11,24 +11,19 @@ WEBKIT_OPTION_DEFINE(ENABLE_STATIC_JSC "Whether to build JavaScriptCore as a sta
 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FTL_JIT PUBLIC ON)
 WEBKIT_OPTION_END()
 
-set(ALL_EVENTLOOP_TYPES
+set(ALL_EVENT_LOOP_TYPES
     GLib
-    None
+    Generic
 )
 
-if (UNIX AND NOT APPLE)
-    set(DEFAULT_EVENTLOOP_TYPE "GLib")
-else ()
-    # TODO: Use native Mac and Win implementations
-    set(DEFAULT_EVENTLOOP_TYPE "None")
-endif ()
+set(DEFAULT_EVENT_LOOP_TYPE "Generic")
 
-set(EVENTLOOP_TYPE ${DEFAULT_EVENTLOOP_TYPE} CACHE STRING "Implementation of event loop to be used in JavaScriptCore (one of ${ALL_EVENTLOOP_TYPES})")
+set(EVENT_LOOP_TYPE ${DEFAULT_EVENT_LOOP_TYPE} CACHE STRING "Implementation of event loop to be used in JavaScriptCore (one of ${ALL_EVENT_LOOP_TYPES})")
 
 set(ENABLE_WEBCORE OFF)
 set(ENABLE_WEBKIT OFF)
 set(ENABLE_WEBKIT2 OFF)
-set(ENABLE_API_TESTS OFF)
+set(ENABLE_API_TESTS ON)
 
 if (WTF_CPU_X86 OR WTF_CPU_X86_64)
     SET_AND_EXPOSE_TO_BUILD(USE_UDIS86 1)
@@ -38,10 +33,15 @@ if (ENABLE_STATIC_JSC)
     set(JavaScriptCore_LIBRARY_TYPE STATIC)
 endif ()
 
-string(TOLOWER ${EVENTLOOP_TYPE} LOWERCASE_EVENTLOOP_TYPE)
-if (LOWERCASE_EVENTLOOP_TYPE STREQUAL "glib")
+string(TOLOWER ${EVENT_LOOP_TYPE} LOWERCASE_EVENT_LOOP_TYPE)
+if (LOWERCASE_EVENT_LOOP_TYPE STREQUAL "glib")
     find_package(GLIB 2.36 REQUIRED COMPONENTS gio gobject)
     SET_AND_EXPOSE_TO_BUILD(USE_GLIB 1)
+    SET_AND_EXPOSE_TO_BUILD(USE_GLIB_EVENT_LOOP 1)
+    SET_AND_EXPOSE_TO_BUILD(WTF_DEFAULT_EVENT_LOOP 0)
+else ()
+    SET_AND_EXPOSE_TO_BUILD(USE_GENERIC_EVENT_LOOP 1)
+    SET_AND_EXPOSE_TO_BUILD(WTF_DEFAULT_EVENT_LOOP 0)
 endif ()
 
 # From OptionsGTK.cmake
index a9e79df..4b2edb8 100644 (file)
@@ -31,6 +31,10 @@ elseif ("${PORT}" STREQUAL "Mac")
     add_subdirectory(DumpRenderTree)
     add_subdirectory(WebKitTestRunner)
     add_subdirectory(MiniBrowser/mac)
+elseif ("${PORT}" STREQUAL "JSCOnly")
+    if (ENABLE_API_TESTS)
+        add_subdirectory(TestWebKitAPI)
+    endif ()
 endif ()
 
 if (WIN32)
index 04fc503..d711e48 100644 (file)
@@ -1,3 +1,26 @@
+2016-04-18  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSCOnly] Implement RunLoop and remove glib dependency
+        https://bugs.webkit.org/show_bug.cgi?id=155706
+
+        Reviewed by Michael Catanzaro.
+
+        Add TestWTF to JSCOnly port to test WorkQueue and RunLoop.
+        Platform specific ones locate under jsconly directory since
+        it is not `generic` (Since it includes the GLIB event loop case).
+
+        * CMakeLists.txt:
+        * TestWebKitAPI/PlatformJSCOnly.cmake: Added.
+        * TestWebKitAPI/PlatformUtilities.h:
+        * TestWebKitAPI/Tests/WTF/RunLoop.cpp:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/config.h:
+        * TestWebKitAPI/jsconly/PlatformUtilitiesJSCOnly.cpp: Renamed from Source/WTF/wtf/none/RunLoopNone.cpp.
+        (TestWebKitAPI::Util::run):
+        (TestWebKitAPI::Util::sleep):
+        * TestWebKitAPI/jsconly/main.cpp: Renamed from Source/WTF/wtf/none/WorkQueueNone.cpp.
+        (main):
+
 2016-04-18  Jon Lee  <jonlee@apple.com>
 
         Update Animometer plan.
diff --git a/Tools/TestWebKitAPI/PlatformJSCOnly.cmake b/Tools/TestWebKitAPI/PlatformJSCOnly.cmake
new file mode 100644 (file)
index 0000000..d7e3cc7
--- /dev/null
@@ -0,0 +1,27 @@
+set(TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/TestWebKitAPI")
+set(TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY_WTF "${TESTWEBKITAPI_RUNTIME_OUTPUT_DIRECTORY}/WTF")
+
+# This is necessary because JSCOnly port does not support WebCore, WebKit and WebKit2.
+# To build TestWTF, we need this flag not to include WebKit related headers except
+# for WTF and JavaScriptCore.
+add_definitions(-DBUILDING_JSCONLY__)
+
+include_directories(
+    ${DERIVED_SOURCES_DIR}/ForwardingHeaders
+    "${WTF_DIR}/icu"
+)
+
+if (LOWERCASE_EVENT_LOOP_TYPE STREQUAL "glib")
+    include_directories(SYSTEM
+        ${GLIB_INCLUDE_DIRS}
+    )
+endif ()
+
+set(test_main_SOURCES
+    ${TESTWEBKITAPI_DIR}/jsconly/main.cpp
+)
+
+list(APPEND TestWTF_SOURCES
+    ${TESTWEBKITAPI_DIR}/jsconly/PlatformUtilitiesJSCOnly.cpp
+    ${TESTWEBKITAPI_DIR}/Tests/WTF/RunLoop.cpp
+)
index 7583e4e..49f5708 100644 (file)
 #ifndef PlatformUtilities_h
 #define PlatformUtilities_h
 
+#ifndef BUILDING_JSCONLY__
 #include <WebKit/WKNativeEvent.h>
 #include <WebKit/WKRetainPtr.h>
+#endif
 #include <string>
 
 #if USE(FOUNDATION)
index e7e3d9f..11aa921 100644 (file)
@@ -54,4 +54,113 @@ TEST(WTF_RunLoop, Deadlock)
     Util::run(&testFinished);
 }
 
+TEST(WTF_RunLoop, NestedRunLoop)
+{
+    RunLoop::initializeMainRunLoop();
+
+    bool testFinished = false;
+    RunLoop::current().dispatch([&] {
+        RunLoop::current().dispatch([&] {
+            testFinished = true;
+        });
+        Util::run(&testFinished);
+    });
+
+    Util::run(&testFinished);
+}
+
+TEST(WTF_RunLoop, OneShotTimer)
+{
+    RunLoop::initializeMainRunLoop();
+
+    bool testFinished = false;
+
+    class DerivedTimer : public RunLoop::Timer<DerivedTimer> {
+    public:
+        DerivedTimer(bool& testFinished)
+            : RunLoop::Timer<DerivedTimer>(RunLoop::current(), this, &DerivedTimer::fired)
+            , m_testFinished(testFinished)
+        {
+        }
+
+        void fired()
+        {
+            m_testFinished = true;
+            stop();
+        }
+
+    private:
+        bool& m_testFinished;
+    };
+
+    {
+        DerivedTimer timer(testFinished);
+        timer.startOneShot(0.1);
+        Util::run(&testFinished);
+    }
+}
+
+TEST(WTF_RunLoop, RepeatingTimer)
+{
+    RunLoop::initializeMainRunLoop();
+
+    bool testFinished = false;
+
+    class DerivedTimer : public RunLoop::Timer<DerivedTimer> {
+    public:
+        DerivedTimer(bool& testFinished)
+            : RunLoop::Timer<DerivedTimer>(RunLoop::current(), this, &DerivedTimer::fired)
+            , m_testFinished(testFinished)
+        {
+        }
+
+        void fired()
+        {
+            if (++m_count == 10) {
+                m_testFinished = true;
+                stop();
+            }
+        }
+
+    private:
+        unsigned m_count { 0 };
+        bool& m_testFinished;
+    };
+
+    {
+        DerivedTimer timer(testFinished);
+        timer.startRepeating(0.01);
+        Util::run(&testFinished);
+    }
+}
+
+TEST(WTF_RunLoop, ManyTimes)
+{
+    RunLoop::initializeMainRunLoop();
+
+    class Counter {
+    public:
+        void run()
+        {
+            if (++m_count == 100000) {
+                RunLoop::current().stop();
+                return;
+            }
+            RunLoop::current().dispatch([this] {
+                run();
+            });
+        }
+
+    private:
+        unsigned m_count { 0 };
+    };
+
+    Counter counter;
+
+    RunLoop::current().dispatch([&counter] {
+        counter.run();
+    });
+    RunLoop::run();
+}
+
 } // namespace TestWebKitAPI
index 2a62583..09e3580 100644 (file)
 #include "cmakeconfig.h"
 #endif
 
-#include <WebCore/PlatformExportMacros.h>
 #include <runtime/JSExportMacros.h>
+#ifndef BUILDING_JSCONLY__
+#include <WebCore/PlatformExportMacros.h>
+#endif
 
 #if defined(__APPLE__) && __APPLE__
 
@@ -63,7 +65,7 @@
 
 #include <stdint.h>
 
-#if !PLATFORM(IOS) && !PLATFORM(WIN) && !(PLATFORM(GTK) && !defined(BUILDING_WEBKIT2__))
+#if !PLATFORM(IOS) && !PLATFORM(WIN) && !(PLATFORM(GTK) && !defined(BUILDING_WEBKIT2__)) && !defined(BUILDING_JSCONLY__)
 #include <WebKit/WebKit2_C.h>
 #endif
 
@@ -89,6 +91,6 @@
 #endif
 #endif
 
-#if !PLATFORM(IOS)
+#if !PLATFORM(IOS) && !defined(BUILDING_JSCONLY__)
 #define WK_HAVE_C_SPI 1
 #endif
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Konstantin Tokavev <annulen@yandex.ru>
+ * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  */
 
 #include "config.h"
-#include "RunLoop.h"
+#include "PlatformUtilities.h"
 
-namespace WTF {
+#include <wtf/CurrentTime.h>
+#include <wtf/RunLoop.h>
 
-RunLoop::RunLoop()
-{
-}
-
-RunLoop::~RunLoop()
-{
-}
-
-void RunLoop::run()
-{
-}
-
-void RunLoop::stop()
-{
-}
+#if USE(GLIB_EVENT_LOOP)
+#include <glib.h>
+#include <wtf/glib/GRefPtr.h>
+#endif
 
-void RunLoop::wakeUp()
-{
-    ASSERT_NOT_REACHED();
-}
-
-RunLoop::TimerBase::TimerBase(RunLoop& runLoop)
-    : m_runLoop(runLoop)
-{
-}
-
-RunLoop::TimerBase::~TimerBase()
-{
-    stop();
-}
-
-void RunLoop::TimerBase::start(double, bool)
-{
-}
+namespace TestWebKitAPI {
+namespace Util {
 
-void RunLoop::TimerBase::stop()
+void run(bool* done)
 {
+    while (!*done) {
+#if USE(GLIB_EVENT_LOOP)
+        g_main_context_iteration(RunLoop::current().mainContext(), false);
+#else
+        WTF::RunLoop::iterate();
+#endif
+    }
 }
 
-bool RunLoop::TimerBase::isActive() const
+void sleep(double seconds)
 {
-    return false;
+    WTF::sleep(seconds);
 }
 
-} // namespace WTF
+} // namespace Util
+} // namespace TestWebKitAPI
similarity index 77%
rename from Source/WTF/wtf/none/WorkQueueNone.cpp
rename to Tools/TestWebKitAPI/jsconly/main.cpp
index 2a6d675..22b12cf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Konstantin Tokavev <annulen@yandex.ru>
+ * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  */
 
 #include "config.h"
-#include "WorkQueue.h"
+#include "TestsController.h"
 
-void WorkQueue::platformInitialize(const char*, Type, QOS)
+int main(int argc, char** argv)
 {
-}
-
-void WorkQueue::platformInvalidate()
-{
-}
-
-void WorkQueue::dispatch(std::function<void()>)
-{
-    ASSERT_NOT_REACHED();
-}
-
-void WorkQueue::dispatchAfter(std::chrono::nanoseconds, std::function<void()>)
-{
-    ASSERT_NOT_REACHED();
+    return TestWebKitAPI::TestsController::singleton().run(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE;
 }