Subject: bug#12447: 24.1.50; Stuck in garbage collection on OS X

From: Eli Zaretskii <[email-masked]>
Date: Sun, 16 Sep 2012 16:47:40 +0300

> Date: Sun, 16 Sep 2012 17:25:35 +0400
> From: Dmitry Gutov <[email-masked]>
> CC: [email-masked], [email-masked]
> 
> >      idle_timers = Vtimer_idle_list;
> 
> Done that, recompiled, no difference in the example a sent previously. 
> Exactly because, I think, of the control flow you describe below:
> 
> >> But no, it probably won't: the "guilty" commit made timer_check_2
> >> actually return 0 after a timer fires (keeping true to the comment above
> >> it), so a local copy would serve no purpose.
> >
> > timer_check_2 indeed returns, but then timer_check will call it again,
> > because it continues calling timer_check_2 in a loop, until there's no
> > ripe timer.
> 
> Each time timer_check_2 is called, a new copy would be made from the 
> idle timers list, so the newly created timer would be reached during the 
> same call to 'timer_check'.

But the first time timer_check_2 encounters an un-ripe timer, or gets
to the end of the list of timers, it returns a non-zero 'nexttime'
value, which should break the loop in timer_check.  Why isn't this
happening?

Perhaps the problem is that the value of 'difference' is not
initialized:

  while (CONSP (timers) || CONSP (idle_timers))
    {
      Lisp_Object timer = Qnil, idle_timer = Qnil;
      EMACS_TIME timer_time, idle_timer_time;
      EMACS_TIME difference;   <<<<<<<<<<<<<<<<<<<<<<<<<<<<

and then never set to any specific value, until here:

      else
	/* When we encounter a timer that is still waiting,
	   return the amount of time to wait before it is ripe.  */
	{
	  UNGCPRO;
	  return difference;
	}

which causes us return garbage, potentially zero, to timer_check.