Reschedule timer_current in case of inner mainloop
authorlucas <lucas@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 28 May 2010 02:31:02 +0000 (02:31 +0000)
committerlucas <lucas@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 28 May 2010 02:31:02 +0000 (02:31 +0000)
Timers' list is and *ordered list*. Therefore, timers can be added
before timer_current in an inner mainloop. Reschedule timer_current in
this case before looping through timers' list.

Thanks to Barbieri for the insight.

The following test didn't work before and it's ok now (I'm adding it to
ecore_suite too).

static int _timer3(void *data)
{
printf("timer 3, do nothing\n");
return 0;
}

static int _timer2(void *data)
{
printf("timer 2, quit inner\n");
ecore_main_loop_quit();
return 0;
}

static int _timer1(void *data)
{
int *times = data;
(*times)++;
printf("BEGIN: inner\n");

ecore_timer_add(0.3, _timer2, NULL);
ecore_timer_add(0.1, _timer3, NULL);

ecore_main_loop_begin();
printf("END: inner\n");
ecore_main_loop_quit();

return 0;
}

int main(void)
{
int times = 0;

ecore_init();
ecore_timer_add(1.0, _timer1, &times);
printf("BEGIN: main\n");
ecore_main_loop_begin();
assert(times == 1);
printf("timer1 called %d times \n", times);
printf("END: main\n");
return 0;
}

By: Lucas De Marchi <lucas.demarchi@profusion.mobi>

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ecore@49245 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/ecore/ecore_timer.c
src/tests/ecore_test_ecore.c

index 8d13c06..995d6c2 100644 (file)
@@ -485,6 +485,28 @@ _ecore_timer_next_get(void)
    return in;
 }
 
+static inline void
+_ecore_timer_reschedule(Ecore_Timer *timer, double when)
+{
+   if ((timer->delete_me) || (timer->frozen)) return;
+
+   timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(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
+     _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
+}
+
 int
 _ecore_timer_call(double when)
 {
@@ -505,7 +527,9 @@ _ecore_timer_call(double when)
    else
      {
        /* recursive main loop, continue from where we were */
+       Ecore_Timer *timer_old = timer_current;
        timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
+       _ecore_timer_reschedule(timer_old, when);
      }
 
    while (timer_current)
@@ -531,24 +555,7 @@ _ecore_timer_call(double when)
        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 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
-              _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, timer->data);
-         }
+       _ecore_timer_reschedule(timer, when);
      }
    return 0;
 }
index fc0c668..69430ef 100644 (file)
@@ -150,6 +150,49 @@ START_TEST(ecore_test_ecore_main_loop_timer)
 }
 END_TEST
 
+static int _timer3(void *data)
+{
+   /* timer 3, do nothing */
+   return 0;
+}
+
+static int _timer2(void *data)
+{
+   /* timer 2, quit inner mainloop */
+   ecore_main_loop_quit();
+   return 0;
+}
+
+static int _timer1(void *data)
+{
+   /* timer 1, begin inner mainloop */
+   int *times = data;
+   (*times)++;
+
+   ecore_timer_add(0.3, _timer2, NULL);
+   ecore_timer_add(0.1, _timer3, NULL);
+   ecore_main_loop_begin();
+
+   ecore_main_loop_quit();
+
+   return 0;
+}
+
+START_TEST(ecore_test_ecore_main_loop_timer_inner)
+{
+   int times = 0;
+
+   ecore_init();
+   ecore_timer_add(1.0, _timer1, &times);
+
+   /* BEGIN: outer mainloop */
+   ecore_main_loop_begin();
+   /*END: outer mainloop */
+
+   fail_if(times != 1);
+}
+END_TEST
+
 static int
 _fd_handler_cb(void *data, Ecore_Fd_Handler *handler __UNUSED__)
 {
@@ -238,4 +281,5 @@ void ecore_test_ecore(TCase *tc)
    tcase_add_test(tc, ecore_test_ecore_main_loop_timer);
    tcase_add_test(tc, ecore_test_ecore_main_loop_fd_handler);
    tcase_add_test(tc, ecore_test_ecore_main_loop_event);
+   tcase_add_test(tc, ecore_test_ecore_main_loop_timer_inner);
 }