1 (in-package "SB!THREAD")
3 ;;; used bu debug-int.lisp to access interrupt contexts
4 #!-sb-fluid (declaim (inline sb!vm::current-thread-offset-sap))
5 (defun sb!vm::current-thread-offset-sap (n)
6 (declare (type (unsigned-byte 27) n))
7 (sb!sys:sap-ref-sap (alien-sap (extern-alien "all_threads" (* t)))
10 (defun current-thread-id ()
11 (sb!sys:sap-ref-32 (alien-sap (extern-alien "all_threads" (* t)))
12 (* sb!vm::thread-pid-slot 4)))
16 ;; spinlocks use 0 as "free" value: higher-level locks use NIL
17 (defun get-spinlock (lock offset new-value)
18 (declare (ignore lock offset new-value)))
20 (defmacro with-spinlock ((queue) &body body)
21 (declare (ignore queue))
24 ;;;; the higher-level locking operations are based on waitqueues
27 (name nil :type (or null simple-base-string))
31 (defstruct (mutex (:include waitqueue))
35 (defun wait-on-queue (queue &optional lock)
36 (let ((pid (current-thread-id)))
37 ;; FIXME what should happen if we get interrupted when we've blocked
38 ;; the sigcont? For that matter, can we get interrupted?
40 (when lock (release-mutex lock))
41 (get-spinlock queue 2 pid)
42 (pushnew pid (waitqueue-data queue))
43 (setf (waitqueue-lock queue) 0)
44 (unblock-sigcont-and-sleep)))
47 (defun dequeue (queue)
48 (let ((pid (current-thread-id)))
49 (get-spinlock queue 2 pid)
50 (setf (waitqueue-data queue)
51 (delete pid (waitqueue-data queue)))
52 (setf (waitqueue-lock queue) 0)))
55 (defun signal-queue-head (queue)
56 (let ((pid (current-thread-id)))
57 (get-spinlock queue 2 pid)
58 (let ((h (car (waitqueue-data queue))))
59 (setf (waitqueue-lock queue) 0)
61 (sb!unix:unix-kill h sb!unix:sigcont)))))
66 (defun get-mutex (lock &optional new-value (wait-p t))
67 (declare (type mutex lock))
68 (let ((pid (current-thread-id)))
69 (unless new-value (setf new-value pid))
70 (assert (not (eql new-value (mutex-value lock))))
73 ;; args are object slot-num old-value new-value
74 (sb!vm::%instance-set-conditional lock 4 nil new-value)
77 (unless wait-p (return nil))
78 (wait-on-queue lock nil))))
81 (defun release-mutex (lock &optional (new-value nil))
82 (declare (type mutex lock))
83 (let ((old-value (mutex-value lock))
87 ;; args are object slot-num old-value new-value
90 (sb!vm::%instance-set-conditional lock 4 old-value new-value)))
91 (signal-queue-head lock)
93 (setf old-value t1))))
95 (defmacro with-mutex ((mutex &key value (wait-p t)) &body body)
97 `(unless (mutex-value ,mutex)
100 (setf (mutex-value ,mutex) (or ,value t))
102 (setf (mutex-value ,mutex) nil))))
106 ;;; what's the best thing to do with these on unithread? commented
107 ;;; functions are the thread versions, just to remind me what they do
110 (defun condition-wait (queue lock)
111 "Atomically release LOCK and enqueue ourselves on QUEUE. Another
112 thread may subsequently notify us using CONDITION-NOTIFY, at which
113 time we reacquire LOCK and return to the caller."
115 (wait-on-queue queue lock)
116 ;; If we are interrupted while waiting, we should do these things
117 ;; before returning. Ideally, in the case of an unhandled signal,
118 ;; we should do them before entering the debugger, but this is
119 ;; better than nothing.
124 (defun condition-notify (queue)
125 "Notify one of the processes waiting on QUEUE"
126 (signal-queue-head queue))
128 (defun maybe-install-futex-functions () nil)
132 (defun init-job-control () t)
133 (defun debugger-wait-until-foreground-thread (stream)
134 (declare (ignore stream))
136 (defun get-foreground () t)
137 (defun release-foreground (&optional next)
138 (declare (ignore next))
140 (defun terminate-session ())