1 /*
   2  * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 6207928 6328220 6378321 6625723
  27  * @summary Recursive lock invariant sanity checks
  28  * @library /lib/testlibrary/
  29  * @author Martin Buchholz
  30  */
  31 
  32 import static java.util.concurrent.TimeUnit.MILLISECONDS;
  33 
  34 import java.io.ByteArrayInputStream;
  35 import java.io.ByteArrayOutputStream;
  36 import java.io.IOException;
  37 import java.io.InputStream;
  38 import java.io.ObjectInputStream;
  39 import java.io.ObjectOutputStream;
  40 import java.util.Random;
  41 import java.util.concurrent.CyclicBarrier;
  42 import java.util.concurrent.ExecutorService;
  43 import java.util.concurrent.Executors;
  44 import java.util.concurrent.TimeUnit;
  45 import java.util.concurrent.locks.Lock;
  46 import java.util.concurrent.locks.ReentrantLock;
  47 import java.util.concurrent.locks.ReentrantReadWriteLock;
  48 import jdk.testlibrary.Utils;
  49 
  50 // I am the Cownt, and I lahve to cownt.
  51 public class Count {
  52     static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
  53     final Random rnd = new Random();
  54 
  55     void lock(Lock lock) {
  56         try {
  57             switch (rnd.nextInt(4)) {
  58             case 0: lock.lock(); break;
  59             case 1: lock.lockInterruptibly(); break;
  60             case 2: check(lock.tryLock()); break;
  61             case 3: check(lock.tryLock(45, TimeUnit.MINUTES)); break;
  62             }
  63         } catch (Throwable t) { unexpected(t); }
  64     }
  65 
  66     void test(String[] args) throws Throwable {
  67         for (boolean fair : new boolean[] { true, false })
  68             for (boolean serialClone : new boolean[] { true, false }) {
  69                 testReentrantLocks(fair, serialClone);
  70                 testConcurrentReadLocks(fair, serialClone);
  71             }
  72     }
  73 
  74     void testConcurrentReadLocks(final boolean fair,
  75                                  final boolean serialClone) throws Throwable {
  76         final int nThreads = 10;
  77         final CyclicBarrier barrier = new CyclicBarrier(nThreads);
  78         final ExecutorService es = Executors.newFixedThreadPool(nThreads);
  79         final ReentrantReadWriteLock rwl = serialClone ?
  80             serialClone(new ReentrantReadWriteLock(fair)) :
  81             new ReentrantReadWriteLock(fair);
  82         for (int i = 0; i < nThreads; i++) {
  83             es.submit(new Runnable() { public void run() {
  84                 try {
  85                     int n = 5;
  86                     for (int i = 0; i < n; i++) {
  87                         barrier.await();
  88                         equal(rwl.getReadHoldCount(), i);
  89                         equal(rwl.getWriteHoldCount(), 0);
  90                         check(! rwl.isWriteLocked());
  91                         equal(rwl.getReadLockCount(), nThreads * i);
  92                         barrier.await();
  93                         lock(rwl.readLock());
  94                     }
  95                     for (int i = 0; i < n; i++) {
  96                         rwl.readLock().unlock();
  97                         barrier.await();
  98                         equal(rwl.getReadHoldCount(), n-i-1);
  99                         equal(rwl.getReadLockCount(), nThreads*(n-i-1));
 100                         equal(rwl.getWriteHoldCount(), 0);
 101                         check(! rwl.isWriteLocked());
 102                         barrier.await();
 103                     }
 104                     THROWS(IllegalMonitorStateException.class,
 105                            new F(){void f(){rwl.readLock().unlock();}},
 106                            new F(){void f(){rwl.writeLock().unlock();}});
 107                     barrier.await();
 108                 } catch (Throwable t) { unexpected(t); }}});}
 109         es.shutdown();
 110         check(es.awaitTermination(LONG_DELAY_MS, MILLISECONDS));
 111     }
 112 
 113     void testReentrantLocks(final boolean fair,
 114                             final boolean serialClone) throws Throwable {
 115         final ReentrantLock rl = serialClone ?
 116             serialClone(new ReentrantLock(fair)) :
 117             new ReentrantLock(fair);
 118         final ReentrantReadWriteLock rwl = serialClone ?
 119             serialClone(new ReentrantReadWriteLock(fair)) :
 120             new ReentrantReadWriteLock(fair);
 121         final int depth = 10;
 122         equal(rl.isFair(), fair);
 123         equal(rwl.isFair(), fair);
 124         check(! rl.isLocked());
 125         check(! rwl.isWriteLocked());
 126         check(! rl.isHeldByCurrentThread());
 127         check(! rwl.isWriteLockedByCurrentThread());
 128         check(! rwl.writeLock().isHeldByCurrentThread());
 129 
 130         for (int i = 0; i < depth; i++) {
 131             equal(rl.getHoldCount(), i);
 132             equal(rwl.getReadLockCount(), i);
 133             equal(rwl.getReadHoldCount(), i);
 134             equal(rwl.getWriteHoldCount(), i);
 135             equal(rwl.writeLock().getHoldCount(), i);
 136             equal(rl.isLocked(), i > 0);
 137             equal(rwl.isWriteLocked(), i > 0);
 138             lock(rl);
 139             lock(rwl.writeLock());
 140             lock(rwl.readLock());
 141         }
 142 
 143         for (int i = depth; i > 0; i--) {
 144             check(! rl.hasQueuedThreads());
 145             check(! rwl.hasQueuedThreads());
 146             check(! rl.hasQueuedThread(Thread.currentThread()));
 147             check(! rwl.hasQueuedThread(Thread.currentThread()));
 148             check(rl.isLocked());
 149             check(rwl.isWriteLocked());
 150             check(rl.isHeldByCurrentThread());
 151             check(rwl.isWriteLockedByCurrentThread());
 152             check(rwl.writeLock().isHeldByCurrentThread());
 153             equal(rl.getQueueLength(), 0);
 154             equal(rwl.getQueueLength(), 0);
 155             equal(rwl.getReadLockCount(), i);
 156             equal(rl.getHoldCount(), i);
 157             equal(rwl.getReadHoldCount(), i);
 158             equal(rwl.getWriteHoldCount(), i);
 159             equal(rwl.writeLock().getHoldCount(), i);
 160             rwl.readLock().unlock();
 161             rwl.writeLock().unlock();
 162             rl.unlock();
 163         }
 164         THROWS(IllegalMonitorStateException.class,
 165                new F(){void f(){rl.unlock();}},
 166                new F(){void f(){rwl.readLock().unlock();}},
 167                new F(){void f(){rwl.writeLock().unlock();}});
 168     }
 169 
 170     //--------------------- Infrastructure ---------------------------
 171     volatile int passed = 0, failed = 0;
 172     void pass() {passed++;}
 173     void fail() {failed++; Thread.dumpStack();}
 174     void fail(String msg) {System.err.println(msg); fail();}
 175     void unexpected(Throwable t) {failed++; t.printStackTrace();}
 176     void check(boolean cond) {if (cond) pass(); else fail();}
 177     void equal(Object x, Object y) {
 178         if (x == null ? y == null : x.equals(y)) pass();
 179         else fail(x + " not equal to " + y);}
 180     public static void main(String[] args) throws Throwable {
 181         new Count().instanceMain(args);}
 182     void instanceMain(String[] args) throws Throwable {
 183         try {test(args);} catch (Throwable t) {unexpected(t);}
 184         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
 185         if (failed > 0) throw new AssertionError("Some tests failed");}
 186     abstract class F {abstract void f() throws Throwable;}
 187     void THROWS(Class<? extends Throwable> k, F... fs) {
 188         for (F f : fs)
 189             try {f.f(); fail("Expected " + k.getName() + " not thrown");}
 190             catch (Throwable t) {
 191                 if (k.isAssignableFrom(t.getClass())) pass();
 192                 else unexpected(t);}}
 193 
 194     static byte[] serializedForm(Object obj) {
 195         try {
 196             ByteArrayOutputStream baos = new ByteArrayOutputStream();
 197             new ObjectOutputStream(baos).writeObject(obj);
 198             return baos.toByteArray();
 199         } catch (IOException e) { throw new RuntimeException(e); }}
 200     static Object readObject(byte[] bytes)
 201         throws IOException, ClassNotFoundException {
 202         InputStream is = new ByteArrayInputStream(bytes);
 203         return new ObjectInputStream(is).readObject();}
 204     @SuppressWarnings("unchecked")
 205     static <T> T serialClone(T obj) {
 206         try { return (T) readObject(serializedForm(obj)); }
 207         catch (Exception e) { throw new RuntimeException(e); }}
 208 }