Method: ThreadSafe::AtomicReferenceCacheBackend::Node#try_await_lock

Defined in:
lib/thread_safe/atomic_reference_cache_backend.rb

#try_await_lock(table, i) ⇒ Object

Spins a while if +LOCKED+ bit set and this node is the first of its bin, and then sets +WAITING+ bits on hash field and blocks (once) if they are still set. It is OK for this method to return even if lock is not available upon exit, which enables these simple single-wait mechanics.

The corresponding signalling operation is performed within callers: Upon detecting that +WAITING+ has been set when unlocking lock (via a failed CAS from non-waiting +LOCKED+ state), unlockers acquire the +cheap_synchronize+ lock and perform a +cheap_broadcast+.



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/thread_safe/atomic_reference_cache_backend.rb', line 260

def try_await_lock(table, i)
  if table && i >= 0 && i < table.size # bounds check, TODO: why are we bounds checking?
    spins = SPIN_LOCK_ATTEMPTS
    randomizer = base_randomizer = Util::XorShiftRandom.get
    while equal?(table.volatile_get(i)) && self.class.locked_hash?(my_hash = hash)
      if spins >= 0
        if (randomizer = (randomizer >> 1)).even? # spin at random
          if (spins -= 1) == 0
            Thread.pass # yield before blocking
          else
            randomizer = base_randomizer = Util::XorShiftRandom.xorshift(base_randomizer) if randomizer.zero?
          end
        end
      elsif cas_hash(my_hash, my_hash | WAITING)
        force_aquire_lock(table, i)
        break
      end
    end
  end
end