-(defun make-thread (function)
- (let* ((real-function (coerce function 'function))
- (tid
- (%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 ((sb!kernel::*restart-clusters* nil)
- (sb!kernel::*handler-clusters* nil)
- (sb!kernel::*condition-restarts* nil)
- (sb!impl::*descriptor-handlers* nil) ; serve-event
- (sb!impl::*available-buffers* nil)) ;for fd-stream
- ;; 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)
- (sb!sys:enable-interrupt sb!unix:sigint :ignore)
- (catch 'sb!impl::%end-of-the-world
- (with-simple-restart
- (destroy-thread
- (format nil "~~@<Destroy this thread (~A)~~@:>"
- (current-thread-id)))
- (funcall real-function))
- 0))
- (values))))))
- (when (zerop tid) (error "Can't create a new thread"))
- (with-mutex ((session-lock *session*))
- (pushnew tid (session-threads *session*)))
- tid))
-
-;;; Really, you don't want to use these: they'll get into trouble with
-;;; garbage collection. Use a lock or a waitqueue instead
-(defun suspend-thread (thread-id)
- (sb!unix:unix-kill thread-id sb!unix:sigstop))
-(defun resume-thread (thread-id)
- (sb!unix:unix-kill thread-id sb!unix:sigcont))
-;;; Note warning about cleanup forms
-(defun destroy-thread (thread-id)
- "Destroy the thread identified by THREAD-ID abruptly, without running cleanup forms"
- (sb!unix:unix-kill thread-id sb!unix:sigterm)
- ;; may have been stopped for some reason, so now wake it up to
- ;; deliver the TERM
- (sb!unix:unix-kill thread-id sb!unix:sigcont))
-
-
-
-
-;;; 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. Used with thought
-;;; though, it's a good deal gentler than the last-resort functions above
-
-(define-condition interrupt-thread-error (error)
- ((thread :reader interrupt-thread-error-thread :initarg :thread)
- (errno :reader interrupt-thread-error-errno :initarg :errno))
- (: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))))))
-
-(defun interrupt-thread (thread function)
- "Interrupt THREAD and make it run FUNCTION."
- (let ((function (coerce function 'function)))
- (sb!sys:with-pinned-objects
- (function)
- (multiple-value-bind (res err)
- (sb!unix::syscall ("interrupt_thread"
- sb!alien:unsigned-long sb!alien:unsigned-long)
- thread
- thread
- (sb!kernel:get-lisp-obj-address function))
- (unless res
- (error 'interrupt-thread-error :thread thread :errno err))))))
-
-
-(defun terminate-thread (thread-id)
- "Terminate the thread identified by THREAD-ID, by causing it to run
-SB-EXT:QUIT - the usual cleanup forms will be evaluated"
- (interrupt-thread thread-id 'sb!ext:quit))
-
-(declaim (inline current-thread-id))
-(defun current-thread-id ()
- (logand
- (sb!sys:sap-int
- (sb!vm::current-thread-offset-sap sb!vm::thread-pid-slot))
- ;; KLUDGE pids are 16 bit really. Avoid boxing the return value
- (1- (ash 1 16))))
-
-;;;; iterate over the in-memory threads
-
-(defun mapcar-threads (function)
- "Call FUNCTION once for each known thread, giving it the thread structure as argument"
- (let ((function (coerce function 'function)))
- (loop for thread = (alien-sap (extern-alien "all_threads" (* t)))
- then (sb!sys:sap-ref-sap thread (* sb!vm:n-word-bytes
- sb!vm::thread-next-slot))
- until (sb!sys:sap= thread (sb!sys:int-sap 0))
- collect (funcall function thread))))
-
-(defun thread-sap-from-id (id)
- (let ((thread (alien-sap (extern-alien "all_threads" (* t)))))
- (loop
- (when (sb!sys:sap= thread (sb!sys:int-sap 0)) (return nil))
- (let ((pid (sb!sys:sap-ref-32 thread (* sb!vm:n-word-bytes
- sb!vm::thread-pid-slot))))
- (when (= pid id) (return thread))
- (setf thread (sb!sys:sap-ref-sap thread (* sb!vm:n-word-bytes
- sb!vm::thread-next-slot)))))))
-
-;;; 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
-(defun symbol-value-in-thread (symbol thread-id)
- (let ((thread (thread-sap-from-id thread-id)))
- (when thread
- (let* ((index (sb!vm::symbol-tls-index symbol))
- (tl-val (sb!sys:sap-ref-word thread
- (* sb!vm:n-word-bytes index))))
- (if (eql tl-val sb!vm::unbound-marker-widetag)
- (sb!vm::symbol-global-value symbol)
- (sb!kernel:make-lisp-obj tl-val))))))
-