changeset 227: | 1741660af6e9 |
parent: | 83e823b80219 |
child: | 2a4f11c0e8c8 |
author: | Richard Westhaver <ellis@rwest.io> |
date: | Thu, 14 Mar 2024 21:52:22 -0400 |
permissions: | -rw-r--r-- |
description: | clists |
5 | 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: |
|
96 | 10 | (in-package :std) |
5 | 11 | |
12 | (defun thread-support-p () (member :thread-support *features*)) |
|
13 | ||
14 | (eval-when (:compile-toplevel) |
|
15 | (defun print-thread-message-top-level (msg) |
|
16 | (sb-thread:make-thread |
|
17 | (lambda () |
|
18 | (format #.*standard-output* msg))) |
|
19 | nil)) |
|
118
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
20 | |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
21 | ;; this is all very unsafe. don't touch the finalizer thread plz. |
119 | 22 | (defun find-thread-by-id (id) |
118
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
23 | "Search for thread by ID which must be an u64. On success returns the thread itself or nil." |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
24 | (sb-thread::avlnode-data (sb-thread::avl-find id sb-thread::*all-threads*))) |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
25 | |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
26 | (defun thread-id-list () |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
27 | (sb-thread::avltree-filter #'sb-thread::avlnode-key sb-thread::*all-threads*)) |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
28 | |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
29 | (defun thread-count () |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
30 | (sb-thread::avl-count sb-thread::*all-threads*)) |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
31 | |
119 | 32 | (defun make-threads (n fn &key (name "thread")) |
227 | 33 | (declare (type fixnum n)) |
34 | (loop for i below n |
|
118
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
35 | collect (make-thread fn :name (format nil "~A-~D" name i)))) |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
36 | |
119 | 37 | (defmacro with-threads ((idx n) &body body) |
38 | `(make-threads ,n (lambda (,idx) (declare (ignorable ,idx)) ,@body))) |
|
39 | ||
40 | (defun finish-threads (&rest threads) |
|
41 | (let ((threads (flatten threads))) |
|
42 | (unwind-protect |
|
43 | (mapc #'join-thread threads) |
|
44 | (dolist (thread threads) |
|
45 | (when (thread-alive-p thread) |
|
182 | 46 | (terminate-thread thread)))))) |
119 | 47 | |
48 | (defun timed-join-thread (thread timeout) |
|
227 | 49 | (declare (type thread thread) (type float timeout)) |
118
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
50 | (handler-case (sb-sys:with-deadline (:seconds timeout) |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
51 | (join-thread thread :default :aborted)) |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
52 | (sb-ext:timeout () |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
53 | :timeout))) |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
54 | |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
55 | (defun hang () |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
56 | (join-thread *current-thread*)) |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
57 | |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
58 | (defun kill-thread (thread) |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
59 | (when (thread-alive-p thread) |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
60 | (ignore-errors |
b828a3caa758
object library stuff, removed DOT - api doesnt jive.
ellis <ellis@rwest.io>
parents:
96
diff
changeset
|
61 | (terminate-thread thread)))) |
119 | 62 | |
227 | 63 | ;; (sb-vm::primitive-object-slots (sb-vm::primitive-object 'sb-vm::thread)) |
64 | ||
119 | 65 | ;; from sb-thread |
66 | (defun dump-thread () |
|
227 | 67 | (let* ((slots (sb-vm::primitive-object-slots #1=(sb-vm::primitive-object 'sb-vm::thread))) |
119 | 68 | (sap (current-thread-sap)) |
227 | 69 | (thread-obj-len (sb-vm::primitive-object-length #1#)) |
119 | 70 | (names (make-array thread-obj-len :initial-element ""))) |
71 | (loop for slot across slots |
|
72 | do |
|
73 | (setf (aref names (sb-vm::slot-offset slot)) (sb-vm::slot-name slot))) |
|
74 | (flet ((safely-read (sap offset &aux (bits (sb-vm::sap-ref-word sap offset))) |
|
75 | (cond ((eql bits sb-vm:no-tls-value-marker) :no-tls-value) |
|
76 | ((eql (logand bits sb-vm:widetag-mask) sb-vm:unbound-marker-widetag) :unbound) |
|
77 | (t (sb-vm::sap-ref-lispobj sap offset)))) |
|
78 | (show (sym val) |
|
227 | 79 | (declare (type fixnum sym)) |
119 | 80 | (let ((*print-right-margin* 128) |
81 | (*print-lines* 4)) |
|
82 | (format t " ~3d ~30a : ~s~%" |
|
83 | #+sb-thread (ash sym (- sb-vm:word-shift)) |
|
84 | #-sb-thread 0 |
|
85 | #+sb-thread (sb-vm:symbol-from-tls-index sym) |
|
86 | #-sb-thread sym |
|
87 | val)))) |
|
88 | (format t "~&TLS: (base=~x)~%" (sb-vm::sap-int sap)) |
|
89 | (loop for tlsindex from sb-vm:n-word-bytes below |
|
90 | #+sb-thread (ash sb-vm::*free-tls-index* sb-vm:n-fixnum-tag-bits) |
|
91 | #-sb-thread (ash thread-obj-len sb-vm:word-shift) |
|
92 | by sb-vm:n-word-bytes |
|
93 | do |
|
94 | (unless (<= sb-vm::thread-allocator-histogram-slot |
|
95 | (ash tlsindex (- sb-vm:word-shift)) |
|
96 | (1- sb-vm::thread-lisp-thread-slot)) |
|
97 | (let ((thread-slot-name |
|
98 | (if (< tlsindex (ash thread-obj-len sb-vm:word-shift)) |
|
99 | (aref names (ash tlsindex (- sb-vm:word-shift)))))) |
|
100 | (if (and thread-slot-name (sb-vm::neq thread-slot-name 'sb-vm::lisp-thread)) |
|
101 | (format t " ~3d ~30a : #x~x~%" (ash tlsindex (- sb-vm:word-shift)) |
|
102 | thread-slot-name (sb-vm::sap-ref-word sap tlsindex)) |
|
103 | (let ((val (safely-read sap tlsindex))) |
|
104 | (unless (eq val :no-tls-value) |
|
105 | (show tlsindex val))))))) |
|
106 | (let ((from (sb-vm::descriptor-sap sb-vm:*binding-stack-start*)) |
|
107 | (to (sb-vm::binding-stack-pointer-sap))) |
|
108 | (format t "~%Binding stack: (depth ~d)~%" |
|
109 | (/ (sb-vm::sap- to from) (* sb-vm:binding-size sb-vm:n-word-bytes))) |
|
110 | (loop |
|
111 | (when (sb-vm::sap>= from to) (return)) |
|
112 | (let ((val (safely-read from 0)) |
|
113 | (sym #+sb-thread (sb-vm::sap-ref-word from sb-vm:n-word-bytes) ; a TLS index |
|
114 | #-sb-thread (sb-vm::sap-ref-lispobj from sb-vm:n-word-bytes))) |
|
115 | (show sym val)) |
|
116 | (setq from (sb-vm::sap+ from (* sb-vm:binding-size sb-vm:n-word-bytes)))))))) |
|
162 | 117 | |
118 | ;;; Tasks |
|
227 | 119 | (defclass oracle () ((thread :initform *current-thread* :initarg :thread :accessor oracle-thread))) |
182 | 120 | |
227 | 121 | (defgeneric designate-oracle (host guest)) |
182 | 122 | |
123 | (defstruct task-pool |
|
124 | (oracle nil :type (or null oracle)) |
|
162 | 125 | (jobs (sb-concurrency:make-queue :name "jobs")) |
182 | 126 | (stages nil :type sequence) |
162 | 127 | (workers (sb-concurrency:make-mailbox :name "workers")) |
128 | (results (sb-concurrency:make-queue :name "results")) |
|
129 | (completed-jobs 0 :type fixnum) ;;atomic |
|
130 | (completed-tasks 0 :type fixnum)) |
|
131 | ||
184 | 132 | (defmethod designate-oracle ((self task-pool) guest) |
133 | (setf (task-pool-oracle self) guest)) |
|
134 | ||
162 | 135 | (defclass task () |
136 | ((object :initarg :object :accessor task-object))) |
|
137 | ||
138 | (defclass job () |
|
182 | 139 | ((tasks :initform (make-array 0 :element-type 'task :fill-pointer 0 :adjustable t) |
140 | :initarg :tasks |
|
141 | :accessor :tasks |
|
222 | 142 | :type (vector task)))) |
182 | 143 | (defclass stage () |
144 | ((jobs :initform (make-array 0 :element-type 'task :fill-pointer 0 :adjustable t) |
|
145 | :initarg :jobs |
|
146 | :accessor :jobs |
|
147 | :type (vector job)))) |