diff options
| author | Gemini Lasswell | 2018-08-01 09:22:32 -0700 |
|---|---|---|
| committer | Gemini Lasswell | 2018-09-09 07:41:49 -0700 |
| commit | 3ca82c59de839f9c10318438ecc87f931b8a0208 (patch) | |
| tree | 31b90d02c22f98564e758a98f6ce0897975c5706 /lisp/thread.el | |
| parent | a133b1f7d6a6961cdb59217918ce7f7c106f420e (diff) | |
| download | emacs-3ca82c59de839f9c10318438ecc87f931b8a0208.tar.gz emacs-3ca82c59de839f9c10318438ecc87f931b8a0208.zip | |
Make lisp/thread.el the new home for thread-related Lisp functions
* lisp/emacs-lisp/thread-list.el: Remove.
* lisp/emacs-lisp/thread.el: Remove.
* lisp/thread.el: New file.
Diffstat (limited to 'lisp/thread.el')
| -rw-r--r-- | lisp/thread.el | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/lisp/thread.el b/lisp/thread.el new file mode 100644 index 00000000000..cb1e7721de9 --- /dev/null +++ b/lisp/thread.el | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | ;;; thread.el --- Thread support in Emacs Lisp -*- lexical-binding: t -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2018 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Gemini Lasswell <gazally@runbox.com> | ||
| 6 | ;; Maintainer: emacs-devel@gnu.org | ||
| 7 | ;; Keywords: thread, tools | ||
| 8 | |||
| 9 | ;; This file is part of GNU Emacs. | ||
| 10 | |||
| 11 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 12 | ;; it under the terms of the GNU General Public License as published by | ||
| 13 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 14 | ;; (at your option) any later version. | ||
| 15 | |||
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | ;; GNU General Public License for more details. | ||
| 20 | |||
| 21 | ;; You should have received a copy of the GNU General Public License | ||
| 22 | ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
| 23 | |||
| 24 | ;;; Commentary: | ||
| 25 | |||
| 26 | ;;; Code: | ||
| 27 | |||
| 28 | (require 'cl-lib) | ||
| 29 | (require 'pcase) | ||
| 30 | (require 'subr-x) | ||
| 31 | |||
| 32 | ;;;###autoload | ||
| 33 | (defun thread-handle-event (event) | ||
| 34 | "Handle thread events, propagated by `thread-signal'. | ||
| 35 | An EVENT has the format | ||
| 36 | (thread-event THREAD ERROR-SYMBOL DATA)" | ||
| 37 | (interactive "e") | ||
| 38 | (if (and (consp event) | ||
| 39 | (eq (car event) 'thread-event) | ||
| 40 | (= (length event) 4)) | ||
| 41 | (let ((thread (cadr event)) | ||
| 42 | (err (cddr event))) | ||
| 43 | (message "Error %s: %S" thread err)))) | ||
| 44 | |||
| 45 | (make-obsolete 'thread-alive-p 'thread-live-p "27.1") | ||
| 46 | |||
| 47 | ;;; The thread list buffer and list-threads command | ||
| 48 | |||
| 49 | (defcustom thread-list-refresh-seconds 0.5 | ||
| 50 | "Seconds between automatic refreshes of the *Threads* buffer." | ||
| 51 | :group 'thread-list | ||
| 52 | :type 'number | ||
| 53 | :version "27.1") | ||
| 54 | |||
| 55 | (defvar thread-list-mode-map | ||
| 56 | (let ((map (make-sparse-keymap))) | ||
| 57 | (set-keymap-parent map tabulated-list-mode-map) | ||
| 58 | (define-key map "s" nil) | ||
| 59 | (define-key map "sq" #'thread-list-send-quit-signal) | ||
| 60 | (define-key map "se" #'thread-list-send-error-signal) | ||
| 61 | (easy-menu-define nil map "" | ||
| 62 | '("Threads" | ||
| 63 | ["Send Quit Signal" thread-list-send-quit-signal t] | ||
| 64 | ["Send Error Signal" thread-list-send-error-signal t])) | ||
| 65 | map) | ||
| 66 | "Local keymap for `thread-list-mode' buffers.") | ||
| 67 | |||
| 68 | (define-derived-mode thread-list-mode tabulated-list-mode "Thread-List" | ||
| 69 | "Major mode for monitoring Lisp threads." | ||
| 70 | (setq tabulated-list-format | ||
| 71 | [("Thread Name" 15 t) | ||
| 72 | ("Status" 10 t) | ||
| 73 | ("Blocked On" 30 t)]) | ||
| 74 | (setq tabulated-list-sort-key (cons (car (aref tabulated-list-format 0)) nil)) | ||
| 75 | (setq tabulated-list-entries #'thread-list--get-entries) | ||
| 76 | (tabulated-list-init-header)) | ||
| 77 | |||
| 78 | ;;;###autoload | ||
| 79 | (defun list-threads () | ||
| 80 | "Display a list of threads." | ||
| 81 | (interactive) | ||
| 82 | ;; Generate the Threads list buffer, and switch to it. | ||
| 83 | (let ((buf (get-buffer-create "*Threads*"))) | ||
| 84 | (with-current-buffer buf | ||
| 85 | (unless (derived-mode-p 'thread-list-mode) | ||
| 86 | (thread-list-mode) | ||
| 87 | (run-at-time 0 nil #'thread-list--timer-func buf))) | ||
| 88 | (switch-to-buffer buf))) | ||
| 89 | ;; This command can be destructive if they don't know what they are | ||
| 90 | ;; doing. Kids, don't try this at home! | ||
| 91 | ;;;###autoload (put 'list-threads 'disabled "Beware: manually canceling threads can ruin your Emacs session.") | ||
| 92 | |||
| 93 | (defun thread-list--timer-func (buf) | ||
| 94 | "Revert BUF and set a timer to do it again." | ||
| 95 | (when (buffer-live-p buf) | ||
| 96 | (with-current-buffer buf | ||
| 97 | (revert-buffer)) | ||
| 98 | (run-at-time thread-list-refresh-seconds nil | ||
| 99 | #'thread-list--timer-func buf))) | ||
| 100 | |||
| 101 | (defun thread-list--get-entries () | ||
| 102 | "Return tabulated list entries for the threads currently active." | ||
| 103 | (let (entries) | ||
| 104 | (dolist (thread (all-threads)) | ||
| 105 | (pcase-let ((`(,status ,blocker) (thread-list--get-status thread))) | ||
| 106 | (push `(,thread [,(or (thread-name thread) | ||
| 107 | (and (eq thread main-thread) "Main") | ||
| 108 | (prin1-to-string thread)) | ||
| 109 | ,status ,blocker]) | ||
| 110 | entries))) | ||
| 111 | entries)) | ||
| 112 | |||
| 113 | (defun thread-list--get-status (thread) | ||
| 114 | "Describe the status of THREAD. | ||
| 115 | Return a list of two strings, the first describing THREAD's | ||
| 116 | status and the second describing what it is blocked on if it is | ||
| 117 | blocked." | ||
| 118 | (cond | ||
| 119 | ((not (thread-alive-p thread)) '("Finished" "")) | ||
| 120 | ((eq thread (current-thread)) '("Running" "")) | ||
| 121 | (t (if-let ((blocker (thread--blocker thread))) | ||
| 122 | `("Blocked" ,(prin1-to-string blocker)) | ||
| 123 | '("Yielded" ""))))) | ||
| 124 | |||
| 125 | (defun thread-list-send-quit-signal () | ||
| 126 | "Send a quit signal to the thread at point." | ||
| 127 | (interactive) | ||
| 128 | (thread-list--send-signal 'quit)) | ||
| 129 | |||
| 130 | (defun thread-list-send-error-signal () | ||
| 131 | "Send an error signal to the thread at point." | ||
| 132 | (interactive) | ||
| 133 | (thread-list--send-signal 'error)) | ||
| 134 | |||
| 135 | (defun thread-list--send-signal (sgnl) | ||
| 136 | "Send the signal SGNL to the thread at point. | ||
| 137 | Confirm with the user first." | ||
| 138 | (let ((thread (tabulated-list-get-id))) | ||
| 139 | (when (and (threadp thread) (thread-alive-p thread)) | ||
| 140 | (when (y-or-n-p (format "Send %s signal to %s? " sgnl thread)) | ||
| 141 | (when (and (threadp thread) (thread-alive-p thread)) | ||
| 142 | (thread-signal thread sgnl nil)))))) | ||
| 143 | |||
| 144 | (provide 'thread) | ||
| 145 | ;;; thread.el ends here | ||