-
-(declaim (inline get-spinlock release-spinlock))
-
-;;; Should always be called with interrupts disabled.
-(defun get-spinlock (spinlock)
- (declare (optimize (speed 3) (safety 0)))
- (let* ((new *current-thread*)
- (old (sb!ext:compare-and-swap (spinlock-value spinlock) nil new)))
- (when old
- (when (eq old new)
- (error "Recursive lock attempt on ~S." spinlock))
- #!+sb-thread
- (with-deadlocks (new spinlock)
- (flet ((cas ()
- (if (sb!ext:compare-and-swap (spinlock-value spinlock) nil new)
- (thread-yield)
- (return-from get-spinlock t))))
- ;; Try once.
- (cas)
- ;; Check deadlocks
- (with-interrupts (check-deadlock))
- (if (and (not *interrupts-enabled*) *allow-with-interrupts*)
- ;; If interrupts are disabled, but we are allowed to
- ;; enabled them, check for pending interrupts every once
- ;; in a while. %CHECK-INTERRUPTS is taking shortcuts, make
- ;; sure that deferrables are unblocked by doing an empty
- ;; WITH-INTERRUPTS once.
- (progn
- (with-interrupts)
- (loop
- (loop repeat 128 do (cas)) ; 128 is arbitrary here
- (sb!unix::%check-interrupts)))
- (loop (cas)))))))
- t)
-
-(defun release-spinlock (spinlock)
- (declare (optimize (speed 3) (safety 0)))
- ;; On x86 and x86-64 we can get away with no memory barriers, (see
- ;; Linux kernel mailing list "spin_unlock optimization(i386)"
- ;; thread, summary at
- ;; http://kt.iserv.nl/kernel-traffic/kt19991220_47.html#1.
- ;;
- ;; If the compiler may reorder this with other instructions, insert
- ;; compiler barrier here.
- ;;
- ;; FIXME: this does not work on SMP Pentium Pro and OOSTORE systems,
- ;; neither on most non-x86 architectures (but we don't have threads
- ;; on those).
- (setf (spinlock-value spinlock) nil)
-
- ;; FIXME: Is a :memory barrier too strong here? Can we use a :write
- ;; barrier instead?
- #!+(not (or x86 x86-64))
- (barrier (:memory)))