]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/timerunx.cpp
Avoid overflowing the wake up when handling events in Unix console apps.
[wxWidgets.git] / src / unix / timerunx.cpp
index 158736fcb3a5a0caa8a68230515d2a15b47488f8..7ee1177c89adabebc16d56d8b0ecfae742c9cc65 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "wx/apptrait.h"
 #include "wx/longlong.h"
+#include "wx/time.h"
+#include "wx/vector.h"
 
 #include <sys/time.h>
 #include <signal.h>
@@ -53,7 +55,7 @@ static inline wxString wxUsecClockAsString(wxUsecClock_t usec)
     #if wxUSE_LONGLONG
         return usec.ToString();
     #else // wxUsecClock_t == double
-        return wxString::Format(_T("%.0f"), usec);
+        return wxString::Format(wxT("%.0f"), usec);
     #endif
 }
 
@@ -85,7 +87,7 @@ void wxTimerScheduler::DoAddTimer(wxTimerSchedule *s)
     for ( node = m_timers.begin(); node != m_timers.end(); ++node )
     {
         wxASSERT_MSG( (*node)->m_timer != s->m_timer,
-                      _T("adding the same timer twice?") );
+                      wxT("adding the same timer twice?") );
 
         if ( (*node)->m_expiration > s->m_expiration )
             break;
@@ -114,7 +116,7 @@ void wxTimerScheduler::RemoveTimer(wxUnixTimerImpl *timer)
         }
     }
 
-    wxFAIL_MSG( _T("removing inexistent timer?") );
+    wxFAIL_MSG( wxT("removing inexistent timer?") );
 }
 
 bool wxTimerScheduler::GetNext(wxUsecClock_t *remaining) const
@@ -122,9 +124,9 @@ bool wxTimerScheduler::GetNext(wxUsecClock_t *remaining) const
     if ( m_timers.empty() )
       return false;
 
-    wxCHECK_MSG( remaining, false, _T("NULL pointer") );
+    wxCHECK_MSG( remaining, false, wxT("NULL pointer") );
 
-    *remaining = (*m_timers.begin())->m_expiration - wxGetLocalTimeUsec();
+    *remaining = (*m_timers.begin())->m_expiration - wxGetUTCTimeUSec();
     if ( *remaining < 0 )
     {
         // timer already expired, don't wait at all before notifying it
@@ -134,16 +136,17 @@ bool wxTimerScheduler::GetNext(wxUsecClock_t *remaining) const
     return true;
 }
 
-void wxTimerScheduler::NotifyExpired()
+bool wxTimerScheduler::NotifyExpired()
 {
     if ( m_timers.empty() )
-      return;
+      return false;
 
-    const wxUsecClock_t now = wxGetLocalTimeUsec();
+    const wxUsecClock_t now = wxGetUTCTimeUSec();
 
-    wxTimerList::iterator cur,
-                          next;
-    for ( cur = m_timers.begin(); cur != m_timers.end(); cur = next )
+    typedef wxVector<wxUnixTimerImpl *> TimerImpls;
+    TimerImpls toNotify;
+    for ( wxTimerList::iterator next,
+            cur = m_timers.begin(); cur != m_timers.end(); cur = next )
     {
         wxTimerSchedule * const s = *cur;
         if ( s->m_expiration > now )
@@ -172,13 +175,33 @@ void wxTimerScheduler::NotifyExpired()
         }
         else // reschedule the next timer expiration
         {
-            s->m_expiration += timer->GetInterval()*1000;
+            // always keep the expiration time in the future, i.e. base it on
+            // the current time instead of just offsetting it from the current
+            // expiration time because it could happen that we're late and the
+            // current expiration time is (far) in the past
+            s->m_expiration = now + timer->GetInterval()*1000;
             DoAddTimer(s);
         }
 
-        // and finally notify the timer
-        timer->Notify();
+        // we can't notify the timer from this loop as the timer event handler
+        // could modify m_timers (for example, but not only, by stopping this
+        // timer) which would render our iterators invalid, so do it after the
+        // loop end
+        toNotify.push_back(timer);
     }
+
+    if ( toNotify.empty() )
+        return false;
+
+    for ( TimerImpls::const_iterator i = toNotify.begin(),
+                                     end = toNotify.end();
+          i != end;
+          ++i )
+    {
+        (*i)->Notify();
+    }
+
+    return true;
 }
 
 // ============================================================================
@@ -196,7 +219,7 @@ bool wxUnixTimerImpl::Start(int milliseconds, bool oneShot)
     // notice that this will stop an already running timer
     wxTimerImpl::Start(milliseconds, oneShot);
 
-    wxTimerScheduler::Get().AddTimer(this, wxGetLocalTimeUsec() + m_milli*1000);
+    wxTimerScheduler::Get().AddTimer(this, wxGetUTCTimeUSec() + m_milli*1000);
     m_isRunning = true;
 
     return true;
@@ -219,7 +242,7 @@ bool wxUnixTimerImpl::IsRunning() const
 
 wxUnixTimerImpl::~wxUnixTimerImpl()
 {
-    wxASSERT_MSG( !m_isRunning, _T("must have been stopped before") );
+    wxASSERT_MSG( !m_isRunning, wxT("must have been stopped before") );
 }
 
 // ============================================================================
@@ -242,21 +265,6 @@ IMPLEMENT_DYNAMIC_CLASS(wxTimerUnixModule, wxModule)
 // global functions
 // ============================================================================
 
-wxUsecClock_t wxGetLocalTimeUsec()
-{
-#ifdef HAVE_GETTIMEOFDAY
-    struct timeval tv;
-    if ( wxGetTimeOfDay(&tv) != -1 )
-    {
-        wxUsecClock_t val = 1000000L; // usec/sec
-        val *= tv.tv_sec;
-        return val + tv.tv_usec;
-    }
-#endif // HAVE_GETTIMEOFDAY
-
-    return wxGetLocalTimeMillis() * 1000L;
-}
-
 wxTimerImpl *wxConsoleAppTraits::CreateTimerImpl(wxTimer *timer)
 {
     return new wxUnixTimerImpl(timer);