restore non-consingness of WITH-SPINLOCK
[sbcl/pkhuong.git] / src / code / thread.lisp
blob6e6ebecd26041488d5f5170fba61f18ca45bc466
1 ;;;; support for threads needed at cross-compile time
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
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!struct mutex
15 #!+sb-doc
16 "Mutex type."
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)
22 (lutex (make-lutex)))
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."
27 (mutex-%owner mutex))
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."
39 '(setf mutex-value))
40 form)
42 (def!struct spinlock
43 #!+sb-doc
44 "Spinlock type."
45 (name nil :type (or null simple-string))
46 (value nil))
48 (sb!xc:defmacro with-mutex ((mutex &key (value '*current-thread*) (wait-p t))
49 &body body)
50 #!+sb-doc
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))
55 (call-with-mutex
56 #'with-mutex-thunk
57 ,mutex
58 ,value
59 ,wait-p)))
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
70 ,mutex)))
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
76 ,spinlock)))
78 (sb!xc:defmacro with-recursive-lock ((mutex) &body body)
79 #!+sb-doc
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
87 ,mutex)))
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
93 ,spinlock)))
95 (sb!xc:defmacro with-recursive-system-spinlock ((spinlock
96 &key without-gcing)
97 &body body)
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
104 ,spinlock)))
106 (sb!xc:defmacro with-spinlock ((spinlock) &body body)
107 `(dx-flet ((with-spinlock-thunk () ,@body))
108 (call-with-spinlock
109 #'with-spinlock-thunk
110 ,spinlock)))
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
115 ;;; using them.
116 #!-sb-thread
117 (progn
118 (macrolet ((def (name &optional variant)
119 `(defun ,(if variant (symbolicate name "/" variant) name) (function lock)
120 (declare (ignore lock) (function function))
121 ,(ecase variant
122 (:without-gcing
123 `(without-gcing (funcall function)))
124 (:allow-with-interrupts
125 `(without-interrupts (allow-with-interrupts (funcall function))))
126 ((nil)
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)
137 (function function))
138 (funcall function))
140 (defun call-with-recursive-lock (function mutex)
141 (declare (ignore mutex) (function function))
142 (funcall function))
144 (defun call-with-spinlock (function spinlock)
145 (declare (ignore spinlock) (function function))
146 (funcall function))
148 (defun call-with-recursive-spinlock (function spinlock)
149 (declare (ignore spinlock) (function function))
150 (funcall function)))
152 #!+sb-thread
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.
156 (progn
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 ()
161 (dx-let (got-it)
162 (unwind-protect
163 (when (setf got-it (get-mutex mutex))
164 (funcall function))
165 (when got-it
166 (release-mutex mutex))))))
167 (declare (inline %call-with-system-mutex))
168 ,(ecase variant
169 (:without-gcing
170 `(without-gcing (%call-with-system-mutex)))
171 (:allow-with-interrupts
172 `(without-interrupts (allow-with-interrupts (%call-with-system-mutex))))
173 ((nil)
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))
181 (without-interrupts
182 (dx-let (got-it)
183 (unwind-protect
184 (when (setf got-it (get-spinlock spinlock))
185 (funcall function))
186 (when got-it
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)))
194 (got-it nil))
195 (unwind-protect
196 (when (or inner-lock-p (setf got-it (get-spinlock spinlock)))
197 (funcall function))
198 (when got-it
199 (release-spinlock spinlock))))))
200 (declare (inline %call-with-system-spinlock))
201 ,(ecase variant
202 (:without-gcing
203 `(without-gcing (%call-with-system-spinlock)))
204 ((nil)
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))
212 (without-interrupts
213 (unwind-protect
214 (when (setf got-it (allow-with-interrupts
215 (get-spinlock spinlock)))
216 (with-local-interrupts (funcall function)))
217 (when got-it
218 (release-spinlock spinlock))))))
220 (defun call-with-mutex (function mutex value waitp)
221 (declare (function function))
222 (dx-let ((got-it nil))
223 (without-interrupts
224 (unwind-protect
225 (when (setq got-it (allow-with-interrupts
226 (get-mutex mutex value waitp)))
227 (with-local-interrupts (funcall function)))
228 (when got-it
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*))
234 (got-it nil))
235 (without-interrupts
236 (unwind-protect
237 (when (or inner-lock-p (setf got-it (allow-with-interrupts
238 (get-mutex mutex))))
239 (with-local-interrupts (funcall function)))
240 (when got-it
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*))
248 (got-it nil))
249 (without-interrupts
250 (unwind-protect
251 (when (or inner-lock-p (setf got-it (allow-with-interrupts
252 (get-spinlock spinlock))))
253 (with-local-interrupts (funcall function)))
254 (when got-it
255 (release-spinlock spinlock)))))))