2009-02-19 David Levin <levin@chromium.org>
authorlevin@chromium.org <levin@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 19 Feb 2009 22:35:40 +0000 (22:35 +0000)
committerlevin@chromium.org <levin@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 19 Feb 2009 22:35:40 +0000 (22:35 +0000)
        Reviewed by Alexey Proskuryakov.

        Bug 23980: WorkerRunLoop needs a way to run in a given mode similar to CFRunLoopInMode.
        <https://bugs.webkit.org/show_bug.cgi?id=23980>

        WorkerRunLoop has the ability to run in a mode which filters the tasks to be run.
        * When WorkerRunLoop::runInMode is called, only task for that mode will run.
        * When WorkerRunLoop::run is called (or the default mode is used), then all tasks
          will run regardless of their posted mode.

        Here's a demonstration of the api:

            RefPtr<NameResolution> nameResolution = NameResolution::create(workerRunLoop);

            //  Internally nameResolution will do workerRunLoop.postTaskForMode(task, "MyCoolMode")
            //  for any tasks that need to be run during this loop.
            nameResolution->setTaskMode("MyCoolMode");

            nameResolution->start();
            while (!nameResolution->done()) {
                // Only tasks which are posted for "MyCoolMode" will run.
                workerRunLoop.runInMode(context, "MyCoolMode");
            }

        No observable change in behavior, so no test.

        * dom/WorkerRunLoop.cpp:
        (WebCore::ModePredicate::ModePredicate):
        (WebCore::ModePredicate::operator()):
        (WebCore::WorkerRunLoop::WorkerRunLoop):
        (WebCore::WorkerRunLoop::~WorkerRunLoop):
        (WebCore::WorkerRunLoop::setSharedTimer):
        (WebCore::WorkerRunLoop::resetSharedTimer):
        (WebCore::WorkerRunLoop::run):
        (WebCore::WorkerRunLoop::runInMode):
        (WebCore::WorkerRunLoop::postTask):
        (WebCore::WorkerRunLoop::postTaskForMode):
        * dom/WorkerRunLoop.h:
        (WebCore::WorkerRunLoop::Task::create):
        (WebCore::WorkerRunLoop::Task::mode):
        (WebCore::WorkerRunLoop::Task::performTask):
        (WebCore::WorkerRunLoop::Task::Task):

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

WebCore/ChangeLog
WebCore/dom/WorkerRunLoop.cpp
WebCore/dom/WorkerRunLoop.h

index b9c37e0c85ee4402f148f1b041cb7b4828d8ef60..bce638daca0b53793abeabdde857540f051d57e8 100644 (file)
@@ -1,3 +1,48 @@
+2009-02-19  David Levin  <levin@chromium.org>
+
+        Reviewed by Alexey Proskuryakov.
+
+        Bug 23980: WorkerRunLoop needs a way to run in a given mode similar to CFRunLoopInMode.
+        <https://bugs.webkit.org/show_bug.cgi?id=23980>
+
+        WorkerRunLoop has the ability to run in a mode which filters the tasks to be run.
+        * When WorkerRunLoop::runInMode is called, only task for that mode will run.
+        * When WorkerRunLoop::run is called (or the default mode is used), then all tasks
+          will run regardless of their posted mode.
+
+        Here's a demonstration of the api:
+
+            RefPtr<NameResolution> nameResolution = NameResolution::create(workerRunLoop);
+
+            //  Internally nameResolution will do workerRunLoop.postTaskForMode(task, "MyCoolMode")
+            //  for any tasks that need to be run during this loop.
+            nameResolution->setTaskMode("MyCoolMode");
+
+            nameResolution->start();
+            while (!nameResolution->done()) {
+                // Only tasks which are posted for "MyCoolMode" will run.
+                workerRunLoop.runInMode(context, "MyCoolMode");
+            }
+
+        No observable change in behavior, so no test.
+
+        * dom/WorkerRunLoop.cpp:
+        (WebCore::ModePredicate::ModePredicate):
+        (WebCore::ModePredicate::operator()):
+        (WebCore::WorkerRunLoop::WorkerRunLoop):
+        (WebCore::WorkerRunLoop::~WorkerRunLoop):
+        (WebCore::WorkerRunLoop::setSharedTimer):
+        (WebCore::WorkerRunLoop::resetSharedTimer):
+        (WebCore::WorkerRunLoop::run):
+        (WebCore::WorkerRunLoop::runInMode):
+        (WebCore::WorkerRunLoop::postTask):
+        (WebCore::WorkerRunLoop::postTaskForMode):
+        * dom/WorkerRunLoop.h:
+        (WebCore::WorkerRunLoop::Task::create):
+        (WebCore::WorkerRunLoop::Task::mode):
+        (WebCore::WorkerRunLoop::Task::performTask):
+        (WebCore::WorkerRunLoop::Task::Task):
+
 2009-02-19  Dimitri Glazkov  <dglazkov@chromium.org>
 
         Reviewed by Eric Seidel.
