diff options
| author | Mattias EngdegÄrd | 2019-04-24 18:39:05 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2019-04-30 13:25:52 +0200 |
| commit | c61bbb4c8e7e2f2068c1cfac9a001806a1969202 (patch) | |
| tree | 2708a16e72d6099b676c7e50d0ef11fe11e194c3 | |
| parent | f478082f9ff22ff41fbd9616ebea75757f9a0311 (diff) | |
| download | emacs-c61bbb4c8e7e2f2068c1cfac9a001806a1969202.tar.gz emacs-c61bbb4c8e7e2f2068c1cfac9a001806a1969202.zip | |
Don't poll auto-revert files that use notification (bug#35418)
It is a waste to periodically poll files that use change notification
in auto-revert mode; stop doing that. If no files need polling,
turn off the periodic execution entirely to further avoid wasting power.
Use a timer to inhibit immediate reversion for some time after a
notification, for throttling.
This change does not apply to files in global-auto-revert-mode, where
polling is still necessary. It is disabled by default, and enabled by
setting `auto-revert-avoid-polling' to non-nil.
* lisp/autorevert.el
(toplevel): Require cl-lib.
(auto-revert-avoid-polling, auto-revert--polled-buffers)
(auto-revert--need-polling-p, auto-revert--lockout-interval)
(auto-revert--lockout-timer, auto-revert--end-lockout): New.
(global-auto-revert-mode): Keep notifiers for buffers in auto-revert mode.
(auto-revert-set-timer): Use auto-revert--need-polling-p.
(auto-revert-notify-handler): Restart polling if notification stopped.
Use new lockout timer.
(auto-revert-buffers):
Use auto-revert--polled-buffers and auto-revert--need-polling-p.
(auto-revert-buffers-counter, auto-revert-buffers-counter-lockedout):
Remove.
* etc/NEWS (Changes in Specialized Modes and Packages):
Describe the new auto-revert-avoid-polling variable.
* doc/emacs/files.texi (Reverting):
Add paragraph describing auto-revert-avoid-polling.
| -rw-r--r-- | doc/emacs/files.texi | 14 | ||||
| -rw-r--r-- | etc/NEWS | 10 | ||||
| -rw-r--r-- | lisp/autorevert.el | 124 |
3 files changed, 111 insertions, 37 deletions
diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi index a57428230cc..990b8f16795 100644 --- a/doc/emacs/files.texi +++ b/doc/emacs/files.texi | |||
| @@ -988,6 +988,20 @@ the polling interval through the variable @code{auto-revert-interval}. | |||
| 988 | supported, @code{auto-revert-use-notify} will be @code{nil} by | 988 | supported, @code{auto-revert-use-notify} will be @code{nil} by |
| 989 | default. | 989 | default. |
| 990 | 990 | ||
| 991 | @vindex auto-revert-avoid-polling | ||
| 992 | @vindex auto-revert-notify-exclude-dir-regexp | ||
| 993 | By default, Auto-Revert mode will poll files for changes | ||
| 994 | periodically even when file notifications are used. Such polling is | ||
| 995 | usually unnecessary, and turning it off may save power by relying on | ||
| 996 | notifications only. To do so, set the variable | ||
| 997 | @code{auto-revert-avoid-polling} to non-@code{nil}. However, | ||
| 998 | notification is ineffective on certain file systems; mainly network | ||
| 999 | file system on Unix-like machines, where files can be altered from | ||
| 1000 | other machines. To force polling when | ||
| 1001 | @code{auto-revert-avoid-polling} is non-@code{nil}, set | ||
| 1002 | @code{auto-revert-notify-exclude-dir-regexp} to match files that | ||
| 1003 | should be excluded from using notification. | ||
| 1004 | |||
| 991 | One use of Auto-Revert mode is to ``tail'' a file such as a system | 1005 | One use of Auto-Revert mode is to ``tail'' a file such as a system |
| 992 | log, so that changes made to that file by other programs are | 1006 | log, so that changes made to that file by other programs are |
| 993 | continuously displayed. To do this, just move the point to the end of | 1007 | continuously displayed. To do this, just move the point to the end of |
| @@ -1389,6 +1389,16 @@ Packages deriving from 'js-mode' with 'define-derived-mode' should | |||
| 1389 | call this function to add enabled syntax extensions to their mode | 1389 | call this function to add enabled syntax extensions to their mode |
| 1390 | name, too. | 1390 | name, too. |
| 1391 | 1391 | ||
| 1392 | ** Autorevert | ||
| 1393 | |||
| 1394 | *** New variable 'auto-revert-avoid-polling' for saving power. | ||
| 1395 | When set to a non-nil value, buffers in Auto-Revert mode are no longer | ||
| 1396 | polled for changes periodically. This reduces the power consumption | ||
| 1397 | of an idle Emacs, but may fail on some network file systems; set | ||
| 1398 | 'auto-revert-notify-exclude-dir-regexp' to match files where | ||
| 1399 | notification is not supported. The new variable currently has no | ||
| 1400 | effect in 'global-auto-revert-mode'. The default value is nil. | ||
| 1401 | |||
| 1392 | 1402 | ||
| 1393 | * New Modes and Packages in Emacs 27.1 | 1403 | * New Modes and Packages in Emacs 27.1 |
| 1394 | 1404 | ||
diff --git a/lisp/autorevert.el b/lisp/autorevert.el index 1d20896c839..6f5ca75ddf8 100644 --- a/lisp/autorevert.el +++ b/lisp/autorevert.el | |||
| @@ -107,7 +107,7 @@ | |||
| 107 | 107 | ||
| 108 | ;; Dependencies: | 108 | ;; Dependencies: |
| 109 | 109 | ||
| 110 | (eval-when-compile (require 'cl-lib)) | 110 | (require 'cl-lib) |
| 111 | (require 'timer) | 111 | (require 'timer) |
| 112 | (require 'filenotify) | 112 | (require 'filenotify) |
| 113 | 113 | ||
| @@ -302,6 +302,29 @@ You should set this variable through Custom." | |||
| 302 | :type 'regexp | 302 | :type 'regexp |
| 303 | :version "24.4") | 303 | :version "24.4") |
| 304 | 304 | ||
| 305 | (defcustom auto-revert-avoid-polling nil | ||
| 306 | "Non-nil to avoid polling files when notification is available. | ||
| 307 | |||
| 308 | Set this variable to a non-nil value to save power by avoiding | ||
| 309 | polling when possible. Files on file-systems that do not support | ||
| 310 | change notifications must match `auto-revert-notify-exclude-dir-regexp' | ||
| 311 | for Auto-Revert to work properly in this case. This typically | ||
| 312 | includes files on network file systems on Unix-like machines, | ||
| 313 | when those files are modified from another computer. | ||
| 314 | |||
| 315 | When nil, buffers in Auto-Revert Mode will always be polled for | ||
| 316 | changes to their files on disk every `auto-revert-interval' | ||
| 317 | seconds, in addition to using notification for those files. | ||
| 318 | |||
| 319 | In Global Auto-Revert Mode, polling is always done regardless of | ||
| 320 | the value of this variable." | ||
| 321 | :group 'auto-revert | ||
| 322 | :type 'boolean | ||
| 323 | :set (lambda (variable value) | ||
| 324 | (set-default variable value) | ||
| 325 | (auto-revert-set-timer)) | ||
| 326 | :version "27.1") | ||
| 327 | |||
| 305 | ;; Internal variables: | 328 | ;; Internal variables: |
| 306 | 329 | ||
| 307 | (defvar auto-revert-buffer-list () | 330 | (defvar auto-revert-buffer-list () |
| @@ -479,9 +502,32 @@ specifies in the mode line." | |||
| 479 | (auto-revert-buffers) | 502 | (auto-revert-buffers) |
| 480 | (dolist (buf (buffer-list)) | 503 | (dolist (buf (buffer-list)) |
| 481 | (with-current-buffer buf | 504 | (with-current-buffer buf |
| 482 | (when auto-revert-notify-watch-descriptor | 505 | (when (and auto-revert-notify-watch-descriptor |
| 506 | (not (memq buf auto-revert-buffer-list))) | ||
| 483 | (auto-revert-notify-rm-watch)))))) | 507 | (auto-revert-notify-rm-watch)))))) |
| 484 | 508 | ||
| 509 | (defun auto-revert--polled-buffers () | ||
| 510 | "List of buffers that need to be polled." | ||
| 511 | (cond (global-auto-revert-mode (buffer-list)) | ||
| 512 | (auto-revert-avoid-polling | ||
| 513 | (mapcan (lambda (buffer) | ||
| 514 | (and (not (buffer-local-value | ||
| 515 | 'auto-revert-notify-watch-descriptor buffer)) | ||
| 516 | (list buffer))) | ||
| 517 | auto-revert-buffer-list)) | ||
| 518 | (t auto-revert-buffer-list))) | ||
| 519 | |||
| 520 | ;; Same as above in a boolean context, but cheaper. | ||
| 521 | (defun auto-revert--need-polling-p () | ||
| 522 | "Whether periodic polling is required." | ||
| 523 | (or global-auto-revert-mode | ||
| 524 | (if auto-revert-avoid-polling | ||
| 525 | (not (cl-every (lambda (buffer) | ||
| 526 | (buffer-local-value | ||
| 527 | 'auto-revert-notify-watch-descriptor buffer)) | ||
| 528 | auto-revert-buffer-list)) | ||
| 529 | auto-revert-buffer-list))) | ||
| 530 | |||
| 485 | (defun auto-revert-set-timer () | 531 | (defun auto-revert-set-timer () |
| 486 | "Restart or cancel the timer used by Auto-Revert Mode. | 532 | "Restart or cancel the timer used by Auto-Revert Mode. |
| 487 | If such a timer is active, cancel it. Start a new timer if | 533 | If such a timer is active, cancel it. Start a new timer if |
| @@ -492,10 +538,10 @@ will use an up-to-date value of `auto-revert-interval'" | |||
| 492 | (if (timerp auto-revert-timer) | 538 | (if (timerp auto-revert-timer) |
| 493 | (cancel-timer auto-revert-timer)) | 539 | (cancel-timer auto-revert-timer)) |
| 494 | (setq auto-revert-timer | 540 | (setq auto-revert-timer |
| 495 | (if (or global-auto-revert-mode auto-revert-buffer-list) | 541 | (and (auto-revert--need-polling-p) |
| 496 | (run-with-timer auto-revert-interval | 542 | (run-with-timer auto-revert-interval |
| 497 | auto-revert-interval | 543 | auto-revert-interval |
| 498 | 'auto-revert-buffers)))) | 544 | 'auto-revert-buffers)))) |
| 499 | 545 | ||
| 500 | (defun auto-revert-notify-rm-watch () | 546 | (defun auto-revert-notify-rm-watch () |
| 501 | "Disable file notification for current buffer's associated file." | 547 | "Disable file notification for current buffer's associated file." |
| @@ -558,24 +604,20 @@ will use an up-to-date value of `auto-revert-interval'" | |||
| 558 | ;; often, we want to skip some revert operations so that we don't spend all our | 604 | ;; often, we want to skip some revert operations so that we don't spend all our |
| 559 | ;; time reverting the buffer. | 605 | ;; time reverting the buffer. |
| 560 | ;; | 606 | ;; |
| 561 | ;; We do this by reverting immediately in response to the first in a flurry of | 607 | ;; We do this by reverting immediately in response to the first in a |
| 562 | ;; notifications. We suppress subsequent notifications until the next time | 608 | ;; flurry of notifications. Any notifications during the following |
| 563 | ;; `auto-revert-buffers' is called (this happens on a timer with a period set by | 609 | ;; `auto-revert-lockout-interval' seconds are noted but not acted upon |
| 564 | ;; `auto-revert-interval'). | 610 | ;; until the end of that interval. |
| 565 | (defvar auto-revert-buffers-counter 1 | 611 | |
| 566 | "Incremented each time `auto-revert-buffers' is called") | 612 | (defconst auto-revert--lockout-interval 2.5 |
| 567 | (defvar-local auto-revert-buffers-counter-lockedout 0 | 613 | "Duration, in seconds, of the Auto-Revert Mode notification lockout. |
| 568 | "Buffer-local value to indicate whether we should immediately | 614 | This is the quiescence after each notification of a file being |
| 569 | update the buffer on a notification event or not. If | 615 | changed during which no automatic reverting takes place, to |
| 570 | 616 | prevent many updates in rapid succession from overwhelming the | |
| 571 | (= auto-revert-buffers-counter-lockedout | 617 | system.") |
| 572 | auto-revert-buffers-counter) | 618 | |
| 573 | 619 | (defvar-local auto-revert--lockout-timer nil | |
| 574 | then the updates are locked out, and we wait until the next call | 620 | "Timer awaiting the end of the notification lockout interval, or nil.") |
| 575 | of `auto-revert-buffers' to revert the buffer. If no lockout is | ||
| 576 | present, then we revert immediately and set the lockout, so that | ||
| 577 | no more reverts are possible until the next call of | ||
| 578 | `auto-revert-buffers'") | ||
| 579 | 621 | ||
| 580 | (defun auto-revert-notify-handler (event) | 622 | (defun auto-revert-notify-handler (event) |
| 581 | "Handle an EVENT returned from file notification." | 623 | "Handle an EVENT returned from file notification." |
| @@ -604,7 +646,11 @@ no more reverts are possible until the next call of | |||
| 604 | (file-name-nondirectory buffer-file-name))) | 646 | (file-name-nondirectory buffer-file-name))) |
| 605 | ;; A buffer w/o a file, like dired. | 647 | ;; A buffer w/o a file, like dired. |
| 606 | (null buffer-file-name)) | 648 | (null buffer-file-name)) |
| 607 | (auto-revert-notify-rm-watch)))) | 649 | (auto-revert-notify-rm-watch) |
| 650 | ;; Restart the timer if it wasn't running. | ||
| 651 | (when (and (memq buffer auto-revert-buffer-list) | ||
| 652 | (not auto-revert-timer)) | ||
| 653 | (auto-revert-set-timer))))) | ||
| 608 | 654 | ||
| 609 | ;; Loop over all buffers, in order to find the intended one. | 655 | ;; Loop over all buffers, in order to find the intended one. |
| 610 | (cl-dolist (buffer buffers) | 656 | (cl-dolist (buffer buffers) |
| @@ -630,11 +676,21 @@ no more reverts are possible until the next call of | |||
| 630 | (setq auto-revert-notify-modified-p t) | 676 | (setq auto-revert-notify-modified-p t) |
| 631 | 677 | ||
| 632 | ;; Revert the buffer now if we're not locked out. | 678 | ;; Revert the buffer now if we're not locked out. |
| 633 | (when (/= auto-revert-buffers-counter-lockedout | 679 | (unless auto-revert--lockout-timer |
| 634 | auto-revert-buffers-counter) | ||
| 635 | (auto-revert-handler) | 680 | (auto-revert-handler) |
| 636 | (setq auto-revert-buffers-counter-lockedout | 681 | (setq auto-revert--lockout-timer |
| 637 | auto-revert-buffers-counter)))))))))) | 682 | (run-with-timer |
| 683 | auto-revert--lockout-interval nil | ||
| 684 | #'auto-revert--end-lockout buffer))))))))))) | ||
| 685 | |||
| 686 | (defun auto-revert--end-lockout (buffer) | ||
| 687 | "End the lockout period after a notification. | ||
| 688 | If the buffer needs to be reverted, do it now." | ||
| 689 | (when (buffer-live-p buffer) | ||
| 690 | (with-current-buffer buffer | ||
| 691 | (setq auto-revert--lockout-timer nil) | ||
| 692 | (when auto-revert-notify-modified-p | ||
| 693 | (auto-revert-handler))))) | ||
| 638 | 694 | ||
| 639 | (defun auto-revert-active-p () | 695 | (defun auto-revert-active-p () |
| 640 | "Check if auto-revert is active (in current buffer or globally)." | 696 | "Check if auto-revert is active (in current buffer or globally)." |
| @@ -755,13 +811,8 @@ This function is also responsible for removing buffers no longer in | |||
| 755 | Auto-Revert Mode from `auto-revert-buffer-list', and for canceling | 811 | Auto-Revert Mode from `auto-revert-buffer-list', and for canceling |
| 756 | the timer when no buffers need to be checked." | 812 | the timer when no buffers need to be checked." |
| 757 | 813 | ||
| 758 | (setq auto-revert-buffers-counter | ||
| 759 | (1+ auto-revert-buffers-counter)) | ||
| 760 | |||
| 761 | (save-match-data | 814 | (save-match-data |
| 762 | (let ((bufs (if global-auto-revert-mode | 815 | (let ((bufs (auto-revert--polled-buffers)) |
| 763 | (buffer-list) | ||
| 764 | auto-revert-buffer-list)) | ||
| 765 | remaining new) | 816 | remaining new) |
| 766 | ;; Buffers with remote contents shall be reverted only if the | 817 | ;; Buffers with remote contents shall be reverted only if the |
| 767 | ;; connection is established already. | 818 | ;; connection is established already. |
| @@ -810,8 +861,7 @@ the timer when no buffers need to be checked." | |||
| 810 | (setq bufs (cdr bufs))) | 861 | (setq bufs (cdr bufs))) |
| 811 | (setq auto-revert-remaining-buffers bufs) | 862 | (setq auto-revert-remaining-buffers bufs) |
| 812 | ;; Check if we should cancel the timer. | 863 | ;; Check if we should cancel the timer. |
| 813 | (when (and (not global-auto-revert-mode) | 864 | (unless (auto-revert--need-polling-p) |
| 814 | (null auto-revert-buffer-list)) | ||
| 815 | (if (timerp auto-revert-timer) | 865 | (if (timerp auto-revert-timer) |
| 816 | (cancel-timer auto-revert-timer)) | 866 | (cancel-timer auto-revert-timer)) |
| 817 | (setq auto-revert-timer nil))))) | 867 | (setq auto-revert-timer nil))))) |