1 ;;;; support for threads needed at cross-compile time
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 (in-package "SB!THREAD")
17 (name nil
:type
(or null simple-string
))
18 (%owner nil
:type
(or null thread
))
19 #!+(and (not sb-lutex
) sb-thread
)
20 (state 0 :type fixnum
)
21 #!+(and sb-lutex sb-thread
)
24 ;;; FIXME: We probably want to rename the accessor MUTEX-OWNER.
25 (defun mutex-value (mutex)
26 "Current owner of the mutex, NIL if the mutex is free."
29 (defsetf mutex-value set-mutex-value
)
31 (declaim (inline set-mutex-value
))
32 (defun set-mutex-value (mutex value
)
33 (declare (ignore mutex value
))
34 (error "~S is no longer supported." '(setf mutex-value
)))
36 (define-compiler-macro set-mutex-value
(&whole form mutex value
)
37 (declare (ignore mutex value
))
38 (warn "~S is no longer supported, and will signal an error at runtime."
45 (name nil
:type
(or null simple-string
))
48 (sb!xc
:defmacro with-mutex
((mutex &key
(value '*current-thread
*) (wait-p t
))
51 "Acquire MUTEX for the dynamic scope of BODY, setting it to
52 NEW-VALUE or some suitable default value if NIL. If WAIT-P is non-NIL
53 and the mutex is in use, sleep until it is available"
54 `(dx-flet ((with-mutex-thunk () ,@body
))
61 (sb!xc
:defmacro with-system-mutex
((mutex &key without-gcing allow-with-interrupts
) &body body
)
62 `(dx-flet ((with-system-mutex-thunk () ,@body
))
63 (,(cond (without-gcing
64 'call-with-system-mutex
/without-gcing
)
65 (allow-with-interrupts
66 'call-with-system-mutex
/allow-with-interrupts
)
68 'call-with-system-mutex
))
69 #'with-system-mutex-thunk
72 (sb!xc
:defmacro with-system-spinlock
((spinlock &key
) &body body
)
73 `(dx-flet ((with-system-spinlock-thunk () ,@body
))
74 (call-with-system-spinlock
75 #'with-system-spinlock-thunk
78 (sb!xc
:defmacro with-recursive-lock
((mutex) &body body
)
80 "Acquires MUTEX for the dynamic scope of BODY. Within that scope
81 further recursive lock attempts for the same mutex succeed. It is
82 allowed to mix WITH-MUTEX and WITH-RECURSIVE-LOCK for the same mutex
83 provided the default value is used for the mutex."
84 `(dx-flet ((with-recursive-lock-thunk () ,@body
))
85 (call-with-recursive-lock
86 #'with-recursive-lock-thunk
89 (sb!xc
:defmacro with-recursive-spinlock
((spinlock) &body body
)
90 `(dx-flet ((with-recursive-spinlock-thunk () ,@body
))
91 (call-with-recursive-spinlock
92 #'with-recursive-spinlock-thunk
95 (sb!xc
:defmacro with-recursive-system-spinlock
((spinlock
98 `(dx-flet ((with-recursive-system-spinlock-thunk () ,@body
))
99 (,(cond (without-gcing
100 'call-with-recursive-system-spinlock
/without-gcing
)
102 'call-with-recursive-system-spinlock
))
103 #'with-recursive-system-spinlock-thunk
106 (sb!xc
:defmacro with-spinlock
((spinlock) &body body
)
107 `(dx-flet ((with-spinlock-thunk () ,@body
))
109 #'with-spinlock-thunk
112 ;;; KLUDGE: this separate implementation for (NOT SB-THREAD) is not
113 ;;; strictly necessary; GET-MUTEX and RELEASE-MUTEX are implemented.
114 ;;; However, there would be a (possibly slight) performance hit in
118 (macrolet ((def (name &optional variant
)
119 `(defun ,(if variant
(symbolicate name
"/" variant
) name
) (function lock
)
120 (declare (ignore lock
) (function function
))
123 `(without-gcing (funcall function
)))
124 (:allow-with-interrupts
125 `(without-interrupts (allow-with-interrupts (funcall function
))))
127 `(without-interrupts (funcall function
)))))))
128 (def call-with-system-mutex
)
129 (def call-with-system-mutex
:without-gcing
)
130 (def call-with-system-mutex
:allow-with-interrupts
)
131 (def call-with-system-spinlock
)
132 (def call-with-recursive-system-spinlock
)
133 (def call-with-recursive-system-spinlock
:without-gcing
))
135 (defun call-with-mutex (function mutex value waitp
)
136 (declare (ignore mutex value waitp
)
140 (defun call-with-recursive-lock (function mutex
)
141 (declare (ignore mutex
) (function function
))
144 (defun call-with-spinlock (function spinlock
)
145 (declare (ignore spinlock
) (function function
))
148 (defun call-with-recursive-spinlock (function spinlock
)
149 (declare (ignore spinlock
) (function function
))
153 ;;; KLUDGE: These need to use DX-LET, because the cleanup form that
154 ;;; closes over GOT-IT causes a value-cell to be allocated for it --
155 ;;; and we prefer that to go on the stack since it can.
157 (macrolet ((def (name &optional variant
)
158 `(defun ,(if variant
(symbolicate name
"/" variant
) name
) (function mutex
)
159 (declare (function function
))
160 (flet ((%call-with-system-mutex
()
163 (when (setf got-it
(get-mutex mutex
))
166 (release-mutex mutex
))))))
167 (declare (inline %call-with-system-mutex
))
170 `(without-gcing (%call-with-system-mutex
)))
171 (:allow-with-interrupts
172 `(without-interrupts (allow-with-interrupts (%call-with-system-mutex
))))
174 `(without-interrupts (%call-with-system-mutex
))))))))
175 (def call-with-system-mutex
)
176 (def call-with-system-mutex
:without-gcing
)
177 (def call-with-system-mutex
:allow-with-interrupts
))
179 (defun call-with-system-spinlock (function spinlock
)
180 (declare (function function
))
184 (when (setf got-it
(get-spinlock spinlock
))
187 (release-spinlock spinlock
))))))
189 (macrolet ((def (name &optional variant
)
190 `(defun ,(if variant
(symbolicate name
"/" variant
) name
) (function spinlock
)
191 (declare (function function
))
192 (flet ((%call-with-system-spinlock
()
193 (dx-let ((inner-lock-p (eq *current-thread
* (spinlock-value spinlock
)))
196 (when (or inner-lock-p
(setf got-it
(get-spinlock spinlock
)))
199 (release-spinlock spinlock
))))))
200 (declare (inline %call-with-system-spinlock
))
203 `(without-gcing (%call-with-system-spinlock
)))
205 `(without-interrupts (%call-with-system-spinlock
))))))))
206 (def call-with-recursive-system-spinlock
)
207 (def call-with-recursive-system-spinlock
:without-gcing
))
209 (defun call-with-spinlock (function spinlock
)
210 (declare (function function
))
211 (dx-let ((got-it nil
))
214 (when (setf got-it
(allow-with-interrupts
215 (get-spinlock spinlock
)))
216 (with-local-interrupts (funcall function
)))
218 (release-spinlock spinlock
))))))
220 (defun call-with-mutex (function mutex value waitp
)
221 (declare (function function
))
222 (dx-let ((got-it nil
))
225 (when (setq got-it
(allow-with-interrupts
226 (get-mutex mutex value waitp
)))
227 (with-local-interrupts (funcall function
)))
229 (release-mutex mutex
))))))
231 (defun call-with-recursive-lock (function mutex
)
232 (declare (function function
))
233 (dx-let ((inner-lock-p (eq (mutex-%owner mutex
) *current-thread
*))
237 (when (or inner-lock-p
(setf got-it
(allow-with-interrupts
239 (with-local-interrupts (funcall function
)))
241 (release-mutex mutex
))))))
245 (defun call-with-recursive-spinlock (function spinlock
)
246 (declare (function function
))
247 (dx-let ((inner-lock-p (eq (spinlock-value spinlock
) *current-thread
*))
251 (when (or inner-lock-p
(setf got-it
(allow-with-interrupts
252 (get-spinlock spinlock
))))
253 (with-local-interrupts (funcall function
)))
255 (release-spinlock spinlock
)))))))