+
+;;;; the beef
+
+(defun make-thread (function &key name)
+ #!+sb-doc
+ "Create a new thread of NAME that runs FUNCTION. When the function
+returns the thread exits."
+ #!-sb-thread (declare (ignore function name))
+ #!-sb-thread (error "Not supported in unithread builds.")
+ #!+sb-thread
+ (let* ((thread (%make-thread :name name))
+ (setup-sem (make-semaphore :name "Thread setup semaphore"))
+ (real-function (coerce function 'function))
+ (thread-sap
+ ;; don't let the child inherit *CURRENT-THREAD* because that
+ ;; can prevent gc'ing this thread while the child runs
+ (let ((*current-thread* nil))
+ (%create-thread
+ (sb!kernel:get-lisp-obj-address
+ (lambda ()
+ ;; in time we'll move some of the binding presently done in C
+ ;; here too
+ (let ((*current-thread* thread)
+ (sb!kernel::*restart-clusters* nil)
+ (sb!kernel::*handler-clusters* nil)
+ (sb!kernel::*condition-restarts* nil)
+ (sb!impl::*descriptor-handlers* nil)) ; serve-event
+ (wait-on-semaphore setup-sem)
+ ;; can't use handling-end-of-the-world, because that flushes
+ ;; output streams, and we don't necessarily have any (or we
+ ;; could be sharing them)
+ (unwind-protect
+ (catch 'sb!impl::toplevel-catcher
+ (catch 'sb!impl::%end-of-the-world
+ (with-simple-restart
+ (terminate-thread
+ (format nil
+ "~~@<Terminate this thread (~A)~~@:>"
+ *current-thread*))
+ ;; now that most things have a chance to
+ ;; work properly without messing up other
+ ;; threads, it's time to enable signals
+ (sb!unix::reset-signal-mask)
+ (unwind-protect
+ (funcall real-function)
+ ;; we're going down, can't handle
+ ;; interrupts sanely anymore
+ (let ((sb!impl::*gc-inhibit* t))
+ (block-blockable-signals)
+ ;; and remove what can be the last
+ ;; reference to this thread
+ (handle-thread-exit thread))))))
+ 0))
+ (values)))))))
+ (when (sb!sys:sap= thread-sap (sb!sys:int-sap 0))
+ (error "Can't create a new thread"))
+ (setf (thread-%sap thread) thread-sap)
+ (with-mutex (*all-threads-lock*)
+ (push thread *all-threads*))
+ (with-session-lock (*session*)
+ (push thread (session-threads *session*)))
+ (signal-semaphore setup-sem)
+ (sb!impl::finalize thread (lambda () (reap-dead-thread thread-sap)))
+ thread))
+
+(defun destroy-thread (thread)
+ #!+sb-doc
+ "Deprecated. Same as TERMINATE-THREAD."
+ (terminate-thread thread))
+
+(define-condition interrupt-thread-error (error)
+ ((thread :reader interrupt-thread-error-thread :initarg :thread)
+ (errno :reader interrupt-thread-error-errno :initarg :errno))
+ #!+sb-doc
+ (:documentation "Interrupting thread failed.")
+ (:report (lambda (c s)
+ (format s "interrupt thread ~A failed (~A: ~A)"
+ (interrupt-thread-error-thread c)
+ (interrupt-thread-error-errno c)
+ (strerror (interrupt-thread-error-errno c))))))
+
+#!+sb-doc
+(setf (sb!kernel:fdocumentation 'interrupt-thread-error-thread 'function)
+ "The thread that was not interrupted."
+ (sb!kernel:fdocumentation 'interrupt-thread-error-errno 'function)
+ "The reason why the interruption failed.")
+
+(defun interrupt-thread (thread function)
+ #!+sb-doc
+ "Interrupt the live THREAD and make it run FUNCTION. A moderate
+degree of care is expected for use of interrupt-thread, due to its
+nature: if you interrupt a thread that was holding important locks
+then do something that turns out to need those locks, you probably
+won't like the effect."
+ #!-sb-thread (declare (ignore thread))
+ ;; not quite perfect, because it does not take WITHOUT-INTERRUPTS
+ ;; into account
+ #!-sb-thread
+ (funcall function)
+ #!+sb-thread
+ (if (eq thread *current-thread*)
+ (funcall function)
+ (let ((function (coerce function 'function)))
+ (multiple-value-bind (res err)
+ ;; protect against gcing just when the ub32 address is
+ ;; just ready to be passed to C
+ (sb!sys::with-pinned-objects (function)
+ (sb!unix::syscall ("interrupt_thread"
+ system-area-pointer sb!alien:unsigned-long)
+ thread
+ (thread-%sap thread)
+ (sb!kernel:get-lisp-obj-address function)))
+ (unless res
+ (error 'interrupt-thread-error :thread thread :errno err))))))
+
+(defun terminate-thread (thread)
+ #!+sb-doc
+ "Terminate the thread identified by THREAD, by causing it to run
+SB-EXT:QUIT - the usual cleanup forms will be evaluated"
+ (interrupt-thread thread 'sb!ext:quit))
+
+;;; internal use only. If you think you need to use this, either you
+;;; are an SBCL developer, are doing something that you should discuss
+;;; with an SBCL developer first, or are doing something that you
+;;; should probably discuss with a professional psychiatrist first
+#!+sb-thread
+(defun symbol-value-in-thread (symbol thread)
+ (let ((thread-sap (thread-%sap thread)))
+ (let* ((index (sb!vm::symbol-tls-index symbol))
+ (tl-val (sb!sys: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)
+ (sb!kernel:make-lisp-obj tl-val)))))