rewrite ecore_timer internals to make it simpler and do better with
authorbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 24 Feb 2010 00:27:04 +0000 (00:27 +0000)
committerbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 24 Feb 2010 00:27:04 +0000 (00:27 +0000)
recursive main loops.

Unlike idlers, timers seems to work reasonably well with main loops, I
*think* they might fail since it used a boolean to flag running as
opposed to a reference count with incremental increments/decrements. I
could not write a test case to demonstrate so.

The now code should be simpler, particularly the
_ecore_timer_call(). It will also consider the previous position when
entering recursive main loops, preserving the order.

Deletion of timers are delegated to ecore_main.c, that was already
calling _ecore_timer_cleanup() after timers were executed.

git-svn-id: http://svn.enlightenment.org/svn/e/trunk/ecore@46416 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/ecore/ecore_timer.c

index 9781bf6..8d13c06 100644 (file)
@@ -23,10 +23,10 @@ struct _Ecore_Timer
    int           (*func) (void *data);
    void           *data;
 
+   int             references;
    unsigned char   delete_me : 1;
    unsigned char   just_added : 1;
    unsigned char   frozen : 1;
-   unsigned char   running : 1;
 };
 
 
@@ -35,6 +35,7 @@ static void _ecore_timer_set(Ecore_Timer *timer, double at, double in, int (*fun
 static int          timers_added = 0;
 static int          timers_delete_me = 0;
 static Ecore_Timer *timers = NULL;
+static Ecore_Timer *timer_current = NULL;
 static Ecore_Timer *suspended = NULL;
 static double       last_check = 0.0;
 static double       precision = 10.0 / 1000000.0;
@@ -176,7 +177,7 @@ ecore_timer_del(Ecore_Timer *timer)
        return NULL;
      }
 
-   if (timer->frozen && !timer->running)
+   if (timer->frozen && !timer->references)
      {
        void *data = timer->data;
 
@@ -309,8 +310,7 @@ ecore_timer_freeze(Ecore_Timer *timer)
    if (timer->frozen)
      return ;
 
-   if (!timer->running)
-     timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
+   timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
    suspended = (Ecore_Timer *) eina_inlist_prepend(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
 
    now = ecore_time_get();
@@ -360,12 +360,15 @@ _ecore_timer_shutdown(void)
         ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
         free(timer);
      }
+
+   timer_current = NULL;
 }
 
 void
 _ecore_timer_cleanup(void)
 {
    Ecore_Timer *l;
+   int in_use = 0;
 
    if (!timers_delete_me) return;
    for (l = timers; l;)
@@ -375,6 +378,11 @@ _ecore_timer_cleanup(void)
        l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
        if (timer->delete_me)
          {
+            if (timer->references)
+              {
+                 in_use++;
+                 continue;
+              }
             timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
             ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
             free(timer);
@@ -389,6 +397,11 @@ _ecore_timer_cleanup(void)
        l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
        if (timer->delete_me)
          {
+            if (timer->references)
+              {
+                 in_use++;
+                 continue;
+              }
             suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
             ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
             free(timer);
@@ -396,7 +409,13 @@ _ecore_timer_cleanup(void)
             if (timers_delete_me == 0) return;
          }
      }
-   timers_delete_me = 0;
+
+   if ((!in_use) && (timers_delete_me))
+     {
+       ERR("%d timers to delete, but they were not found! reset counter.",
+           timers_delete_me);
+       timers_delete_me = 0;
+     }
 }
 
 void
@@ -469,58 +488,66 @@ _ecore_timer_next_get(void)
 int
 _ecore_timer_call(double when)
 {
-   Ecore_Timer *timer, *l;
-
    if (!timers) return 0;
    if (last_check > when)
      {
+       Ecore_Timer *timer;
        /* User set time backwards */
        EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when);
      }
    last_check = when;
-   for (l = timers; l;)
+
+   if (!timer_current)
      {
-       timer = l;
-       l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
-//        printf("_ecore_timer_call %3.3f <= %3.3f %i %i %p\n", 
-//               timer->at, when, timer->just_added, timer->delete_me, timer);
-       if ((timer->at <= when) &&
-           (timer->just_added == 0) &&
-           (timer->delete_me == 0))
+       /* regular main loop, start from head */
+       timer_current = timers;
+     }
+   else
+     {
+       /* recursive main loop, continue from where we were */
+       timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
+     }
+
+   while (timer_current)
+     {
+       Ecore_Timer *timer = timer_current;
+
+       if (timer->at > when)
+         {
+            timer_current = NULL; /* ended walk, next should restart. */
+            return 0;
+         }
+
+       if ((timer->just_added) || (timer->delete_me))
          {
-            timer->running = EINA_TRUE;
+            timer_current = (Ecore_Timer*)EINA_INLIST_GET(timer_current)->next;
+            continue;
+         }
+
+       timer->references++;
+       if (!timer->func(timer->data)) ecore_timer_del(timer);
+       timer->references--;
 
+       if (timer_current) /* may have changed in recursive main loops */
+         timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
+
+       if ((!timer->delete_me) && (!timer->frozen))
+         {
             timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
-            if ((!timer->delete_me) && (timer->func(timer->data)))
-              {
-                 /* if the timer would have gone off more than 15 seconds ago,
-                  * assume that the system hung and set the timer to go off
-                  * timer->in from now. this handles system hangs, suspends
-                  * and more, so ecore will only "replay" the timers while
-                  * the system is suspended if it is suspended for less than
-                  * 15 seconds (basically). this also handles if the process
-                  * is stopped in a debugger or IO and other handling gets
-                  * really slow within the main loop.
-                  */
-                 if (!timer->delete_me)
-                   {
-                      timer->running = EINA_FALSE;
-
-                      if (!timer->frozen)
-                        {
-                           if ((timer->at + timer->in) < (when - 15.0))
-                             _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
-                           else
-                             _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
-                        }
-                   }
-                 else
-                   free(timer);
-              }
+
+            /* if the timer would have gone off more than 15 seconds ago,
+             * assume that the system hung and set the timer to go off
+             * timer->in from now. this handles system hangs, suspends
+             * and more, so ecore will only "replay" the timers while
+             * the system is suspended if it is suspended for less than
+             * 15 seconds (basically). this also handles if the process
+             * is stopped in a debugger or IO and other handling gets
+             * really slow within the main loop.
+             */
+            if ((timer->at + timer->in) < (when - 15.0))
+              _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, timer->data);
             else
-              free(timer);
-            _ecore_timer_call(when);
-            return 1;
+              _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
          }
      }
    return 0;