- (tagbody
- (with-pinned-objects (value)
- ;; Prevent the dead 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)))
- (if (eql tl-val sb!vm::no-tls-value-marker-widetag)
- (go :unbound)
- (setf (sap-ref-word sap offset)
- (get-lisp-obj-address value)))
- (return-from %set-symbol-value-in-thread (values value t)))
- (return-from %set-symbol-value-in-thread (values nil nil)))))
- :unbound
- (error "Cannot set thread-local symbol value: ~S unbound in ~S"
- symbol thread))))
+ (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))))
+ (cond ((zerop offset)
+ (values nil :no-tls-value))
+ (t
+ (setf (sap-ref-word (%thread-sap thread) offset)
+ (get-lisp-obj-address value))
+ (values value :ok))))
+ (values nil :thread-dead)))))
+
+ (define-alien-variable tls-index-start unsigned-int)
+
+ ;; Get values from the TLS area of the current thread.
+ (defun %thread-local-references ()
+ (without-gcing
+ (let ((sap (%thread-sap *current-thread*)))
+ (loop for index from tls-index-start
+ below (symbol-value 'sb!vm::*free-tls-index*)
+ for value = (sap-ref-word sap (* sb!vm:n-word-bytes index))
+ for (obj ok) = (multiple-value-list (sb!kernel:make-lisp-obj value nil))
+ unless (or (not ok)
+ (typep obj '(or fixnum character))
+ (member value
+ '(#.sb!vm:no-tls-value-marker-widetag
+ #.sb!vm:unbound-marker-widetag))
+ (member obj seen :test #'eq))
+ collect obj into seen
+ finally (return seen))))))
+
+(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 for inter-thread communication."
+ (declare (symbol symbol) (thread thread))
+ #!+sb-thread
+ (multiple-value-bind (res status) (%symbol-value-in-thread symbol thread)
+ (if (eq :ok 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-in-thread))
+ (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 :ok 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-in-thread))
+ (values nil nil))))