-(defun thread-sap-for-id (id)
- (let ((thread-sap (alien-sap (extern-alien "all_threads" (* t)))))
- (loop
- (when (sap= thread-sap (int-sap 0)) (return nil))
- (let ((os-thread (sap-ref-word thread-sap
- (* sb!vm:n-word-bytes
- sb!vm::thread-os-thread-slot))))
- (when (= os-thread id) (return thread-sap))
- (setf thread-sap
- (sap-ref-sap thread-sap (* sb!vm:n-word-bytes
- sb!vm::thread-next-slot)))))))
-
-#!+sb-thread
-(defun symbol-value-in-thread (symbol thread-sap)
- (let* ((index (sb!vm::symbol-tls-index symbol))
- (tl-val (sap-ref-word thread-sap
- (* sb!vm:n-word-bytes index))))
- (if (eql tl-val sb!vm::no-tls-value-marker-widetag)
- (sb!vm::symbol-global-value symbol)
- (make-lisp-obj tl-val))))
+(progn
+ (defun %thread-sap (thread)
+ (let ((thread-sap (alien-sap (extern-alien "all_threads" (* t))))
+ (target (thread-os-thread thread)))
+ (loop
+ (when (sap= thread-sap (int-sap 0)) (return nil))
+ (let ((os-thread (sap-ref-word thread-sap
+ (* sb!vm:n-word-bytes
+ sb!vm::thread-os-thread-slot))))
+ (when (= os-thread target) (return thread-sap))
+ (setf thread-sap
+ (sap-ref-sap thread-sap (* sb!vm:n-word-bytes
+ sb!vm::thread-next-slot)))))))
+
+ (defun %symbol-value-in-thread (symbol thread)
+ ;; Prevent the thread from dying completely while we look for the TLS
+ ;; area...
+ (with-all-threads-lock
+ (if (thread-alive-p thread)
+ (let* ((offset (* sb!vm:n-word-bytes
+ (sb!vm::symbol-tls-index symbol)))
+ (tl-val (sap-ref-word (%thread-sap thread) offset)))
+ (if (eql tl-val sb!vm::no-tls-value-marker-widetag)
+ (values nil :unbound)
+ (values (make-lisp-obj tl-val) :bound)))
+ (values nil :dead))))
+
+ (defun %set-symbol-value-in-thread (symbol thread value)
+ (with-pinned-objects (value)
+ ;; Prevent the thread from dying completely while we look for the TLS
+ ;; area...
+ (with-all-threads-lock
+ (if (thread-alive-p thread)
+ (let* ((offset (* sb!vm:n-word-bytes
+ (sb!vm::symbol-tls-index symbol)))
+ (sap (%thread-sap thread))
+ (tl-val (sap-ref-word sap offset)))
+ (cond ((eql tl-val sb!vm::no-tls-value-marker-widetag)
+ (values nil :unbound))
+ (t
+ (setf (sap-ref-word sap offset)
+ (get-lisp-obj-address value))
+ (values value :bound))))
+ (values nil :dead))))))
+
+(defun symbol-value-in-thread (symbol thread &optional (errorp t))
+ "Return the local value of SYMBOL in THREAD, and a secondary value of T
+on success.
+
+If the value cannot be retrieved (because the thread has exited or because it
+has no local binding for NAME) and ERRORP is true signals an error of type
+SYMBOL-VALUE-IN-THREAD-ERROR; if ERRORP is false returns a primary value of
+NIL, and a secondary value of NIL.
+
+Can also be used with SETF to change the thread-local value of SYMBOL.
+
+SYMBOL-VALUE-IN-THREAD is primarily intended as a debugging tool, and not as a
+mechanism form inter-thread communication."
+ (declare (symbol symbol) (thread thread))
+ #!+sb-thread
+ (multiple-value-bind (res status) (%symbol-value-in-thread symbol thread)
+ (if (eq :bound status)
+ (values res t)
+ (if errorp
+ (error 'symbol-value-in-thread-error
+ :name symbol
+ :thread thread
+ :info (list :read status))
+ (values nil nil))))
+ #!-sb-thread
+ (if (boundp symbol)
+ (values (symbol-value symbol) t)
+ (if errorp
+ (error 'symbol-value-in-thread-error
+ :name symbol
+ :thread thread
+ :info (list :read :unbound))
+ (values nil nil))))
+
+(defun (setf symbol-value-in-thread) (value symbol thread &optional (errorp t))
+ (declare (symbol symbol) (thread thread))
+ #!+sb-thread
+ (multiple-value-bind (res status) (%set-symbol-value-in-thread symbol thread value)
+ (if (eq :bound status)
+ (values res t)
+ (if errorp
+ (error 'symbol-value-in-thread-error
+ :name symbol
+ :thread thread
+ :info (list :write status))
+ (values nil nil))))
+ #!-sb-thread
+ (if (boundp symbol)
+ (values (setf (symbol-value symbol) value) t)
+ (if errorp
+ (error 'symbol-value-in-thread-error
+ :name symbol
+ :thread thread
+ :info (list :write :unbound))
+ (values nil nil))))