All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.concurrent.stm.ccstm.TxnSlotManager.scala Maven / Gradle / Ivy

The newest version!
/* scala-stm - (c) 2009-2011, Stanford University, PPL */

package scala.concurrent.stm
package ccstm


import java.util.concurrent.atomic.AtomicReferenceArray


private case class SlotLock(txn: AnyRef, refCount: Int)

/** This class manages a mapping from active transaction to a bounded integral
 *  range, so that transaction identities to be packed into some of the bits of
 *  an integral value.
 *
 *  @author Nathan Bronson
 */
private[ccstm] final class TxnSlotManager[T <: AnyRef](range: Int, reservedSlots: Int) {

  assert(range >= 16 & (range & (range - 1)) == 0)
  assert(range >= reservedSlots + 16)

  private def nextSlot(tries: Int) = {
    ((skel.SimpleRandom.nextInt() << 4) | ((-tries >> 1) & 0xf)) & (range - 1)
  }

  /** CAS on the entries manages the actual acquisition.  Entries are either
   *  transactions, or SlotLock objects.
   */
  private val slots = new AtomicReferenceArray[AnyRef](range)

  @throws(classOf[InterruptedException])
  def assign(txn: T, slotHint: Int): Int = {
    // We advance to the next slot number after the hint, wrapping around in a
    // 64 byte space.  This avoids rollback from late steals, but keeps us in
    // a cache line we already own.
    var s = ((slotHint & ~0xf) | ((slotHint + 1) & 0xf)) & (range - 1)

    var tries = 0
    while (s < reservedSlots || slots.get(s) != null || !slots.compareAndSet(s, null, txn)) {
      s = nextSlot(tries)
      tries += 1
      if (tries > 100) {
        if (Thread.interrupted) {
          throw new InterruptedException
        }
        () // Thread.`yield`()
      }
    }
    s
  }

  /** Returns the slot associated with `slot` at some instant.  The
   *  returned value may be obsolete before this method returns.
   */
  def lookup(slot:Int): T = unwrap(slots.get(slot))

  private def unwrap(e: AnyRef): T = {
    e match {
      case SlotLock(txn, _) => txn.asInstanceOf[T]
      case txn => txn.asInstanceOf[T]
    }
  }

  /** A non-racy version of `lookup`, that must be paired with
   *  `endLookup`.
   */
  def beginLookup(slot: Int): T = {
    var e: AnyRef = null
    while ({
      e = slots.get(slot)

      e != null && !slots.compareAndSet(slot, e, locked(e))
    }) ()

    unwrap(e)
  }

  private def locked(e: AnyRef): AnyRef = {
    e match {
      case SlotLock(txn, rc) => SlotLock(txn, rc + 1)
      case txn => SlotLock(txn, 1)
    }
  }

  def endLookup(slot: Int, observed: T): Unit =
    if (null != observed) release(slot)

  def release(slot: Int): Unit = {
    var e: AnyRef = null
    while ({
      e = slots.get(slot)

      !slots.compareAndSet(slot, e, unlocked(e))
    }) ()
  }

  private def unlocked(e: AnyRef): AnyRef = {
    e match {
      case SlotLock(txn, 1) => txn
      case SlotLock(txn, rc) => SlotLock(txn, rc - 1)
      case _ => null
    }
  }

  //  def assertAllReleased() {
  //    for (i <- 0 until range) {
  //      val e = slots.get(i)
  //      if (null != e) {
  //        assert(false, i + " -> " + e)
  //      }
  //    }
  //  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy