1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  */
  22 
  23 /*
  24  * This file is available under and governed by the GNU General Public
  25  * License version 2 only, as published by the Free Software Foundation.
  26  * However, the following notice accompanied the original version of this
  27  * file:
  28  *
  29  * Written by Doug Lea with assistance from members of JCP JSR-166
  30  * Expert Group and released to the public domain, as explained at
  31  * http://creativecommons.org/publicdomain/zero/1.0/
  32  */
  33 
  34 /*
  35  * @test
  36  * @bug 4486658
  37  * @summary basic safety and liveness of ReentrantLocks, and other locks based on them
  38  * @library /test/lib
  39  */
  40 
  41 import static java.util.concurrent.TimeUnit.MILLISECONDS;
  42 
  43 import java.util.concurrent.CyclicBarrier;
  44 import java.util.concurrent.ExecutorService;
  45 import java.util.concurrent.Executors;
  46 import java.util.concurrent.Semaphore;
  47 import java.util.concurrent.ThreadLocalRandom;
  48 import java.util.concurrent.locks.Lock;
  49 import java.util.concurrent.locks.ReentrantLock;
  50 import java.util.concurrent.locks.ReentrantReadWriteLock;
  51 import jdk.test.lib.Utils;
  52 
  53 public final class CheckedLockLoops {
  54     static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
  55     static ExecutorService pool;
  56 
  57     public static void main(String[] args) throws Exception {
  58         final int maxThreads = (args.length > 0)
  59             ? Integer.parseInt(args[0])
  60             : 5;
  61         int iters = 3000;
  62 
  63         pool = Executors.newCachedThreadPool();
  64         for (int i = 1; i <= maxThreads; i += (i+1) >>> 1) {
  65             oneTest(i, iters / i);
  66         }
  67         pool.shutdown();
  68         if (! pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS))
  69             throw new Error();
  70         pool = null;
  71     }
  72 
  73     static void oneTest(int nthreads, int iters) throws Exception {
  74         System.out.println("Threads: " + nthreads);
  75         int v = ThreadLocalRandom.current().nextInt();
  76         System.out.print("builtin lock          ");
  77         new BuiltinLockLoop().test(v, nthreads, iters);
  78 
  79         System.out.print("ReentrantLock         ");
  80         new ReentrantLockLoop().test(v, nthreads, iters);
  81 
  82         System.out.print("Mutex                 ");
  83         new MutexLoop().test(v, nthreads, iters);
  84 
  85         System.out.print("ReentrantWriteLock    ");
  86         new ReentrantWriteLockLoop().test(v, nthreads, iters);
  87 
  88         System.out.print("ReentrantReadWriteLock");
  89         new ReentrantReadWriteLockLoop().test(v, nthreads, iters);
  90 
  91         System.out.print("Semaphore             ");
  92         new SemaphoreLoop().test(v, nthreads, iters);
  93 
  94         System.out.print("fair Semaphore        ");
  95         new FairSemaphoreLoop().test(v, nthreads, iters);
  96 
  97         System.out.print("FairReentrantLock     ");
  98         new FairReentrantLockLoop().test(v, nthreads, iters);
  99 
 100         System.out.print("FairRWriteLock         ");
 101         new FairReentrantWriteLockLoop().test(v, nthreads, iters);
 102 
 103         System.out.print("FairRReadWriteLock     ");
 104         new FairReentrantReadWriteLockLoop().test(v, nthreads, iters);
 105     }
 106 
 107     abstract static class LockLoop implements Runnable {
 108         int value;
 109         int checkValue;
 110         int iters;
 111         volatile int result;
 112         final LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
 113         CyclicBarrier barrier;
 114 
 115         final int setValue(int v) {
 116             checkValue = v ^ 0x55555555;
 117             value = v;
 118             return v;
 119         }
 120 
 121         final int getValue() {
 122             int v = value;
 123             if (checkValue != ~(v ^ 0xAAAAAAAA))
 124                 throw new Error("lock protection failure");
 125             return v;
 126         }
 127 
 128         final void test(int initialValue, int nthreads, int iters) throws Exception {
 129             setValue(initialValue);
 130             this.iters = iters;
 131             barrier = new CyclicBarrier(nthreads+1, timer);
 132             for (int i = 0; i < nthreads; ++i)
 133                 pool.execute(this);
 134             barrier.await();
 135             barrier.await();
 136             long time = timer.getTime();
 137             long tpi = time / (iters * nthreads);
 138             System.out.print("\t" + LoopHelpers.rightJustify(tpi) + " ns per update");
 139             //                double secs = (double)(time) / 1000000000.0;
 140             //                System.out.print("\t " + secs + "s run time");
 141             System.out.println();
 142 
 143             if (result == 0) // avoid overoptimization
 144                 System.out.println("useless result: " + result);
 145         }
 146         abstract int loop(int n);
 147         public final void run() {
 148             try {
 149                 barrier.await();
 150                 result += loop(iters);
 151                 barrier.await();
 152             }
 153             catch (Exception ex) {
 154                 return;
 155             }
 156         }
 157 
 158     }
 159 
 160     private static class BuiltinLockLoop extends LockLoop {
 161         final int loop(int n) {
 162             int sum = 0;
 163             int x = 0;
 164             while (n-- > 0) {
 165                 synchronized (this) {
 166                     x = setValue(LoopHelpers.compute1(getValue()));
 167                 }
 168                 sum += LoopHelpers.compute2(x);
 169             }
 170             return sum;
 171         }
 172     }
 173 
 174     private static class ReentrantLockLoop extends LockLoop {
 175         private final ReentrantLock lock = new ReentrantLock();
 176         final int loop(int n) {
 177             final ReentrantLock lock = this.lock;
 178             int sum = 0;
 179             int x = 0;
 180             while (n-- > 0) {
 181                 lock.lock();
 182                 try {
 183                     x = setValue(LoopHelpers.compute1(getValue()));
 184                 }
 185                 finally {
 186                     lock.unlock();
 187                 }
 188                 sum += LoopHelpers.compute2(x);
 189             }
 190             return sum;
 191         }
 192     }
 193 
 194     private static class MutexLoop extends LockLoop {
 195         private final Mutex lock = new Mutex();
 196         final int loop(int n) {
 197             final Mutex lock = this.lock;
 198             int sum = 0;
 199             int x = 0;
 200             while (n-- > 0) {
 201                 lock.lock();
 202                 try {
 203                     x = setValue(LoopHelpers.compute1(getValue()));
 204                 }
 205                 finally {
 206                     lock.unlock();
 207                 }
 208                 sum += LoopHelpers.compute2(x);
 209             }
 210             return sum;
 211         }
 212     }
 213 
 214     private static class FairReentrantLockLoop extends LockLoop {
 215         private final ReentrantLock lock = new ReentrantLock(true);
 216         final int loop(int n) {
 217             final ReentrantLock lock = this.lock;
 218             int sum = 0;
 219             int x = 0;
 220             while (n-- > 0) {
 221                 lock.lock();
 222                 try {
 223                     x = setValue(LoopHelpers.compute1(getValue()));
 224                 }
 225                 finally {
 226                     lock.unlock();
 227                 }
 228                 sum += LoopHelpers.compute2(x);
 229             }
 230             return sum;
 231         }
 232     }
 233 
 234     private static class ReentrantWriteLockLoop extends LockLoop {
 235         private final Lock lock = new ReentrantReadWriteLock().writeLock();
 236         final int loop(int n) {
 237             final Lock lock = this.lock;
 238             int sum = 0;
 239             int x = 0;
 240             while (n-- > 0) {
 241                 lock.lock();
 242                 try {
 243                     x = setValue(LoopHelpers.compute1(getValue()));
 244                 }
 245                 finally {
 246                     lock.unlock();
 247                 }
 248                 sum += LoopHelpers.compute2(x);
 249             }
 250             return sum;
 251         }
 252     }
 253 
 254     private static class FairReentrantWriteLockLoop extends LockLoop {
 255         final Lock lock = new ReentrantReadWriteLock(true).writeLock();
 256         final int loop(int n) {
 257             final Lock lock = this.lock;
 258             int sum = 0;
 259             int x = 0;
 260             while (n-- > 0) {
 261                 lock.lock();
 262                 try {
 263                     x = setValue(LoopHelpers.compute1(getValue()));
 264                 }
 265                 finally {
 266                     lock.unlock();
 267                 }
 268                 sum += LoopHelpers.compute2(x);
 269             }
 270             return sum;
 271         }
 272     }
 273 
 274     private static class SemaphoreLoop extends LockLoop {
 275         private final Semaphore sem = new Semaphore(1, false);
 276         final int loop(int n) {
 277             final Semaphore sem = this.sem;
 278             int sum = 0;
 279             int x = 0;
 280             while (n-- > 0) {
 281                 sem.acquireUninterruptibly();
 282                 try {
 283                     x = setValue(LoopHelpers.compute1(getValue()));
 284                 }
 285                 finally {
 286                     sem.release();
 287                 }
 288                 sum += LoopHelpers.compute2(x);
 289             }
 290             return sum;
 291         }
 292     }
 293 
 294     private static class FairSemaphoreLoop extends LockLoop {
 295         private final Semaphore sem = new Semaphore(1, true);
 296         final int loop(int n) {
 297             final Semaphore sem = this.sem;
 298             int sum = 0;
 299             int x = 0;
 300             while (n-- > 0) {
 301                 sem.acquireUninterruptibly();
 302                 try {
 303                     x = setValue(LoopHelpers.compute1(getValue()));
 304                 }
 305                 finally {
 306                     sem.release();
 307                 }
 308                 sum += LoopHelpers.compute2(x);
 309             }
 310             return sum;
 311         }
 312     }
 313 
 314     private static class ReentrantReadWriteLockLoop extends LockLoop {
 315         private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
 316         final int loop(int n) {
 317             final Lock rlock = lock.readLock();
 318             final Lock wlock = lock.writeLock();
 319             int sum = 0;
 320             int x = 0;
 321             while (n-- > 0) {
 322                 if ((n & 16) != 0) {
 323                     rlock.lock();
 324                     try {
 325                         x = LoopHelpers.compute1(getValue());
 326                         x = LoopHelpers.compute2(x);
 327                     }
 328                     finally {
 329                         rlock.unlock();
 330                     }
 331                 }
 332                 else {
 333                     wlock.lock();
 334                     try {
 335                         setValue(x);
 336                     }
 337                     finally {
 338                         wlock.unlock();
 339                     }
 340                     sum += LoopHelpers.compute2(x);
 341                 }
 342             }
 343             return sum;
 344         }
 345     }
 346 
 347     private static class FairReentrantReadWriteLockLoop extends LockLoop {
 348         private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
 349         final int loop(int n) {
 350             final Lock rlock = lock.readLock();
 351             final Lock wlock = lock.writeLock();
 352             int sum = 0;
 353             int x = 0;
 354             while (n-- > 0) {
 355                 if ((n & 16) != 0) {
 356                     rlock.lock();
 357                     try {
 358                         x = LoopHelpers.compute1(getValue());
 359                         x = LoopHelpers.compute2(x);
 360                     }
 361                     finally {
 362                         rlock.unlock();
 363                     }
 364                 }
 365                 else {
 366                     wlock.lock();
 367                     try {
 368                         setValue(x);
 369                     }
 370                     finally {
 371                         wlock.unlock();
 372                     }
 373                     sum += LoopHelpers.compute2(x);
 374                 }
 375             }
 376             return sum;
 377         }
 378     }
 379 }