[jboss-remoting-commits] JBoss Remoting SVN: r3727 - remoting3/trunk/util/src/main/java/org/jboss/cx/remoting/util.
jboss-remoting-commits at lists.jboss.org
jboss-remoting-commits at lists.jboss.org
Fri Mar 21 18:06:51 EDT 2008
Author: david.lloyd at jboss.com
Date: 2008-03-21 18:06:51 -0400 (Fri, 21 Mar 2008)
New Revision: 3727
Added:
remoting3/trunk/util/src/main/java/org/jboss/cx/remoting/util/StateLock.java
Log:
New type of lock
Added: remoting3/trunk/util/src/main/java/org/jboss/cx/remoting/util/StateLock.java
===================================================================
--- remoting3/trunk/util/src/main/java/org/jboss/cx/remoting/util/StateLock.java (rev 0)
+++ remoting3/trunk/util/src/main/java/org/jboss/cx/remoting/util/StateLock.java 2008-03-21 22:06:51 UTC (rev 3727)
@@ -0,0 +1,257 @@
+package org.jboss.cx.remoting.util;
+
+/**
+ * Lock rules:
+ *
+ * Shared acquire:
+ * - Unlocked
+ * or
+ * - Shared-locked
+ *
+ * Exclusive acquire:
+ * - Unlocked
+ * or
+ * - All previously waiting readers have had a chance to lock
+ */
+public final class StateLock {
+ private static final class ReaderToken {
+ private int count;
+
+ private ReaderToken(final int count) {
+ this.count = count;
+ }
+ }
+
+ private static final String LOCK_NOT_HELD = "Unlock when lock isn't held";
+
+ private final Object lock = new Object();
+ /**
+ * A counter for the readers that will be granted after the next exclusive lock is released.
+ *
+ * @protectedby {@code lock}
+ */
+ private ReaderToken nextReaderToken = new ReaderToken(0);
+ /**
+ * A counter for the readers that must be granted before an exclusive lock can be granted.
+ *
+ * @protectedby {@code lock}
+ */
+ private ReaderToken currentReaderToken = new ReaderToken(0);
+
+ // @protectedby {@code lock} (writes only)
+ private volatile int sharedHolderCount = 0;
+ // @protectedby {@code lock} (writes only)
+ private volatile boolean exclusive = false;
+
+ private final ThreadLocal<LockState> localLockState = new ThreadLocal<LockState>();
+
+ private void incLocalExclCount() {
+ final LockState lockState = localLockState.get();
+ if (lockState == null) {
+ localLockState.set(new LockState(1, 0));
+ } else {
+ lockState.exclLevel++;
+ }
+ }
+
+ private boolean decLocalExclCount() {
+ final LockState lockState = localLockState.get();
+ if (lockState == null || lockState.exclLevel == 0) {
+ throw new IllegalMonitorStateException(LOCK_NOT_HELD);
+ }
+ return --lockState.exclLevel == 0;
+ }
+
+ private int getLocalExclCount() {
+ final LockState lockState = localLockState.get();
+ if (lockState == null) {
+ return 0;
+ } else {
+ return lockState.exclLevel;
+ }
+ }
+
+ private void incLocalShrdCount() {
+ final LockState lockState = localLockState.get();
+ if (lockState == null) {
+ localLockState.set(new LockState(0, 1));
+ } else {
+ lockState.shrdLevel++;
+ }
+ }
+
+ private boolean decLocalShrdCount() {
+ final LockState lockState = localLockState.get();
+ if (lockState == null || lockState.shrdLevel == 0) {
+ throw new IllegalMonitorStateException(LOCK_NOT_HELD);
+ }
+ return --lockState.shrdLevel == 0;
+ }
+
+ private int getLocalShrdCount() {
+ final LockState lockState = localLockState.get();
+ if (lockState == null) {
+ return 0;
+ } else {
+ return lockState.shrdLevel;
+ }
+ }
+
+ public void lockExclusive() {
+ if (getLocalExclCount() > 0) {
+ incLocalExclCount();
+ return;
+ }
+ if (getLocalShrdCount() > 0) {
+ throw new IllegalMonitorStateException("Lock exclusive while shared lock is held");
+ }
+ synchronized (lock) {
+ boolean intr = false;
+ try {
+ while (exclusive || currentReaderToken.count > 0 || sharedHolderCount > 0) {
+ try {
+ lock.wait();
+ } catch (InterruptedException e) {
+ intr = true;
+ }
+ }
+ exclusive = true;
+ incLocalExclCount();
+ return;
+ } finally {
+ if (intr) Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public void unlockExclusive() {
+ if (! exclusive) {
+ throw new IllegalMonitorStateException(LOCK_NOT_HELD);
+ }
+ if (decLocalExclCount()) {
+ synchronized (lock) {
+ exclusive = false;
+ currentReaderToken = nextReaderToken;
+ nextReaderToken = new ReaderToken(0);
+ lock.notifyAll();
+ }
+ }
+ }
+
+ public void lockShared() {
+ if (getLocalShrdCount() > 0) {
+ incLocalShrdCount();
+ return;
+ }
+ synchronized (lock) {
+ boolean intr = false;
+ try {
+ final ReaderToken token = currentReaderToken;
+ if (exclusive) {
+ token.count++;
+ while (exclusive) {
+ try {
+ lock.wait();
+ } catch (InterruptedException e) {
+ intr = true;
+ }
+ }
+ token.count--;
+ }
+ sharedHolderCount++;
+ incLocalShrdCount();
+ return;
+ } finally {
+ if (intr) Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public void unlockShared() {
+ if (decLocalShrdCount()) {
+ synchronized (lock) {
+ if (--sharedHolderCount == 0) {
+ lock.notifyAll();
+ }
+ }
+ }
+ }
+
+ public void yieldShared() {
+ if (getLocalShrdCount() == 1 && getLocalExclCount() == 0) {
+ synchronized (lock) {
+ boolean intr = false;
+ try {
+ final ReaderToken token = nextReaderToken;
+ token.count++;
+ sharedHolderCount--;
+ while (! exclusive) {
+ try {
+ lock.wait();
+ } catch (InterruptedException e) {
+ intr = true;
+ }
+ }
+ while (exclusive) {
+ try {
+ lock.wait();
+ } catch (InterruptedException e) {
+ intr = true;
+ }
+ }
+ token.count--;
+ sharedHolderCount++;
+ } finally {
+ if (intr) Thread.currentThread().interrupt();
+ }
+ }
+ } else {
+ throw new IllegalMonitorStateException("May only hold one shared lock to invoke yieldShared()");
+ }
+ }
+
+ public void awaitExclusive() {
+ if (getLocalExclCount() == 0) {
+ throw new IllegalMonitorStateException("await() called when lock not held");
+ }
+ synchronized (lock) {
+ boolean intr = false;
+ try {
+ exclusive = false;
+ try {
+ lock.wait();
+ } catch (InterruptedException e) {
+ intr = true;
+ }
+ while (exclusive || currentReaderToken.count > 0 || sharedHolderCount > 0) {
+ try {
+ lock.wait();
+ } catch (InterruptedException e) {
+ intr = true;
+ }
+ }
+ exclusive = true;
+ incLocalExclCount();
+ return;
+ } finally {
+ if (intr) Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public void signal() {
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+
+ private static final class LockState {
+ private int exclLevel;
+ private int shrdLevel;
+
+ private LockState(final int exclLevel, final int shrdLevel) {
+ this.exclLevel = exclLevel;
+ this.shrdLevel = shrdLevel;
+ }
+ }
+}
More information about the jboss-remoting-commits
mailing list