index 6a9ebb3ab00ec5d843832f3b971520c51434be35..63e3d10ba3d8fc1aa7d5fef5eb204c9a51b208ca 100644 (file)
@@ -64,44 +64,135 @@ private:
     double m_nextFireTime;
 };
 
+class WorkerRunLoop::Task : public RefCounted<Task> {
+public:
+    static PassRefPtr<Task> create(PassRefPtr<ScriptExecutionContext::Task> task, const String& mode)
+    {
+        return adoptRef(new Task(task, mode));
+    }
+
+    const String& mode() const { return m_mode; }
+    void performTask(ScriptExecutionContext* context) { m_task->performTask(context); }
+
+private:
+    Task(PassRefPtr<ScriptExecutionContext::Task> task, const String& mode)
+        : m_task(task)
+        , m_mode(mode.copy())
+    {
+    }
+
+    RefPtr<ScriptExecutionContext::Task> m_task;
+    String m_mode;
+};
+
+class ModePredicate {
+public:
+    ModePredicate(const String& mode)
+        : m_mode(mode)
+        , m_defaultMode(mode == WorkerRunLoop::defaultMode())
+    {
+    }
+
+    bool isDefaultMode() const
+    {
+        return m_defaultMode;
+    }
+
+    bool operator()(PassRefPtr<WorkerRunLoop::Task> task)
+    {
+        return m_defaultMode || m_mode == task->mode();
+    }
+
+private:
+    String m_mode;
+    bool m_defaultMode;
+};
+
 WorkerRunLoop::WorkerRunLoop()
     : m_sharedTimer(new WorkerSharedTimer)
+    , m_nestedCount(0)
 {
 }
 
 WorkerRunLoop::~WorkerRunLoop()
 {
+    ASSERT(!m_nestedCount);
 }
 
+String WorkerRunLoop::defaultMode()
+{
+    return String();
+}
+
+class RunLoopSetup : Noncopyable
+{
+public:
+    RunLoopSetup(WorkerRunLoop& runLoop)
+        : m_runLoop(runLoop)
+    {
+        if (!m_runLoop.m_nestedCount)
+            threadGlobalData().threadTimers().setSharedTimer(m_runLoop.m_sharedTimer.get());
+        m_runLoop.m_nestedCount++;
+    }
+
+    ~RunLoopSetup()
+    {
+        m_runLoop.m_nestedCount--;
+        if (!m_runLoop.m_nestedCount)
+            threadGlobalData().threadTimers().setSharedTimer(0);
+    }
+private:
+    WorkerRunLoop& m_runLoop;
+};
+
 void WorkerRunLoop::run(WorkerContext* context)
