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)))))))