diff options
| author | Eli Zaretskii | 2012-09-22 16:16:03 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2012-09-22 16:16:03 +0300 |
| commit | df9685f3961022245b9ab73b62023aa573862001 (patch) | |
| tree | dc572840dcc97dd6abe4a9cfe7e279525211a124 | |
| parent | 8e17c9ba1443c2f21c5801f0c4660ac08dccc837 (diff) | |
| download | emacs-df9685f3961022245b9ab73b62023aa573862001.tar.gz emacs-df9685f3961022245b9ab73b62023aa573862001.zip | |
Fix bugs #12447 and #12326 with infloop causes by idle timers, update docs.
src/keyboard.c (timer_check_2): Move calculation of 'timers' and
'idle_timers' from here ...
(timer_check): ... to here. Use Fcopy_sequence to copy the timer
lists, to avoid infloops when the timer does something stupid,
like reinvoke itself with the same or smaller time-out.
lisp/emacs-lisp/timer.el (run-with-idle-timer)
(timer-activate-when-idle): Warn against reinvoking an idle timer
from within its own timer action.
doc/lispref/os.texi (Idle Timers): Warn against reinvoking an idle timer
from within its own timer action.
| -rw-r--r-- | doc/lispref/ChangeLog | 5 | ||||
| -rw-r--r-- | doc/lispref/os.texi | 7 | ||||
| -rw-r--r-- | lisp/ChangeLog | 6 | ||||
| -rw-r--r-- | lisp/emacs-lisp/timer.el | 15 | ||||
| -rw-r--r-- | src/ChangeLog | 9 | ||||
| -rw-r--r-- | src/keyboard.c | 34 |
6 files changed, 61 insertions, 15 deletions
diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index f1ae632267b..8acd12d82a8 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2012-09-22 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * os.texi (Idle Timers): Warn against reinvoking an idle timer | ||
| 4 | from within its own timer action. (Bug#12447) | ||
| 5 | |||
| 1 | 2012-09-22 Chong Yidong <cyd@gnu.org> | 6 | 2012-09-22 Chong Yidong <cyd@gnu.org> |
| 2 | 7 | ||
| 3 | * frames.texi (Pop-Up Menus): Minor clarification (Bug#11148). | 8 | * frames.texi (Pop-Up Menus): Minor clarification (Bug#11148). |
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index 6431ac8bead..68e53c78972 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi | |||
| @@ -1864,6 +1864,13 @@ It blocks out any idle timers that ought to run during that time. | |||
| 1864 | @end itemize | 1864 | @end itemize |
| 1865 | 1865 | ||
| 1866 | @noindent | 1866 | @noindent |
| 1867 | For similar reasons, do not write an idle timer function that sets | ||
| 1868 | up another idle time (including the same idle timer) with the | ||
| 1869 | @var{secs} argument less or equal to the current idleness time. Such | ||
| 1870 | a timer will run almost immediately, and continue running again and | ||
| 1871 | again, instead of waiting for the next time Emacs becomes idle. | ||
| 1872 | |||
| 1873 | @noindent | ||
| 1867 | The correct approach is for the idle timer to reschedule itself after | 1874 | The correct approach is for the idle timer to reschedule itself after |
| 1868 | a brief pause, using the method in the @code{timer-function} example | 1875 | a brief pause, using the method in the @code{timer-function} example |
| 1869 | above. | 1876 | above. |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index f18bfd73611..b0e91b675a3 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | 2012-09-22 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * emacs-lisp/timer.el (run-with-idle-timer) | ||
| 4 | (timer-activate-when-idle): Warn against reinvoking an idle timer | ||
| 5 | from within its own timer action. (Bug#12447) | ||
| 6 | |||
| 1 | 2012-09-22 Martin Rudalics <rudalics@gmx.at> | 7 | 2012-09-22 Martin Rudalics <rudalics@gmx.at> |
| 2 | 8 | ||
| 3 | * cus-start.el (window-combination-limit): Add new optional | 9 | * cus-start.el (window-combination-limit): Add new optional |
diff --git a/lisp/emacs-lisp/timer.el b/lisp/emacs-lisp/timer.el index 2248dde8c03..bcd582a6f88 100644 --- a/lisp/emacs-lisp/timer.el +++ b/lisp/emacs-lisp/timer.el | |||
| @@ -205,12 +205,19 @@ timers). If nil, allocate a new cell." | |||
| 205 | "Insert TIMER into `timer-idle-list'. | 205 | "Insert TIMER into `timer-idle-list'. |
| 206 | This arranges to activate TIMER whenever Emacs is next idle. | 206 | This arranges to activate TIMER whenever Emacs is next idle. |
| 207 | If optional argument DONT-WAIT is non-nil, set TIMER to activate | 207 | If optional argument DONT-WAIT is non-nil, set TIMER to activate |
| 208 | immediately, or at the right time, if Emacs is already idle. | 208 | immediately \(see beloe\), or at the right time, if Emacs is |
| 209 | already idle. | ||
| 209 | 210 | ||
| 210 | REUSE-CELL, if non-nil, is a cons cell to reuse when inserting | 211 | REUSE-CELL, if non-nil, is a cons cell to reuse when inserting |
| 211 | TIMER into `timer-idle-list' (usually a cell removed from that | 212 | TIMER into `timer-idle-list' (usually a cell removed from that |
| 212 | list by `cancel-timer-internal'; using this reduces consing for | 213 | list by `cancel-timer-internal'; using this reduces consing for |
| 213 | repeat timers). If nil, allocate a new cell." | 214 | repeat timers). If nil, allocate a new cell. |
| 215 | |||
| 216 | Using non-nil DONT-WAIT is not recommended when activating an | ||
| 217 | idle timer from an idle timer handler, if the timer being | ||
| 218 | activated has an idleness time that is smaller or equal to | ||
| 219 | the time of the current timer. That's because the activated | ||
| 220 | timer will fire right away." | ||
| 214 | (timer--activate timer (not dont-wait) reuse-cell 'idle)) | 221 | (timer--activate timer (not dont-wait) reuse-cell 'idle)) |
| 215 | 222 | ||
| 216 | (defalias 'disable-timeout 'cancel-timer) | 223 | (defalias 'disable-timeout 'cancel-timer) |
| @@ -403,7 +410,9 @@ The action is to call FUNCTION with arguments ARGS. | |||
| 403 | SECS may be an integer, a floating point number, or the internal | 410 | SECS may be an integer, a floating point number, or the internal |
| 404 | time format returned by, e.g., `current-idle-time'. | 411 | time format returned by, e.g., `current-idle-time'. |
| 405 | If Emacs is currently idle, and has been idle for N seconds (N < SECS), | 412 | If Emacs is currently idle, and has been idle for N seconds (N < SECS), |
| 406 | then it will call FUNCTION in SECS - N seconds from now. | 413 | then it will call FUNCTION in SECS - N seconds from now. Using |
| 414 | SECS <= N is not recommended if this function is invoked from an idle | ||
| 415 | timer, because FUNCTION will then be called immediately. | ||
| 407 | 416 | ||
| 408 | If REPEAT is non-nil, do the action each time Emacs has been idle for | 417 | If REPEAT is non-nil, do the action each time Emacs has been idle for |
| 409 | exactly SECS seconds (that is, only once for each time Emacs becomes idle). | 418 | exactly SECS seconds (that is, only once for each time Emacs becomes idle). |
diff --git a/src/ChangeLog b/src/ChangeLog index 6ea40b3f122..b69d4bb7113 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,12 @@ | |||
| 1 | 2012-09-22 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * keyboard.c (timer_check_2): Move calculation of 'timers' and | ||
| 4 | 'idle_timers' from here ... | ||
| 5 | (timer_check): ... to here. Use Fcopy_sequence to copy the timer | ||
| 6 | lists, to avoid infloops when the timer does something stupid, | ||
| 7 | like reinvoke itself with the same or smaller time-out. | ||
| 8 | (Bug#12447) | ||
| 9 | |||
| 1 | 2012-09-22 Martin Rudalics <rudalics@gmx.at> | 10 | 2012-09-22 Martin Rudalics <rudalics@gmx.at> |
| 2 | 11 | ||
| 3 | * window.c (Fsplit_window_internal): Handle only Qt value of | 12 | * window.c (Fsplit_window_internal): Handle only Qt value of |
diff --git a/src/keyboard.c b/src/keyboard.c index 098d3530ef8..8b1113a026a 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -4333,25 +4333,18 @@ decode_timer (Lisp_Object timer, EMACS_TIME *result) | |||
| 4333 | should be done. */ | 4333 | should be done. */ |
| 4334 | 4334 | ||
| 4335 | static EMACS_TIME | 4335 | static EMACS_TIME |
| 4336 | timer_check_2 (void) | 4336 | timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers) |
| 4337 | { | 4337 | { |
| 4338 | EMACS_TIME nexttime; | 4338 | EMACS_TIME nexttime; |
| 4339 | EMACS_TIME now; | 4339 | EMACS_TIME now; |
| 4340 | EMACS_TIME idleness_now; | 4340 | EMACS_TIME idleness_now; |
| 4341 | Lisp_Object timers, idle_timers, chosen_timer; | 4341 | Lisp_Object chosen_timer; |
| 4342 | struct gcpro gcpro1, gcpro2, gcpro3; | 4342 | struct gcpro gcpro1; |
| 4343 | 4343 | ||
| 4344 | nexttime = invalid_emacs_time (); | 4344 | nexttime = invalid_emacs_time (); |
| 4345 | 4345 | ||
| 4346 | /* Always consider the ordinary timers. */ | ||
| 4347 | timers = Vtimer_list; | ||
| 4348 | /* Consider the idle timers only if Emacs is idle. */ | ||
| 4349 | if (EMACS_TIME_VALID_P (timer_idleness_start_time)) | ||
| 4350 | idle_timers = Vtimer_idle_list; | ||
| 4351 | else | ||
| 4352 | idle_timers = Qnil; | ||
| 4353 | chosen_timer = Qnil; | 4346 | chosen_timer = Qnil; |
| 4354 | GCPRO3 (timers, idle_timers, chosen_timer); | 4347 | GCPRO1 (chosen_timer); |
| 4355 | 4348 | ||
| 4356 | /* First run the code that was delayed. */ | 4349 | /* First run the code that was delayed. */ |
| 4357 | while (CONSP (pending_funcalls)) | 4350 | while (CONSP (pending_funcalls)) |
| @@ -4500,13 +4493,30 @@ EMACS_TIME | |||
| 4500 | timer_check (void) | 4493 | timer_check (void) |
| 4501 | { | 4494 | { |
| 4502 | EMACS_TIME nexttime; | 4495 | EMACS_TIME nexttime; |
| 4496 | Lisp_Object timers, idle_timers; | ||
| 4497 | struct gcpro gcpro1, gcpro2; | ||
| 4498 | |||
| 4499 | /* We use copies of the timers' lists to allow a timer to add itself | ||
| 4500 | again, without locking up Emacs if the newly added timer is | ||
| 4501 | already ripe when added. */ | ||
| 4502 | |||
| 4503 | /* Always consider the ordinary timers. */ | ||
| 4504 | timers = Fcopy_sequence (Vtimer_list); | ||
| 4505 | /* Consider the idle timers only if Emacs is idle. */ | ||
| 4506 | if (EMACS_TIME_VALID_P (timer_idleness_start_time)) | ||
| 4507 | idle_timers = Fcopy_sequence (Vtimer_idle_list); | ||
| 4508 | else | ||
| 4509 | idle_timers = Qnil; | ||
| 4510 | |||
| 4511 | GCPRO2 (timers, idle_timers); | ||
| 4503 | 4512 | ||
| 4504 | do | 4513 | do |
| 4505 | { | 4514 | { |
| 4506 | nexttime = timer_check_2 (); | 4515 | nexttime = timer_check_2 (timers, idle_timers); |
| 4507 | } | 4516 | } |
| 4508 | while (EMACS_SECS (nexttime) == 0 && EMACS_NSECS (nexttime) == 0); | 4517 | while (EMACS_SECS (nexttime) == 0 && EMACS_NSECS (nexttime) == 0); |
| 4509 | 4518 | ||
| 4519 | UNGCPRO; | ||
| 4510 | return nexttime; | 4520 | return nexttime; |
| 4511 | } | 4521 | } |
| 4512 | 4522 | ||