aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/NEWS2
-rw-r--r--lisp/proced.el296
2 files changed, 195 insertions, 103 deletions
diff --git a/etc/NEWS b/etc/NEWS
index dc60aaa138f..5595fafd37f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -411,6 +411,8 @@ server properties.
411** In Perl mode, new option `perl-indent-parens-as-block' causes non-block 411** In Perl mode, new option `perl-indent-parens-as-block' causes non-block
412closing brackets to be aligned with the line of the opening bracket. 412closing brackets to be aligned with the line of the opening bracket.
413 413
414** In Proced mode, new command `proced-renice' renices selected processes.
415
414** Python mode 416** Python mode
415 417
416A new version of python.el, which provides several new features, including: 418A new version of python.el, which provides several new features, including:
diff --git a/lisp/proced.el b/lisp/proced.el
index d98bf7d2c5b..be6cae2ef08 100644
--- a/lisp/proced.el
+++ b/lisp/proced.el
@@ -28,8 +28,11 @@
28;; listed. See `proced-mode' for getting started. 28;; listed. See `proced-mode' for getting started.
29;; 29;;
30;; To do: 30;; To do:
31;; - interactive temporary customizability of flags in `proced-grammar-alist' 31;; - Interactive temporary customizability of flags in `proced-grammar-alist'
32;; - allow "sudo kill PID", "renice PID" 32;; - Allow "sudo kill PID", "sudo renice PID"
33;; `proced-send-signal' operates on multiple processes one by one.
34;; With "sudo" we want to execute one "kill" or "renice" command
35;; for all marked processes. Is there a `sudo-call-process'?
33;; 36;;
34;; Thoughts and Ideas 37;; Thoughts and Ideas
35;; - Currently, `process-attributes' returns the list of 38;; - Currently, `process-attributes' returns the list of
@@ -62,6 +65,11 @@ the external command (usually \"kill\")."
62 :type '(choice (function :tag "function") 65 :type '(choice (function :tag "function")
63 (string :tag "command"))) 66 (string :tag "command")))
64 67
68(defcustom proced-renice-command "renice"
69 "Name of renice command."
70 :group 'proced
71 :type '(string :tag "command"))
72
65(defcustom proced-signal-list 73(defcustom proced-signal-list
66 '( ;; signals supported on all POSIX compliant systems 74 '( ;; signals supported on all POSIX compliant systems
67 ("HUP" . " (1. Hangup)") 75 ("HUP" . " (1. Hangup)")
@@ -491,6 +499,7 @@ Important: the match ends just after the marker.")
491 (define-key km "o" 'proced-omit-processes) 499 (define-key km "o" 'proced-omit-processes)
492 (define-key km "x" 'proced-send-signal) ; Dired compatibility 500 (define-key km "x" 'proced-send-signal) ; Dired compatibility
493 (define-key km "k" 'proced-send-signal) ; kill processes 501 (define-key km "k" 'proced-send-signal) ; kill processes
502 (define-key km "r" 'proced-renice) ; renice processes
494 ;; misc 503 ;; misc
495 (define-key km "h" 'describe-mode) 504 (define-key km "h" 'describe-mode)
496 (define-key km "?" 'proced-help) 505 (define-key km "?" 'proced-help)
@@ -561,8 +570,11 @@ Important: the match ends just after the marker.")
561 :style toggle 570 :style toggle
562 :selected (eval proced-auto-update-flag) 571 :selected (eval proced-auto-update-flag)
563 :help "Auto Update of Proced Buffer"] 572 :help "Auto Update of Proced Buffer"]
573 "--"
564 ["Send signal" proced-send-signal 574 ["Send signal" proced-send-signal
565 :help "Send Signal to Marked Processes"])) 575 :help "Send Signal to Marked Processes"]
576 ["Renice" proced-renice
577 :help "Renice Marked Processes"]))
566 578
567;; helper functions 579;; helper functions
568(defun proced-marker-regexp () 580(defun proced-marker-regexp ()
@@ -1686,14 +1698,11 @@ After updating a displayed Proced buffer run the normal hook
1686Preserves point and marks." 1698Preserves point and marks."
1687 (proced-update t)) 1699 (proced-update t))
1688 1700
1689(defun proced-send-signal (&optional signal) 1701(defun proced-marked-processes ()
1690 "Send a SIGNAL to the marked processes. 1702 "Return marked processes as alist of PIDs.
1691If no process is marked, operate on current process. 1703If no process is marked return alist with the PID of the process point is on.
1692SIGNAL may be a string (HUP, INT, TERM, etc.) or a number. 1704The cdrs of the alist are the text strings displayed by Proced for these
1693If SIGNAL is nil display marked processes and query interactively for SIGNAL. 1705processes. They are used for error messages."
1694After sending the signal, this command runs the normal hook
1695`proced-after-send-signal-hook'."
1696 (interactive)
1697 (let ((regexp (proced-marker-regexp)) 1706 (let ((regexp (proced-marker-regexp))
1698 process-alist) 1707 process-alist)
1699 ;; collect marked processes 1708 ;; collect marked processes
@@ -1706,102 +1715,183 @@ After sending the signal, this command runs the normal hook
1706 (+ 2 (line-beginning-position)) 1715 (+ 2 (line-beginning-position))
1707 (line-end-position))) 1716 (line-end-position)))
1708 process-alist))) 1717 process-alist)))
1709 (setq process-alist 1718 (if process-alist
1710 (if process-alist 1719 (nreverse process-alist)
1711 (nreverse process-alist) 1720 ;; take current process
1712 ;; take current process 1721 (let ((pid (proced-pid-at-point)))
1713 (list (cons (proced-pid-at-point) 1722 (if pid
1723 (list (cons pid
1714 (buffer-substring-no-properties 1724 (buffer-substring-no-properties
1715 (+ 2 (line-beginning-position)) 1725 (+ 2 (line-beginning-position))
1716 (line-end-position)))))) 1726 (line-end-position)))))))))
1727
1728(defmacro proced-with-processes-buffer (process-alist &rest body)
1729 "Execute the forms in BODY in a temporary buffer displaying PROCESS-ALIST.
1730PROCESS-ALIST is an alist of process PIDs as in `proced-process-alist'.
1731The value returned is the value of the last form in BODY."
1732 (declare (indent 1) (debug t))
1733 ;; Use leading space in buffer name to make this buffer ephemeral
1734 `(let ((bufname " *Marked Processes*")
1735 (header-line (substring-no-properties proced-header-line)))
1736 (with-current-buffer (get-buffer-create bufname)
1737 (setq truncate-lines t
1738 proced-header-line header-line ; inherit header line
1739 header-line-format '(:eval (proced-header-line)))
1740 (add-hook 'post-command-hook 'force-mode-line-update nil t)
1741 (let ((inhibit-read-only t))
1742 (erase-buffer)
1743 (buffer-disable-undo)
1744 (setq buffer-read-only t)
1745 (dolist (process ,process-alist)
1746 (insert " " (cdr process) "\n"))
1747 (delete-char -1)
1748 (goto-char (point-min)))
1749 (save-window-excursion
1750 ;; Analogous to `dired-pop-to-buffer'
1751 ;; Don't split window horizontally. (Bug#1806)
1752 (let (split-width-threshold)
1753 (pop-to-buffer (current-buffer)))
1754 (fit-window-to-buffer (get-buffer-window) nil 1)
1755 ,@body))))
1756
1757(defun proced-send-signal (&optional signal process-alist)
1758 "Send a SIGNAL to processes in PROCESS-ALIST.
1759PROCESS-ALIST is an alist as returned by `proced-marked-processes'.
1760Interactively, PROCESS-ALIST contains the marked processes.
1761If no process is marked, it contains the process point is on,
1762SIGNAL may be a string (HUP, INT, TERM, etc.) or a number.
1763After sending SIGNAL to all processes in PROCESS-ALIST, this command
1764runs the normal hook `proced-after-send-signal-hook'.
1765
1766For backward compatibility SIGNAL and PROCESS-ALIST may be nil.
1767Then PROCESS-ALIST contains the marked processes or the process point is on
1768and SIGNAL is queried interactively. This noninteractive usage is still
1769supported but discouraged. It will be removed in a future version of Emacs."
1770 (interactive
1771 (let* ((process-alist (proced-marked-processes))
1772 (pnum (if (= 1 (length process-alist))
1773 "1 process"
1774 (format "%d processes" (length process-alist))))
1775 (completion-ignore-case t)
1776 (completion-extra-properties
1777 '(:annotation-function
1778 (lambda (s) (cdr (assoc s proced-signal-list))))))
1779 (proced-with-processes-buffer process-alist
1780 (list (completing-read (concat "Send signal [" pnum
1781 "] (default TERM): ")
1782 proced-signal-list
1783 nil nil nil nil "TERM")
1784 process-alist))))
1785
1786 (unless (and signal process-alist)
1787 ;; Discouraged usge (supported for backward compatibility):
1788 ;; The new calling sequence separates more cleanly between the parts
1789 ;; of the code required for interactive and noninteractive calls so that
1790 ;; the command can be used more flexibly in noninteractive ways, too.
1791 (unless (get 'proced-send-signal 'proced-outdated)
1792 (put 'proced-send-signal 'proced-outdated t)
1793 (message "Outdated usage of `proced-send-signal'")
1794 (sit-for 2))
1795 (setq process-alist (proced-marked-processes))
1717 (unless signal 1796 (unless signal
1718 ;; Display marked processes (code taken from `dired-mark-pop-up'). 1797 (let ((pnum (if (= 1 (length process-alist))
1719 (let ((bufname " *Marked Processes*") ; use leading space in buffer name 1798 "1 process"
1720 ; to make this buffer ephemeral 1799 (format "%d processes" (length process-alist))))
1721 (header-line (substring-no-properties proced-header-line))) 1800 (completion-ignore-case t)
1722 (with-current-buffer (get-buffer-create bufname) 1801 (completion-extra-properties
1723 (setq truncate-lines t 1802 '(:annotation-function
1724 proced-header-line header-line ; inherit header line 1803 (lambda (s) (cdr (assoc s proced-signal-list))))))
1725 header-line-format '(:eval (proced-header-line))) 1804 (proced-with-processes-buffer process-alist
1726 (add-hook 'post-command-hook 'force-mode-line-update nil t) 1805 (setq signal (completing-read (concat "Send signal [" pnum
1727 (let ((inhibit-read-only t)) 1806 "] (default TERM): ")
1728 (erase-buffer) 1807 proced-signal-list
1729 (buffer-disable-undo) 1808 nil nil nil nil "TERM"))))))
1730 (setq buffer-read-only t) 1809
1731 (dolist (process process-alist) 1810 (let (failures)
1732 (insert " " (cdr process) "\n")) 1811 ;; Why not always use `signal-process'? See
1733 (delete-char -1) 1812 ;; http://lists.gnu.org/archive/html/emacs-devel/2008-03/msg02955.html
1734 (goto-char (point-min))) 1813 (if (functionp proced-signal-function)
1735 (save-window-excursion 1814 ;; use built-in `signal-process'
1736 ;; Analogous to `dired-pop-to-buffer' 1815 (let ((signal (if (stringp signal)
1737 ;; Don't split window horizontally. (Bug#1806) 1816 (if (string-match "\\`[0-9]+\\'" signal)
1738 (let (split-width-threshold) 1817 (string-to-number signal)
1739 (pop-to-buffer (current-buffer))) 1818 (make-symbol signal))
1740 (fit-window-to-buffer (get-buffer-window) nil 1) 1819 signal))) ; number
1741 (let* ((completion-ignore-case t)
1742 (pnum (if (= 1 (length process-alist))
1743 "1 process"
1744 (format "%d processes" (length process-alist))))
1745 (completion-extra-properties
1746 '(:annotation-function
1747 (lambda (s) (cdr (assoc s proced-signal-list))))))
1748 (setq signal
1749 (completing-read (concat "Send signal [" pnum
1750 "] (default TERM): ")
1751 proced-signal-list
1752 nil nil nil nil "TERM")))))))
1753 ;; send signal
1754 (let ((count 0)
1755 failures)
1756 ;; Why not always use `signal-process'? See
1757 ;; http://lists.gnu.org/archive/html/emacs-devel/2008-03/msg02955.html
1758 (if (functionp proced-signal-function)
1759 ;; use built-in `signal-process'
1760 (let ((signal (if (stringp signal)
1761 (if (string-match "\\`[0-9]+\\'" signal)
1762 (string-to-number signal)
1763 (make-symbol signal))
1764 signal))) ; number
1765 (dolist (process process-alist)
1766 (condition-case err
1767 (if (zerop (funcall
1768 proced-signal-function (car process) signal))
1769 (setq count (1+ count))
1770 (proced-log "%s\n" (cdr process))
1771 (push (cdr process) failures))
1772 (error ; catch errors from failed signals
1773 (proced-log "%s\n" err)
1774 (proced-log "%s\n" (cdr process))
1775 (push (cdr process) failures)))))
1776 ;; use external system call
1777 (let ((signal (concat "-" (if (numberp signal)
1778 (number-to-string signal) signal))))
1779 (dolist (process process-alist) 1820 (dolist (process process-alist)
1780 (with-temp-buffer 1821 (condition-case err
1781 (condition-case nil 1822 (unless (zerop (funcall
1782 (if (zerop (call-process 1823 proced-signal-function (car process) signal))
1783 proced-signal-function nil t nil 1824 (proced-log "%s\n" (cdr process))
1784 signal (number-to-string (car process)))) 1825 (push (cdr process) failures))
1785 (setq count (1+ count)) 1826 (error ; catch errors from failed signals
1786 (proced-log (current-buffer)) 1827 (proced-log "%s\n" err)
1787 (proced-log "%s\n" (cdr process)) 1828 (proced-log "%s\n" (cdr process))
1788 (push (cdr process) failures)) 1829 (push (cdr process) failures)))))
1789 (error ; catch errors from failed signals 1830 ;; use external system call
1790 (proced-log (current-buffer)) 1831 (let ((signal (format "-%s" signal)))
1791 (proced-log "%s\n" (cdr process)) 1832 (dolist (process process-alist)
1792 (push (cdr process) failures))))))) 1833 (with-temp-buffer
1793 (if failures 1834 (condition-case nil
1794 ;; Proced error message are not always very precise. 1835 (unless (zerop (call-process
1795 ;; Can we issue a useful one-line summary in the 1836 proced-signal-function nil t nil
1796 ;; message area (using FAILURES) if only one signal failed? 1837 signal (number-to-string (car process))))
1797 (proced-log-summary 1838 (proced-log (current-buffer))
1798 signal 1839 (proced-log "%s\n" (cdr process))
1799 (format "%d of %d signal%s failed" 1840 (push (cdr process) failures))
1800 (length failures) (length process-alist) 1841 (error ; catch errors from failed signals
1801 (if (= 1 (length process-alist)) "" "s"))) 1842 (proced-log (current-buffer))
1802 (proced-success-message "Sent signal to" count))) 1843 (proced-log "%s\n" (cdr process))
1803 ;; final clean-up 1844 (push (cdr process) failures)))))))
1804 (run-hooks 'proced-after-send-signal-hook))) 1845 (if failures
1846 ;; Proced error message are not always very precise.
1847 ;; Can we issue a useful one-line summary in the
1848 ;; message area (using FAILURES) if only one signal failed?
1849 (proced-log-summary
1850 (format "Signal %s" signal)
1851 (format "%d of %d signal%s failed"
1852 (length failures) (length process-alist)
1853 (if (= 1 (length process-alist)) "" "s")))
1854 (proced-success-message "Sent signal to" (length process-alist))))
1855 ;; final clean-up
1856 (run-hooks 'proced-after-send-signal-hook))
1857
1858(defun proced-renice (priority process-alist)
1859 "Renice the processes in PROCESS-ALIST to PRIORITY.
1860PROCESS-ALIST is an alist as returned by `proced-marked-processes'.
1861Interactively, PROCESS-ALIST contains the marked processes.
1862If no process is marked, it contains the process point is on,
1863After renicing all processes in PROCESS-ALIST, this command runs
1864the normal hook `proced-after-send-signal-hook'."
1865 (interactive
1866 (let ((process-alist (proced-marked-processes)))
1867 (proced-with-processes-buffer process-alist
1868 (list (read-number "New priority: ")
1869 process-alist))))
1870 (if (numberp priority)
1871 (setq priority (number-to-string priority)))
1872 (let (failures)
1873 (dolist (process process-alist)
1874 (with-temp-buffer
1875 (condition-case nil
1876 (unless (zerop (call-process
1877 proced-renice-command nil t nil
1878 priority (number-to-string (car process))))
1879 (proced-log (current-buffer))
1880 (proced-log "%s\n" (cdr process))
1881 (push (cdr process) failures))
1882 (error ; catch errors from failed renice
1883 (proced-log (current-buffer))
1884 (proced-log "%s\n" (cdr process))
1885 (push (cdr process) failures)))))
1886 (if failures
1887 (proced-log-summary
1888 (format "Renice %s" priority)
1889 (format "%d of %d renice%s failed"
1890 (length failures) (length process-alist)
1891 (if (= 1 (length process-alist)) "" "s")))
1892 (proced-success-message "Reniced" (length process-alist))))
1893 ;; final clean-up
1894 (run-hooks 'proced-after-send-signal-hook))
1805 1895
1806;; similar to `dired-why' 1896;; similar to `dired-why'
1807(defun proced-why () 1897(defun proced-why ()