;; 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 :sigint :ignore)
+ (sb!sys:enable-interrupt sb!unix:sigint :ignore)
(sb!unix:unix-exit
(catch 'sb!impl::%end-of-the-world
(with-simple-restart
(funcall real-function))
0))))))))
-;;; Conventional wisdom says that it's a bad idea to use these unless
-;;; you really need to. Use a lock or a waitqueue instead
+;;; 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 :sigstop))
+ (sb!unix:unix-kill thread-id sb!unix:sigstop))
(defun resume-thread (thread-id)
- (sb!unix:unix-kill thread-id :sigcont))
+ (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 :sigterm)
+ (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 :sigcont))
+ (sb!unix:unix-kill thread-id sb!unix:sigcont))
;;; a moderate degree of care is expected for use of interrupt-thread,
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 ()
- (sb!sys:sap-int
- (sb!vm::current-thread-offset-sap sb!vm::thread-pid-slot)))
+ (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
;;;; queues, locks
;; spinlocks use 0 as "free" value: higher-level locks use NIL
+(declaim (inline get-spinlock release-spinlock))
+
(defun get-spinlock (lock offset new-value)
(declare (optimize (speed 3) (safety 0)))
(loop until
(eql (sb!vm::%instance-set-conditional lock offset 0 new-value) 0)))
+;; this should do nothing if we didn't own the lock, so safe to use in
+;; unwind-protect cleanups when lock acquisition failed for some reason
+(defun release-spinlock (lock offset our-value)
+ (declare (optimize (speed 3) (safety 0)))
+ (sb!vm::%instance-set-conditional lock offset our-value 0))
+
(defmacro with-spinlock ((queue) &body body)
(with-unique-names (pid)
- `(unwind-protect
- (let ((,pid (current-thread-id)))
- (get-spinlock ,queue 2 ,pid)
- ,@body)
- (setf (waitqueue-lock ,queue) 0))))
+ `(let ((,pid (current-thread-id)))
+ (unwind-protect
+ (progn
+ (get-spinlock ,queue 2 ,pid)
+ ,@body)
+ (release-spinlock ,queue 2 ,pid)))))
+
;;;; the higher-level locking operations are based on waitqueues
(sb!alien:define-alien-routine "block_sigcont" void)
(sb!alien:define-alien-routine "unblock_sigcont_and_sleep" void)
+
;;; this should only be called while holding the queue spinlock.
;;; it releases the spinlock before sleeping
(defun wait-on-queue (queue &optional lock)
(let ((pid (current-thread-id)))
- ;; FIXME what should happen if we get interrupted when we've blocked
- ;; the sigcont? For that matter, can we get interrupted?
(block-sigcont)
(when lock (release-mutex lock))
(sb!sys:without-interrupts
;;; this should only be called while holding the queue spinlock.
(defun signal-queue-head (queue)
(let ((p (car (waitqueue-data queue))))
- (when p (sb!unix:unix-kill p :sigcont))))
+ (when p (sb!unix:unix-kill p sb!unix::sig-dequeue))))
;;;; mutex
(defun get-mutex (lock &optional new-value (wait-p t))
- (declare (type mutex lock))
+ (declare (type mutex lock)
+ (optimize (speed 3)))
(let ((pid (current-thread-id)))
(unless new-value (setf new-value pid))
(assert (not (eql new-value (mutex-value lock))))
(sb!sys:make-fd-stream err :input t :output t :buffering :line))
(sb!impl::*descriptor-handlers* nil))
(get-mutex *session-lock*)
- (sb!sys:enable-interrupt :sigint #'sb!unix::sigint-handler)
+ (sb!sys:enable-interrupt sb!unix:sigint #'sb!unix::sigint-handler)
(unwind-protect
(sb!impl::toplevel-repl nil)
(sb!int:flush-standard-output-streams)))))
(sb!impl::repl-prompt-fun out-stream))))
(defun resume-stopped-thread (id)
- (let ((pid (current-thread-id))
- (lock *session-lock*))
+ (let ((lock *session-lock*))
(with-spinlock (lock)
(setf (waitqueue-data lock)
(cons id (delete id (waitqueue-data lock)))))