aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/thread.el
diff options
context:
space:
mode:
authorGemini Lasswell2018-08-01 09:22:32 -0700
committerGemini Lasswell2018-09-09 07:41:49 -0700
commit3ca82c59de839f9c10318438ecc87f931b8a0208 (patch)
tree31b90d02c22f98564e758a98f6ce0897975c5706 /lisp/thread.el
parenta133b1f7d6a6961cdb59217918ce7f7c106f420e (diff)
downloademacs-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.el145
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'.
35An 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.
115Return a list of two strings, the first describing THREAD's
116status and the second describing what it is blocked on if it is
117blocked."
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.
137Confirm 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