1.0.27.31: repeatable fasl header and debug-source
[sbcl.git] / src / code / thread.lisp
1 ;;;; support for threads needed at cross-compile time
2
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.
11
12 (in-package "SB!THREAD")
13
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)))
23
24 (defun mutex-value (mutex)
25   "Current owner of the mutex, NIL if the mutex is free. May return a
26 stale value, use MUTEX-OWNER instead."
27   (mutex-%owner mutex))
28
29 (defun holding-mutex-p (mutex)
30   "Test whether the current thread is holding MUTEX."
31   ;; This is about the only use for which a stale value of owner is
32   ;; sufficient.
33   (eq sb!thread:*current-thread* (mutex-%owner mutex)))
34
35 (defsetf mutex-value set-mutex-value)
36
37 (declaim (inline set-mutex-value))
38 (defun set-mutex-value (mutex value)
39   (declare (ignore mutex value))
40   (error "~S is no longer supported." '(setf mutex-value)))
41
42 (define-compiler-macro set-mutex-value (&whole form mutex value)
43   (declare (ignore mutex value))
44   (warn "~S is no longer supported, and will signal an error at runtime."
45         '(setf mutex-value))
46   form)
47
48 (def!struct spinlock
49   #!+sb-doc
50   "Spinlock type."
51   (name nil :type (or null simple-string))
52   (value nil))
53
54 (sb!xc:defmacro with-mutex ((mutex &key (value '*current-thread*) (wait-p t))
55                             &body body)
56   #!+sb-doc
57   "Acquire MUTEX for the dynamic scope of BODY, setting it to
58 NEW-VALUE or some suitable default value if NIL.  If WAIT-P is non-NIL
59 and the mutex is in use, sleep until it is available"
60   `(dx-flet ((with-mutex-thunk () ,@body))
61      (call-with-mutex
62       #'with-mutex-thunk
63       ,mutex
64       ,value
65       ,wait-p)))
66
67 (sb!xc:defmacro with-system-mutex ((mutex
68                                     &key without-gcing allow-with-interrupts)
69                                    &body body)
70   `(dx-flet ((with-system-mutex-thunk () ,@body))
71      (,(cond (without-gcing
72                'call-with-system-mutex/without-gcing)
73              (allow-with-interrupts
74               'call-with-system-mutex/allow-with-interrupts)
75              (t
76               'call-with-system-mutex))
77        #'with-system-mutex-thunk
78        ,mutex)))
79
80 (sb!xc:defmacro with-system-spinlock ((spinlock &key) &body body)
81   `(dx-flet ((with-system-spinlock-thunk () ,@body))
82      (call-with-system-spinlock
83        #'with-system-spinlock-thunk
84        ,spinlock)))
85
86 (sb!xc:defmacro with-recursive-lock ((mutex) &body body)
87   #!+sb-doc
88   "Acquires MUTEX for the dynamic scope of BODY. Within that scope
89 further recursive lock attempts for the same mutex succeed. It is
90 allowed to mix WITH-MUTEX and WITH-RECURSIVE-LOCK for the same mutex
91 provided the default value is used for the mutex."
92   `(dx-flet ((with-recursive-lock-thunk () ,@body))
93      (call-with-recursive-lock
94       #'with-recursive-lock-thunk
95       ,mutex)))
96
97 (sb!xc:defmacro with-recursive-spinlock ((spinlock) &body body)
98   `(dx-flet ((with-recursive-spinlock-thunk () ,@body))
99      (call-with-recursive-spinlock
100       #'with-recursive-spinlock-thunk
101       ,spinlock)))
102
103 (sb!xc:defmacro with-recursive-system-spinlock ((spinlock
104                                                  &key without-gcing)
105                                                 &body body)
106   `(dx-flet ((with-recursive-system-spinlock-thunk () ,@body))
107      (,(cond (without-gcing
108                'call-with-recursive-system-spinlock/without-gcing)
109              (t
110               'call-with-recursive-system-spinlock))
111        #'with-recursive-system-spinlock-thunk
112        ,spinlock)))
113
114 (sb!xc:defmacro with-spinlock ((spinlock) &body body)
115   `(dx-flet ((with-spinlock-thunk () ,@body))
116      (call-with-spinlock
117       #'with-spinlock-thunk
118       ,spinlock)))
119
120 (macrolet ((def (name &optional variant)
121              `(defun ,(if variant (symbolicate name "/" variant) name)
122                   (function mutex)
123                 (declare (function function))
124                 (flet ((%call-with-system-mutex ()
125                          (dx-let (got-it)
126                            (unwind-protect
127                                 (when (setf got-it (get-mutex mutex))
128                                   (funcall function))
129                              (when got-it
130                                (release-mutex mutex))))))
131                   (declare (inline %call-with-system-mutex))
132                   ,(ecase variant
133                      (:without-gcing
134                        `(without-gcing (%call-with-system-mutex)))
135                      (:allow-with-interrupts
136                        `(without-interrupts
137                           (allow-with-interrupts (%call-with-system-mutex))))
138                      ((nil)
139                       `(without-interrupts (%call-with-system-mutex))))))))
140   (def call-with-system-mutex)
141   (def call-with-system-mutex :without-gcing)
142   (def call-with-system-mutex :allow-with-interrupts))
143
144 #!-sb-thread
145 (progn
146   (macrolet ((def (name &optional variant)
147                `(defun ,(if variant (symbolicate name "/" variant) name)
148                     (function lock)
149                   (declare (ignore lock) (function function))
150                   ,(ecase variant
151                     (:without-gcing
152                       `(without-gcing (funcall function)))
153                     (:allow-with-interrupts
154                       `(without-interrupts
155                          (allow-with-interrupts (funcall function))))
156                     ((nil)
157                       `(without-interrupts (funcall function)))))))
158     (def call-with-system-spinlock)
159     (def call-with-recursive-system-spinlock)
160     (def call-with-recursive-system-spinlock :without-gcing))
161
162   (defun call-with-mutex (function mutex value waitp)
163     (declare (ignore mutex value waitp)
164              (function function))
165     (funcall function))
166
167   (defun call-with-recursive-lock (function mutex)
168     (declare (ignore mutex) (function function))
169     (funcall function))
170
171   (defun call-with-spinlock (function spinlock)
172     (declare (ignore spinlock) (function function))
173     (funcall function))
174
175   (defun call-with-recursive-spinlock (function spinlock)
176     (declare (ignore spinlock) (function function))
177     (funcall function)))
178
179 #!+sb-thread
180 ;;; KLUDGE: These need to use DX-LET, because the cleanup form that
181 ;;; closes over GOT-IT causes a value-cell to be allocated for it --
182 ;;; and we prefer that to go on the stack since it can.
183 (progn
184   (defun call-with-system-spinlock (function spinlock)
185     (declare (function function))
186     (without-interrupts
187       (dx-let (got-it)
188         (unwind-protect
189              (when (setf got-it (get-spinlock spinlock))
190                (funcall function))
191           (when got-it
192             (release-spinlock spinlock))))))
193
194   (macrolet ((def (name &optional variant)
195                `(defun ,(if variant (symbolicate name "/" variant) name)
196                     (function spinlock)
197                   (declare (function function))
198                   (flet ((%call-with-system-spinlock ()
199                            (dx-let ((inner-lock-p
200                                      (eq *current-thread*
201                                          (spinlock-value spinlock)))
202                                     (got-it nil))
203                              (unwind-protect
204                                   (when (or inner-lock-p
205                                             (setf got-it
206                                                   (get-spinlock spinlock)))
207                                     (funcall function))
208                                (when got-it
209                                  (release-spinlock spinlock))))))
210                     (declare (inline %call-with-system-spinlock))
211                     ,(ecase variant
212                       (:without-gcing
213                         `(without-gcing (%call-with-system-spinlock)))
214                       ((nil)
215                         `(without-interrupts (%call-with-system-spinlock))))))))
216     (def call-with-recursive-system-spinlock)
217     (def call-with-recursive-system-spinlock :without-gcing))
218
219   (defun call-with-spinlock (function spinlock)
220     (declare (function function))
221     (dx-let ((got-it nil))
222       (without-interrupts
223         (unwind-protect
224              (when (setf got-it (allow-with-interrupts
225                                  (get-spinlock spinlock)))
226                (with-local-interrupts (funcall function)))
227           (when got-it
228             (release-spinlock spinlock))))))
229
230   (defun call-with-mutex (function mutex value waitp)
231     (declare (function function))
232     (dx-let ((got-it nil))
233       (without-interrupts
234         (unwind-protect
235              (when (setq got-it (allow-with-interrupts
236                                  (get-mutex mutex value waitp)))
237                (with-local-interrupts (funcall function)))
238           (when got-it
239             (release-mutex mutex))))))
240
241   (defun call-with-recursive-lock (function mutex)
242     (declare (function function))
243     (dx-let ((inner-lock-p (eq (mutex-%owner mutex) *current-thread*))
244              (got-it nil))
245       (without-interrupts
246         (unwind-protect
247              (when (or inner-lock-p (setf got-it (allow-with-interrupts
248                                                   (get-mutex mutex))))
249                (with-local-interrupts (funcall function)))
250           (when got-it
251             (release-mutex mutex))))))
252
253   (defun call-with-recursive-spinlock (function spinlock)
254     (declare (function function))
255     (dx-let ((inner-lock-p (eq (spinlock-value spinlock) *current-thread*))
256           (got-it nil))
257       (without-interrupts
258         (unwind-protect
259              (when (or inner-lock-p (setf got-it (allow-with-interrupts
260                                                   (get-spinlock spinlock))))
261                (with-local-interrupts (funcall function)))
262           (when got-it
263             (release-spinlock spinlock)))))))