[haiku-webkit-commits] r241 - webkit/trunk/WebCore/platform/haiku

  • From: webkit@xxxxxxxxxxxxxxx
  • To: haiku-webkit-commits@xxxxxxxxxxxxx
  • Date: Sat, 27 Feb 2010 20:47:03 +0000

Author: stippi
Date: Sat Feb 27 20:47:03 2010
New Revision: 241
URL: http://mmlr.dyndns.org/changeset/241

Log:
Rewrote the SharedTimer impelementation. The old one used BMessageRunner, which
is imprecise since it uses the registrar to fire messages across processes. This
uses kernel ports and has bad timing resolution. The new message uses it's own
high priority thread. The BMessageFilter is now a BHandler, which doesn't
change much, other than how the message arrives. But sending messages within
the same team attaches the message directly to the message queue, no ports
involved. The asteroids demo stays totally smooth now. :-)

Modified:
   webkit/trunk/WebCore/platform/haiku/SharedTimerHaiku.cpp

Modified: webkit/trunk/WebCore/platform/haiku/SharedTimerHaiku.cpp
==============================================================================
--- webkit/trunk/WebCore/platform/haiku/SharedTimerHaiku.cpp    Sat Feb 27 
18:26:46 2010        (r240)
+++ webkit/trunk/WebCore/platform/haiku/SharedTimerHaiku.cpp    Sat Feb 27 
20:47:03 2010        (r241)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2009 Maxime Simon <simon.maxime@xxxxxxxxx>
+ * Copyright (C) 2010 Stephan Aßmus <superstippi@xxxxxx>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -38,7 +39,98 @@
 
 namespace WebCore {
 
-class SharedTimerHaiku : public BMessageFilter {
+class TimerThread : public BLocker {
+public:
+       TimerThread(const BMessenger& timer)
+               : m_timer(timer)
+               , m_timerThread(B_BAD_THREAD_ID)
+               , m_timerSem(B_BAD_SEM_ID)
+               , m_nextFireTime(0)
+               , m_threadWaitUntil(0)
+               , m_terminating(false)
+       {
+               m_timerSem = create_sem(0, "timer thread control");
+               if (m_timerSem >= 0) {
+                       m_timerThread = spawn_thread(timerThreadEntry, "timer 
thread",
+                               B_DISPLAY_PRIORITY + 1, this);
+                       if (m_timerThread >= 0)
+                               resume_thread(m_timerThread);
+               }
+       }
+
+       ~TimerThread()
+       {
+               m_terminating = true;
+               if (delete_sem(m_timerSem) == B_OK) {
+                       int32 dummy;
+                       wait_for_thread(m_timerThread, &dummy);
+               }
+       }
+
+       bool isValid() const
+       {
+               return m_timerThread >= 0 && m_timerSem >= 0;
+       }
+
+       void setNextEventTime(bigtime_t time)
+       {
+               Lock();
+               m_nextFireTime = time;
+               if (m_nextFireTime < m_threadWaitUntil)
+                       release_sem(m_timerSem);
+               Unlock();
+       }
+
+private:
+       static int32 timerThreadEntry(void *data)
+       {
+               return ((TimerThread*)data)->timerThread();
+       }
+
+       int32 timerThread()
+       {
+               bool running = true;
+               while (running) {
+                       bigtime_t waitUntil = B_INFINITE_TIMEOUT;
+                       if (Lock()) {
+                               if (m_nextFireTime > 0)
+                                   waitUntil = m_nextFireTime;
+                               m_threadWaitUntil = waitUntil;
+                               Unlock();
+                       }
+                       status_t err = acquire_sem_etc(m_timerSem, 1, 
B_ABSOLUTE_TIMEOUT, waitUntil);
+                       switch (err) {
+                               case B_TIMED_OUT:
+                                       // do events, that are supposed to go 
off
+                                       if (!m_terminating && Lock() && 
system_time() >= m_nextFireTime) {
+                                               m_nextFireTime = 0;
+                                               Unlock();
+                                               
m_timer.SendMessage(FIRE_MESSAGE);
+                                       }
+                                       if (IsLocked())
+                                               Unlock();
+                                       break;
+                               case B_BAD_SEM_ID:
+                                       running = false;
+                                       break;
+                               case B_OK:
+                               default:
+                                       break;
+                       }
+               }
+               return 0;
+       }
+
+private:
+       BMessenger m_timer;
+       thread_id m_timerThread;
+       sem_id m_timerSem;
+       volatile bigtime_t m_nextFireTime;
+       volatile bigtime_t m_threadWaitUntil;
+       volatile bool m_terminating;
+};
+
+class SharedTimerHaiku : public BHandler {
     friend void setSharedTimerFiredFunction(void (*f)());
 public:
     static SharedTimerHaiku* instance();
@@ -46,8 +138,13 @@
     void start(double);
     void stop();
 
+       void setTimerThread(TimerThread* thread)
+       {
+               m_timerThread = thread;
+       }
+
 protected:
-    virtual filter_result Filter(BMessage*, BHandler**);
+    virtual void MessageReceived(BMessage*);
 
 private:
     SharedTimerHaiku();
@@ -55,28 +152,33 @@
 
     void (*m_timerFunction)();
     bool m_shouldRun;
+    TimerThread* m_timerThread;
 };
 
 SharedTimerHaiku::SharedTimerHaiku()
-    : BMessageFilter(FIRE_MESSAGE)
+    : BHandler("WebKit shared timer")
     , m_timerFunction(0)
     , m_shouldRun(false)
+    , m_timerThread(0)
 {
 }
 
 SharedTimerHaiku::~SharedTimerHaiku()
 {
+       delete m_timerThread;
 }
 
 SharedTimerHaiku* SharedTimerHaiku::instance()
 {
-    BLooper* looper = BLooper::LooperForThread(find_thread(0));
     static SharedTimerHaiku* timer;
 
     if (!timer) {
+        BLooper* looper = BLooper::LooperForThread(find_thread(0));
         BAutolock lock(looper);
         timer = new SharedTimerHaiku();
-        looper->AddCommonFilter(timer);
+        looper->AddHandler(timer);
+        // Only at this time, the timer can be a valid BMessenger.
+        timer->setTimerThread(new TimerThread(BMessenger(timer)));
     }
 
     return timer;
@@ -89,8 +191,7 @@
     double intervalInSeconds = fireTime - currentTime();
     bigtime_t intervalInMicroSeconds = intervalInSeconds < 0 ? 0 : 
intervalInSeconds * 1000000;
 
-    BMessage message(FIRE_MESSAGE);
-    BMessageRunner::StartSending(Looper(), &message, intervalInMicroSeconds, 
1);
+       m_timerThread->setNextEventTime(system_time() + intervalInMicroSeconds);
 }
 
 void SharedTimerHaiku::stop()
@@ -98,12 +199,10 @@
     m_shouldRun = false;
 }
 
-filter_result SharedTimerHaiku::Filter(BMessage*, BHandler**)
+void SharedTimerHaiku::MessageReceived(BMessage*)
 {
     if (m_shouldRun && m_timerFunction)
         m_timerFunction();
-
-    return B_SKIP_MESSAGE;
 }
 
 // WebCore functions

Other related posts: