changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > core / lisp/std/thread.lisp

changeset 497: bcf772e86fbc
parent: cde5360295cd
child: da17bf652e48
author: Richard Westhaver <ellis@rwest.io>
date: Mon, 01 Jul 2024 20:48:11 -0400
permissions: -rw-r--r--
description: add std/task, some fixes and added cli/tools/systemd
1 ;;; threads.lisp --- Multi-thread utilities
2 
3 ;; Threading Macros
4 
5 ;;; Commentary:
6 
7 ;; mostly yoinked from sb-thread and friends
8 
9 ;;; Code:
10 (in-package :std/thread)
11 
12 ;; (sb-thread:thread-os-tid sb-thread:*current-thread*)
13 ;; sb-thread:interrupt-thread
14 
15 ;;; Utils
16 (defun thread-support-p () (member :thread-support *features*))
17 
18 (eval-when (:compile-toplevel)
19  (defun print-top-level (msg)
20  (sb-thread:make-thread
21  (lambda ()
22  (format #.*standard-output* msg)))
23  nil))
24 
25 (defun find-thread-by-id (id)
26  "Search for thread by ID which must be an u64. On success returns the thread itself or nil."
27  (find id (sb-thread::list-all-threads) :test '= :key 'thread-os-tid))
28 
29 (defun find-thread (name)
30  "Find a thread by name."
31  (find name (sb-thread::list-all-threads) :test 'equal :key 'thread-name))
32 
33 (defun thread-key-list ()
34  (sb-thread::avltree-filter #'sb-thread::avlnode-key sb-thread::*all-threads*))
35 
36 (defun thread-id-list ()
37  (sb-thread::avltree-filter (lambda (th) (thread-os-tid (sb-thread::avlnode-data th))) sb-thread::*all-threads*))
38 
39 (defun thread-count ()
40  (sb-thread::avl-count sb-thread::*all-threads*))
41 
42 (defun make-threads (n fn &key (name "thread"))
43  (declare (type fixnum n))
44  (loop for i below n
45  collect (make-thread fn :name (format nil "~A-~D" name i))))
46 
47 (defun parse-lambda-list-names (ll)
48  (multiple-value-bind (idx _ args) (sb-int:parse-lambda-list ll)
49  (declare (ignore idx _))
50  (loop for a in args
51  collect
52  (etypecase a
53  (atom a)
54  (cons (car a))))))
55 
56 (defmacro with-threads ((n &key args) &body body)
57  `(make-threads ,n (lambda (,@args) (declare (ignorable ,@(parse-lambda-list-names args))) ,@body)))
58 
59 (defun finish-threads (&rest threads)
60  (let ((threads (flatten threads)))
61  (unwind-protect
62  (mapc #'join-thread threads)
63  (dolist (thread threads)
64  (when (thread-alive-p thread)
65  (terminate-thread thread))))))
66 
67 (defun timed-join-thread (thread timeout)
68  (declare (type thread thread) (type float timeout))
69  (handler-case (sb-sys:with-deadline (:seconds timeout)
70  (join-thread thread :default :aborted))
71  (sb-ext:timeout ()
72  :timeout)))
73 
74 (defun hang ()
75  (join-thread *current-thread*))
76 
77 (defun kill-thread (thread)
78  (when (thread-alive-p thread)
79  (ignore-errors
80  (terminate-thread thread))))
81 
82 ;; (sb-vm::primitive-object-slots (sb-vm::primitive-object 'sb-vm::thread))
83 (defun init-session (&optional (thread *current-thread*)) (sb-thread::new-session thread))
84 
85 ;; (sb-thread::with-progressive-timeout (timet :seconds 4) (dotimes (i 4000) (print (timet))))
86 
87 ;; (describe sb-thread::*session*)
88 
89 ;; make-listener-thread
90 
91 ;; with-progressive-timeout
92 
93 ;; from sb-thread
94 (defun dump-thread ()
95  (let* ((slots (sb-vm::primitive-object-slots #1=(sb-vm::primitive-object 'sb-vm::thread)))
96  (sap (current-thread-sap))
97  (thread-obj-len (sb-vm::primitive-object-length #1#))
98  (names (make-array thread-obj-len :initial-element "")))
99  (loop for slot across slots
100  do
101  (setf (aref names (sb-vm::slot-offset slot)) (sb-vm::slot-name slot)))
102  (flet ((safely-read (sap offset &aux (bits (sb-vm::sap-ref-word sap offset)))
103  (cond ((eql bits sb-vm:no-tls-value-marker) :no-tls-value)
104  ((eql (logand bits sb-vm:widetag-mask) sb-vm:unbound-marker-widetag) :unbound)
105  (t (sb-vm::sap-ref-lispobj sap offset))))
106  (show (sym val)
107  (declare (type fixnum sym))
108  (let ((*print-right-margin* 128)
109  (*print-lines* 4))
110  (format t " ~3d ~30a : ~s~%"
111  #+sb-thread (ash sym (- sb-vm:word-shift))
112  #-sb-thread 0
113  #+sb-thread (sb-vm:symbol-from-tls-index sym)
114  #-sb-thread sym
115  val))))
116  (format t "~&TLS: (base=~x)~%" (sb-vm::sap-int sap))
117  (loop for tlsindex from sb-vm:n-word-bytes below
118  #+sb-thread (ash sb-vm::*free-tls-index* sb-vm:n-fixnum-tag-bits)
119  #-sb-thread (ash thread-obj-len sb-vm:word-shift)
120  by sb-vm:n-word-bytes
121  do
122  (unless (<= sb-vm::thread-allocator-histogram-slot
123  (ash tlsindex (- sb-vm:word-shift))
124  (1- sb-vm::thread-lisp-thread-slot))
125  (let ((thread-slot-name
126  (if (< tlsindex (ash thread-obj-len sb-vm:word-shift))
127  (aref names (ash tlsindex (- sb-vm:word-shift))))))
128  (if (and thread-slot-name (sb-vm::neq thread-slot-name 'sb-vm::lisp-thread))
129  (format t " ~3d ~30a : #x~x~%" (ash tlsindex (- sb-vm:word-shift))
130  thread-slot-name (sb-vm::sap-ref-word sap tlsindex))
131  (let ((val (safely-read sap tlsindex)))
132  (unless (eq val :no-tls-value)
133  (show tlsindex val)))))))
134  (let ((from (sb-vm::descriptor-sap sb-vm:*binding-stack-start*))
135  (to (sb-vm::binding-stack-pointer-sap)))
136  (format t "~%Binding stack: (depth ~d)~%"
137  (/ (sb-vm::sap- to from) (* sb-vm:binding-size sb-vm:n-word-bytes)))
138  (loop
139  (when (sb-vm::sap>= from to) (return))
140  (let ((val (safely-read from 0))
141  (sym #+sb-thread (sb-vm::sap-ref-word from sb-vm:n-word-bytes) ; a TLS index
142  #-sb-thread (sb-vm::sap-ref-lispobj from sb-vm:n-word-bytes)))
143  (show sym val))
144  (setq from (sb-vm::sap+ from (* sb-vm:binding-size sb-vm:n-word-bytes))))))))
145 
146 (defun wait-for-threads (threads)
147  (map 'list (lambda (thread) (sb-thread:join-thread thread :default nil)) threads)
148  (not (some #'sb-thread:thread-alive-p threads)))
149 
150 (defun process-all-interrupts (&optional (thread sb-thread:*current-thread*))
151  (sb-ext:wait-for (null (sb-thread::thread-interruptions thread))))