aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2019-04-24 18:39:05 +0200
committerMattias EngdegÄrd2019-04-30 13:25:52 +0200
commitc61bbb4c8e7e2f2068c1cfac9a001806a1969202 (patch)
tree2708a16e72d6099b676c7e50d0ef11fe11e194c3
parentf478082f9ff22ff41fbd9616ebea75757f9a0311 (diff)
downloademacs-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.texi14
-rw-r--r--etc/NEWS10
-rw-r--r--lisp/autorevert.el124
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}.
988supported, @code{auto-revert-use-notify} will be @code{nil} by 988supported, @code{auto-revert-use-notify} will be @code{nil} by
989default. 989default.
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
994periodically even when file notifications are used. Such polling is
995usually unnecessary, and turning it off may save power by relying on
996notifications only. To do so, set the variable
997@code{auto-revert-avoid-polling} to non-@code{nil}. However,
998notification is ineffective on certain file systems; mainly network
999file system on Unix-like machines, where files can be altered from
1000other 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
1003should 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
992log, so that changes made to that file by other programs are 1006log, so that changes made to that file by other programs are
993continuously displayed. To do this, just move the point to the end of 1007continuously displayed. To do this, just move the point to the end of
diff --git a/etc/NEWS b/etc/NEWS
index 9b32d720b62..f6676e0e0b6 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1389,6 +1389,16 @@ Packages deriving from 'js-mode' with 'define-derived-mode' should
1389call this function to add enabled syntax extensions to their mode 1389call this function to add enabled syntax extensions to their mode
1390name, too. 1390name, too.
1391 1391
1392** Autorevert
1393
1394*** New variable 'auto-revert-avoid-polling' for saving power.
1395When set to a non-nil value, buffers in Auto-Revert mode are no longer
1396polled for changes periodically. This reduces the power consumption
1397of an idle Emacs, but may fail on some network file systems; set
1398'auto-revert-notify-exclude-dir-regexp' to match files where
1399notification is not supported. The new variable currently has no
1400effect 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
308Set this variable to a non-nil value to save power by avoiding
309polling when possible. Files on file-systems that do not support
310change notifications must match `auto-revert-notify-exclude-dir-regexp'
311for Auto-Revert to work properly in this case. This typically
312includes files on network file systems on Unix-like machines,
313when those files are modified from another computer.
314
315When nil, buffers in Auto-Revert Mode will always be polled for
316changes to their files on disk every `auto-revert-interval'
317seconds, in addition to using notification for those files.
318
319In Global Auto-Revert Mode, polling is always done regardless of
320the 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.
487If such a timer is active, cancel it. Start a new timer if 533If 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 614This is the quiescence after each notification of a file being
569update the buffer on a notification event or not. If 615changed during which no automatic reverting takes place, to
570 616prevent many updates in rapid succession from overwhelming the
571 (= auto-revert-buffers-counter-lockedout 617system.")
572 auto-revert-buffers-counter) 618
573 619(defvar-local auto-revert--lockout-timer nil
574then the updates are locked out, and we wait until the next call 620 "Timer awaiting the end of the notification lockout interval, or nil.")
575of `auto-revert-buffers' to revert the buffer. If no lockout is
576present, then we revert immediately and set the lockout, so that
577no 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.
688If 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
755Auto-Revert Mode from `auto-revert-buffer-list', and for canceling 811Auto-Revert Mode from `auto-revert-buffer-list', and for canceling
756the timer when no buffers need to be checked." 812the 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)))))