;; FUNCTION until the other is called, from when it does nothing.
(let ((mutex (sb!thread:make-mutex))
(cancelled-p nil))
- #!-sb-thread
- (declare (ignore mutex))
(list
#'(lambda ()
(sb!thread:with-recursive-lock (mutex)
(defmacro with-scheduler-lock ((&optional) &body body)
;; don't let the SIGALRM handler mess things up
- `(sb!sys:without-interrupts
- (sb!thread:with-mutex (*scheduler-lock*)
- ,@body)))
+ `(sb!thread::call-with-system-mutex (lambda () ,@body) *scheduler-lock*))
(defun under-scheduler-lock-p ()
#!-sb-thread
(defmacro sb!ext:with-timeout (expires &body body)
#!+sb-doc
- "Execute the body, asynchronously interrupting it and signalling a
-TIMEOUT condition after at least EXPIRES seconds have passed."
+ "Execute the body, asynchronously interrupting it and signalling a TIMEOUT
+condition after at least EXPIRES seconds have passed.
+
+Note that it is never safe to unwind from an asynchronous condition. Consider:
+
+ (defun call-with-foo (function)
+ (let (foo)
+ (unwind-protect
+ (progn
+ (setf foo (get-foo))
+ (funcall function foo))
+ (when foo
+ (release-foo foo)))))
+
+If TIMEOUT occurs after GET-FOO has executed, but before the assignment, then
+RELEASE-FOO will be missed. While individual sites like this can be made proof
+against asynchronous unwinds, this doesn't solve the fundamental issue, as all
+the frames potentially unwound through need to be proofed, which includes both
+system and application code -- and in essence proofing everything will make
+the system uninterruptible."
(with-unique-names (timer)
;; FIXME: a temporary compatibility workaround for CLX, if unsafe
;; unwinds are handled revisit it.