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")
14 (def!type thread-name
()
17 (def!struct
(thread (:constructor %make-thread
))
19 "Thread type. Do not rely on threads being structs as it may change
21 (name nil
:type
(or thread-name null
))
22 (%alive-p nil
:type boolean
)
23 (os-thread nil
:type
(or integer null
))
24 (interruptions nil
:type list
)
25 (result nil
:type list
)
27 (make-mutex :name
"thread interruptions lock")
30 (make-mutex :name
"thread result lock")
36 (name nil
:type
(or null thread-name
))
37 (%owner nil
:type
(or null thread
))
38 #!+(and (not sb-lutex
) sb-thread
)
39 (state 0 :type fixnum
)
40 #!+(and sb-lutex sb-thread
)
43 (defun mutex-value (mutex)
44 "Current owner of the mutex, NIL if the mutex is free. May return a
45 stale value, use MUTEX-OWNER instead."
48 (defun holding-mutex-p (mutex)
49 "Test whether the current thread is holding MUTEX."
50 ;; This is about the only use for which a stale value of owner is
52 (eq sb
!thread
:*current-thread
* (mutex-%owner mutex
)))
54 (defsetf mutex-value set-mutex-value
)
56 (declaim (inline set-mutex-value
))
57 (defun set-mutex-value (mutex value
)
58 (declare (ignore mutex value
))
59 (error "~S is no longer supported." '(setf mutex-value
)))
61 (define-compiler-macro set-mutex-value
(&whole form mutex value
)
62 (declare (ignore mutex value
))
63 (warn "~S is no longer supported, and will signal an error at runtime."
70 (name nil
:type
(or null thread-name
))
73 (sb!xc
:defmacro with-mutex
((mutex &key
(value '*current-thread
*) (wait-p t
))
76 "Acquire MUTEX for the dynamic scope of BODY, setting it to VALUE or
77 some suitable default value if NIL. If WAIT-P is non-NIL and the mutex
78 is in use, sleep until it is available"
79 `(dx-flet ((with-mutex-thunk () ,@body
))
86 (sb!xc
:defmacro with-system-mutex
((mutex
87 &key without-gcing allow-with-interrupts
)
89 `(dx-flet ((with-system-mutex-thunk () ,@body
))
90 (,(cond (without-gcing
91 'call-with-system-mutex
/without-gcing
)
92 (allow-with-interrupts
93 'call-with-system-mutex
/allow-with-interrupts
)
95 'call-with-system-mutex
))
96 #'with-system-mutex-thunk
99 (sb!xc
:defmacro with-system-spinlock
((spinlock &key
) &body body
)
100 `(dx-flet ((with-system-spinlock-thunk () ,@body
))
101 (call-with-system-spinlock
102 #'with-system-spinlock-thunk
105 (sb!xc
:defmacro with-recursive-lock
((mutex) &body body
)
107 "Acquires MUTEX for the dynamic scope of BODY. Within that scope
108 further recursive lock attempts for the same mutex succeed. It is
109 allowed to mix WITH-MUTEX and WITH-RECURSIVE-LOCK for the same mutex
110 provided the default value is used for the mutex."
111 `(dx-flet ((with-recursive-lock-thunk () ,@body
))
112 (call-with-recursive-lock
113 #'with-recursive-lock-thunk
116 (sb!xc
:defmacro with-recursive-spinlock
((spinlock) &body body
)
117 `(dx-flet ((with-recursive-spinlock-thunk () ,@body
))
118 (call-with-recursive-spinlock
119 #'with-recursive-spinlock-thunk
122 (sb!xc
:defmacro with-recursive-system-spinlock
((spinlock
125 `(dx-flet ((with-recursive-system-spinlock-thunk () ,@body
))
126 (,(cond (without-gcing
127 'call-with-recursive-system-spinlock
/without-gcing
)
129 'call-with-recursive-system-spinlock
))
130 #'with-recursive-system-spinlock-thunk
133 (sb!xc
:defmacro with-spinlock
((spinlock) &body body
)
134 `(dx-flet ((with-spinlock-thunk () ,@body
))
136 #'with-spinlock-thunk
139 (macrolet ((def (name &optional variant
)
140 `(defun ,(if variant
(symbolicate name
"/" variant
) name
)
142 (declare (function function
))
143 (flet ((%call-with-system-mutex
()
146 (when (setf got-it
(get-mutex mutex
))
149 (release-mutex mutex
))))))
150 (declare (inline %call-with-system-mutex
))
153 `(without-gcing (%call-with-system-mutex
)))
154 (:allow-with-interrupts
156 (allow-with-interrupts (%call-with-system-mutex
))))
158 `(without-interrupts (%call-with-system-mutex
))))))))
159 (def call-with-system-mutex
)
160 (def call-with-system-mutex
:without-gcing
)
161 (def call-with-system-mutex
:allow-with-interrupts
))
165 (macrolet ((def (name &optional variant
)
166 `(defun ,(if variant
(symbolicate name
"/" variant
) name
)
168 (declare (ignore lock
) (function function
))
171 `(without-gcing (funcall function
)))
172 (:allow-with-interrupts
174 (allow-with-interrupts (funcall function
))))
176 `(without-interrupts (funcall function
)))))))
177 (def call-with-system-spinlock
)
178 (def call-with-recursive-system-spinlock
)
179 (def call-with-recursive-system-spinlock
:without-gcing
))
181 (defun call-with-mutex (function mutex value waitp
)
182 (declare (ignore mutex value waitp
)
186 (defun call-with-recursive-lock (function mutex
)
187 (declare (ignore mutex
) (function function
))
190 (defun call-with-spinlock (function spinlock
)
191 (declare (ignore spinlock
) (function function
))
194 (defun call-with-recursive-spinlock (function spinlock
)
195 (declare (ignore spinlock
) (function function
))
199 ;;; KLUDGE: These need to use DX-LET, because the cleanup form that
200 ;;; closes over GOT-IT causes a value-cell to be allocated for it --
201 ;;; and we prefer that to go on the stack since it can.
203 (defun call-with-system-spinlock (function spinlock
)
204 (declare (function function
))
208 (when (setf got-it
(get-spinlock spinlock
))
211 (release-spinlock spinlock
))))))
213 (macrolet ((def (name &optional variant
)
214 `(defun ,(if variant
(symbolicate name
"/" variant
) name
)
216 (declare (function function
))
217 (flet ((%call-with-system-spinlock
()
218 (dx-let ((inner-lock-p
220 (spinlock-value spinlock
)))
223 (when (or inner-lock-p
225 (get-spinlock spinlock
)))
228 (release-spinlock spinlock
))))))
229 (declare (inline %call-with-system-spinlock
))
232 `(without-gcing (%call-with-system-spinlock
)))
234 `(without-interrupts (%call-with-system-spinlock
))))))))
235 (def call-with-recursive-system-spinlock
)
236 (def call-with-recursive-system-spinlock
:without-gcing
))
238 (defun call-with-spinlock (function spinlock
)
239 (declare (function function
))
240 (dx-let ((got-it nil
))
243 (when (setf got-it
(allow-with-interrupts
244 (get-spinlock spinlock
)))
245 (with-local-interrupts (funcall function
)))
247 (release-spinlock spinlock
))))))
249 (defun call-with-mutex (function mutex value waitp
)
250 (declare (function function
))
251 (dx-let ((got-it nil
))
254 (when (setq got-it
(allow-with-interrupts
255 (get-mutex mutex value waitp
)))
256 (with-local-interrupts (funcall function
)))
258 (release-mutex mutex
))))))
260 (defun call-with-recursive-lock (function mutex
)
261 (declare (function function
))
262 (dx-let ((inner-lock-p (eq (mutex-%owner mutex
) *current-thread
*))
266 (when (or inner-lock-p
(setf got-it
(allow-with-interrupts
268 (with-local-interrupts (funcall function
)))
270 (release-mutex mutex
))))))
272 (defun call-with-recursive-spinlock (function spinlock
)
273 (declare (function function
))
274 (dx-let ((inner-lock-p (eq (spinlock-value spinlock
) *current-thread
*))
278 (when (or inner-lock-p
(setf got-it
(allow-with-interrupts
279 (get-spinlock spinlock
))))
280 (with-local-interrupts (funcall function
)))
282 (release-spinlock spinlock
)))))))