00001
00016 module mango.locks.ReentrantLock;
00017
00018 import mango.locks.Lock;
00019
00020 private {
00021 import std.thread;
00022
00023 import mango.sys.Atomic;
00024
00025 import mango.locks.Utils;
00026 import mango.locks.LockImpl;
00027 import mango.locks.Exceptions;
00028 }
00029
00089 class ReentrantLock : Lock {
00090
00092 private final Sync sync;
00093
00094
00095
00096
00097
00098
00099 abstract class Sync : AbstractLock {
00100
00101 Thread owner;
00102
00103
00104
00105
00106
00107 abstract void lock();
00108
00109
00110
00111
00112
00113
00114 final bool nonfairTryAcquire(int acquires) {
00115 Thread current = Thread.getThis();
00116 int c = state;
00117 if (c == 0) {
00118 if (Atomic.compareAndSet32(&state_, c, acquires)) {
00119 owner = current;
00120 return true;
00121 }
00122 }
00123 else if (current is owner) {
00124 state = c+acquires;
00125 return true;
00126 }
00127 return false;
00128 }
00129
00130 final bool tryRelease(int releases) {
00131 if (Thread.getThis() !is owner)
00132 throw new IllegalArgumentException();
00133 int c = state - releases;
00134 bool free = false;
00135 if (c == 0) {
00136 free = true;
00137 owner = null;
00138 }
00139 state = c;
00140 return free;
00141 }
00142
00143 final bool isHeldExclusively() {
00144 return state != 0 && owner is Thread.getThis();
00145 }
00146
00147 final ConditionObject newCondition() {
00148 return new ConditionObject(this);
00149 }
00150
00151
00152
00153 final Thread getOwner() {
00154 int c = state;
00155 Thread o = owner;
00156 return (c == 0)? null : o;
00157 }
00158
00159 final int getHoldCount() {
00160 int c = state;
00161 Thread o = owner;
00162 return (o is Thread.getThis())? c : 0;
00163 }
00164
00165 final bool isLocked() {
00166 return state != 0;
00167 }
00168 }
00169
00170
00171
00172
00173 final class NonfairSync : Sync {
00174
00175
00176
00177
00178 final void lock() {
00179 if (Atomic.compareAndSet32(&state_, 0, 1))
00180 owner = Thread.getThis();
00181 else {
00182 acquire(1);
00183 }
00184 }
00185
00186 protected final bool tryAcquire(int acquires) {
00187 return nonfairTryAcquire(acquires);
00188 }
00189 }
00190
00191
00192
00193
00194 final class FairSync : Sync {
00195 final void lock() {
00196 acquire(1);
00197 }
00198
00199
00200
00201
00202
00203 protected final bool tryAcquire(int acquires) {
00204 Thread current = Thread.getThis();
00205 int c = state;
00206 if (c == 0) {
00207 Thread first = getFirstQueuedThread();
00208 if ((first is null || first is current) &&
00209 Atomic.compareAndSet32(&state_, c, acquires)) {
00210 owner = current;
00211 return true;
00212 }
00213 }
00214 else if (current is owner) {
00215 state = c+acquires;
00216 return true;
00217 }
00218 return false;
00219 }
00220 }
00221
00227 this(bool fair = false) {
00228 if (fair)
00229 sync = new FairSync();
00230 else
00231 sync = new NonfairSync();
00232 }
00233
00248 void lock() {
00249 sync.lock();
00250 }
00251
00275 bool tryLock() {
00276 return sync.nonfairTryAcquire(1);
00277 }
00278
00321 bool tryLock(long timeout, TimeUnit unit) {
00322 return sync.tryAcquireNanos(1, toNanos(timeout,unit));
00323 }
00324
00332 void unlock() {
00333 sync.release(1);
00334 }
00335
00356 Condition newCondition() {
00357 return sync.newCondition();
00358 }
00359
00393 int getHoldCount() {
00394 return sync.getHoldCount();
00395 }
00396
00404 bool isHeldByCurrentThread() {
00405 return sync.isHeldExclusively();
00406 }
00407
00415 bool isLocked() {
00416 return sync.isLocked();
00417 }
00418
00423 final bool isFair() {
00424 return cast(FairSync)sync !is null;
00425 }
00426
00436 protected Thread getOwner() {
00437 return sync.getOwner();
00438 }
00439
00450 final bool hasQueuedThreads() {
00451 return sync.hasQueuedThreads();
00452 }
00453
00454
00465 final bool hasQueuedThread(Thread thread) {
00466 return sync.isQueued(thread);
00467 }
00468
00469
00479 final int getQueueLength() {
00480 return sync.getQueueLength();
00481 }
00482
00493 protected Thread[] getQueuedThreads() {
00494 return sync.getQueuedThreads();
00495 }
00496
00507 bool hasWaiters(Condition condition) {
00508 if ((condition is null) ||
00509 (cast(AbstractLock.ConditionObject)condition is null))
00510 throw new IllegalArgumentException();
00511 return sync.hasWaiters(cast(AbstractLock.ConditionObject)condition);
00512 }
00513
00524 int getWaitQueueLength(Condition condition) {
00525 if ((condition is null) ||
00526 (cast(AbstractLock.ConditionObject)condition is null))
00527 throw new IllegalArgumentException();
00528 return sync.getWaitQueueLength(cast(AbstractLock.ConditionObject)condition);
00529 }
00530
00543 protected Thread[] getWaitingThreads(Condition condition) {
00544 if ((condition is null) ||
00545 (cast(AbstractLock.ConditionObject)condition is null))
00546 throw new IllegalArgumentException();
00547 return sync.getWaitingThreads(cast(AbstractLock.ConditionObject)condition);
00548 }
00549
00557 char[] toString() {
00558 Thread owner = sync.getOwner();
00559 return super.toString() ~ ((owner is null) ?
00560 "[Unlocked]" :
00561 ("[Locked by thread" ~ owner.toString() ~ "]"));
00562 }
00563
00564 unittest {
00565 ReentrantLock lock;
00566 int acquired;
00567 Thread[] t;
00568
00569 ThreadReturn f() {
00570 int n;
00571 Thread tt = Thread.getThis();
00572 for (n=0; n < t.length; n++) {
00573 if (tt is t[n])
00574 break;
00575 }
00576 version (LocksVerboseUnittest)
00577 printf(" thread %d started\n",n);
00578 lock.lock();
00579 version (LocksVerboseUnittest)
00580 printf(" thread %d aquired\n",n);
00581 for (int k=0;k<1000;k++)
00582 Thread.yield();
00583 lock.unlock();
00584 acquired++;
00585 version (LocksVerboseUnittest)
00586 printf(" thread %d released\n",n);
00587 return 0;
00588 }
00589
00590 lock = new ReentrantLock;
00591 acquired = 0;
00592 t = new Thread[3];
00593 int n;
00594 for (n=0; n<t.length; n++) {
00595 t[n] = new Thread(&f);
00596 }
00597 version (LocksVerboseUnittest)
00598 printf("starting locks.reentrantlock unittest\n");
00599 for (n=0; n<t.length; n++) {
00600 t[n].start();
00601 }
00602 while (acquired != n)
00603 Thread.yield();
00604
00605
00606
00607 {
00608 auto ScopedLock sl = new ScopedLock(lock);
00609 assert( lock.isHeldByCurrentThread );
00610
00611 }
00612 assert( ~lock.isHeldByCurrentThread );
00613
00614 version (LocksVerboseUnittest)
00615 printf("finished locks.reentrantlock unittest\n");
00616 }
00617 }