+{
+    RunLoopSetup setup(*this);
+    ModePredicate modePredicate(defaultMode());
+    MessageQueueWaitResult result;
+    do {
+        result = runInMode(context, modePredicate);
+    } while (result != MessageQueueTerminated);
+}
+
+MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerContext* context, const String& mode)
+{
+    RunLoopSetup setup(*this);
+    ModePredicate modePredicate(mode);
+    MessageQueueWaitResult result = runInMode(context, modePredicate);
+    return result;
+}
+
+MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerContext* context, ModePredicate& predicate)
 {
     ASSERT(context);
     ASSERT(context->thread());
     ASSERT(context->thread()->threadID() == currentThread());
 
-    threadGlobalData().threadTimers().setSharedTimer(m_sharedTimer.get());
-
-    while (true) {
-        RefPtr<ScriptExecutionContext::Task> task;
-        MessageQueueWaitResult result;
-
+    RefPtr<Task> task;
+    MessageQueueWaitResult result;
+    if (predicate.isDefaultMode()) {
         if (m_sharedTimer->isActive())
             result = m_messageQueue.waitForMessageTimed(task, m_sharedTimer->fireTime());
         else
-            result = (m_messageQueue.waitForMessage(task) ? MessageQueueMessageReceived : MessageQueueTerminated);
-
-        if (result == MessageQueueTerminated)
-            break;
-        
-        if (result == MessageQueueMessageReceived)
-            task->performTask(context);
-        else {
-            ASSERT(result == MessageQueueTimeout);
-            m_sharedTimer->fire();
-        }
+            result = m_messageQueue.waitForMessage(task) ? MessageQueueMessageReceived : MessageQueueTerminated;
+    } else
+        result = m_messageQueue.waitForMessageFiltered(task, predicate);
+
+    switch (result) {
+    case MessageQueueTerminated:
+        break;
+
+    case MessageQueueMessageReceived:
+        task->performTask(context);
+        break;
+
+    case MessageQueueTimeout:
+        m_sharedTimer->fire();
+        break;
     }
 
-    threadGlobalData().threadTimers().setSharedTimer(0);
+    return result;
 }
 
 void WorkerRunLoop::terminate()
@@ -111,7 +202,12 @@ void WorkerRunLoop::terminate()
 
 void WorkerRunLoop::postTask(PassRefPtr<ScriptExecutionContext::Task> task)
 {
-    m_messageQueue.append(task);
+    postTaskForMode(task, defaultMode());
+}
+
+void WorkerRunLoop::postTaskForMode(PassRefPtr<ScriptExecutionContext::Task> task, const String& mode)
+{
+    m_messageQueue.append(Task::create(task, mode.copy()));
 }
 
 } // namespace WebCore
index 8bddbe36f953078bab2f175ab92bb33957cc7b18..9ae9fd4297793ee08cab58f6903b587fc45ed432 100644 (file)
@@ -40,6 +40,7 @@
 
 namespace WebCore {
 
+    class ModePredicate;
     class WorkerContext;
     class WorkerSharedTimer;
 
@@ -50,15 +51,25 @@ namespace WebCore {
         
         // Blocking call. Waits for tasks and timers, invokes the callbacks.
         void run(WorkerContext*);
-        
+
+        // Waits for a single task and returns.
+        MessageQueueWaitResult runInMode(WorkerContext*, const String& mode);
+
         void terminate();
         bool terminated() { return m_messageQueue.killed(); }
 
         void postTask(PassRefPtr<ScriptExecutionContext::Task>);
+        void postTaskForMode(PassRefPtr<ScriptExecutionContext::Task>, const String& mode);
 
+        static String defaultMode();
+        class Task;
     private:
-        MessageQueue<RefPtr<ScriptExecutionContext::Task> > m_messageQueue;
+        friend class RunLoopSetup;
+        MessageQueueWaitResult runInMode(WorkerContext*, ModePredicate&);
+
+        MessageQueue<RefPtr<Task> > m_messageQueue;
         OwnPtr<WorkerSharedTimer> m_sharedTimer;
+        int m_nestedCount;
     };
 
 } // namespace WebCore