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 /lib/testlibrary/
39 */
40
41import static java.util.concurrent.TimeUnit.MILLISECONDS;
42
43import java.util.concurrent.CyclicBarrier;
44import java.util.concurrent.ExecutorService;
45import java.util.concurrent.Executors;
46import java.util.concurrent.Semaphore;
47import java.util.concurrent.ThreadLocalRandom;
48import java.util.concurrent.locks.Lock;
49import java.util.concurrent.locks.ReentrantLock;
50import java.util.concurrent.locks.ReentrantReadWriteLock;
51import jdk.testlibrary.Utils;
52
53public 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}
380