     public func withReadLock<Return>(@noescape body: () throws -> Return) rethrows -> Return {
         // spin until we acquire read lock
         repeat {
-            let state = _state.memory
-
-            // if there is no writer and no writer waiting, try to increment reader count
-            if (state & Masks.MASK_WRITER_BITS) == 0 &&
-                OSAtomicCompareAndSwap32Barrier(state, state + 1, _state) {
-                    break
-            }
+            // wait for active writer to release the lock
+            while (state.memory & Constants.WriterMask) != 0 {
+                _OSAtomicSpin()
+            }
+
+            // increment the reader count
+            if (OSAtomicIncrement32Barrier(state) & Constants.WriterMask) == 0 {
+                // read lock required
+                break
+            }
+
+            // a writer became active while locking; try again
+            OSAtomicDecrement32Barrier(state)
         } while true
         
         defer {
-            // decrement reader count
-            repeat {
-                let state = _state.memory
-                
-                // sanity check that we have a positive reader count before decrementing it
-                assert((state & Masks.MASK_READER_BITS) > 0, "unlocking read lock - invalid reader count")
-                
-                // desired new state: 1 fewer reader, preserving whether or not there is a writer waiting
-                let newState = ((state & Masks.MASK_READER_BITS) - 1) |
-                    (state & Masks.WRITER_WAITING_BIT)
-                
-                if OSAtomicCompareAndSwap32Barrier(state, newState, _state) {
-                    break
-                }
-            } while true
-        }
-
-        // read lock acquired - run block
+            // decrement readers, potentially unblock writers
+            OSAtomicDecrement32Barrier(state)
+        }
+
         return try body()
     }
 }

/// A custom spin-lock with readers-writer semantics. The spin lock will poll
/// to check the state of the lock, allowing many readers at the same time.
public final class CASSpinLock: ReadWriteLock {
    private struct Masks {
        static let WRITER_BIT: Int32         = 0x40000000
        static let WRITER_WAITING_BIT: Int32 = 0x20000000
        static let MASK_WRITER_BITS          = WRITER_BIT | WRITER_WAITING_BIT
        static let MASK_READER_BITS          = ~MASK_WRITER_BITS
    }

    private var _state: UnsafeMutablePointer<Int32>

    /// Allocate the spinlock.
    public init() {
        _state = UnsafeMutablePointer.alloc(1)
        _state.initialize(0)
    }

    deinit {
        _state.destroy()
        _state.dealloc(1)
    }

    /// Call `body` with a writing lock.

    public func withWriteLock<Return>(@noescape body: () throws -> Return) rethrows -> Return {
        // spin until we acquire write lock
        repeat {
            // wait for any active writer to release the lock
            while (state.memory & Constants.WriterMask) != 0 {
                _OSAtomicSpin()
            }

            // increment the writer count
            if (OSAtomicAdd32Barrier(Constants.WriterOffset, state) & Constants.WriterMask) == Constants.WriterOffset {
                // wait until there are no more readers
                while (state.memory & Constants.ReaderMask) != 0 {
                    _OSAtomicSpin()
                }

                // write lock acquired
                break
            }

            // there's another writer active; try again
            OSAtomicAdd32Barrier(-Constants.WriterOffset, state)
        } while true
        
        defer {
            // decrement writers, potentially unblock readers
            OSAtomicAdd32Barrier(-Constants.WriterOffset, state)
        }

        return try body()
    }

