- (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
- (sb!unix::block-blockable-signals)))))
- ;; mark the thread dead, so that the gc does not
- ;; wait for it to handle sig-stop-for-gc
- (%set-thread-state thread :dead)
- ;; and remove what can be the last reference to
- ;; the thread object
- (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*)))
- (setq setup-p t)
- (sb!impl::finalize thread (lambda () (reap-dead-thread thread-sap)))
- thread))
+ (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*))
+ (unwind-protect
+ (progn
+ ;; 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)
+ (setf (thread-result thread)
+ (cons t
+ (multiple-value-list
+ (funcall real-function)))))
+ (handle-thread-exit thread)))))))
+ (values))))
+ ;; Keep INITIAL-FUNCTION pinned until the child thread is
+ ;; initialized properly.
+ (with-pinned-objects (initial-function)
+ (let ((os-thread
+ (%create-thread
+ (get-lisp-obj-address initial-function))))
+ (when (zerop os-thread)
+ (error "Can't create a new thread"))
+ (wait-on-semaphore setup-sem)
+ thread))))
+
+(define-condition join-thread-error (error)
+ ((thread :reader join-thread-error-thread :initarg :thread))
+ #!+sb-doc
+ (:documentation "Joining thread failed.")
+ (:report (lambda (c s)
+ (format s "Joining thread failed: thread ~A ~
+ has not returned normally."
+ (join-thread-error-thread c)))))
+
+#!+sb-doc
+(setf (fdocumentation 'join-thread-error-thread 'function)
+ "The thread that we failed to join.")
+
+(defun join-thread (thread &key (default nil defaultp))
+ #!+sb-doc
+ "Suspend current thread until THREAD exits. Returns the result
+values of the thread function. If the thread does not exit normally,
+return DEFAULT if given or else signal JOIN-THREAD-ERROR."
+ (with-mutex ((thread-result-lock thread))
+ (cond ((car (thread-result thread))
+ (values-list (cdr (thread-result thread))))
+ (defaultp
+ default)
+ (t
+ (error 'join-thread-error :thread thread)))))