/*
 * Written by Doug Lea and Martin Buchholz with assistance from
 * members of JCP JSR-166 Expert Group and released to the public
 * domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 * Other contributors include Andrew Wright, Jeffrey Hayes,
 * Pat Fisher, Mike Judd.
 */

package jsr166;

import static java.util.concurrent.TimeUnit.MILLISECONDS;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;

import junit.framework.Test;
import junit.framework.TestSuite;

public class LockSupportTest extends JSR166TestCase {
    // android-note: Removed because the CTS runner does a bad job of
    // retrying tests that have suite() declarations.
    //
    // public static void main(String[] args) {
    //     main(suite(), args);
    // }
    // public static Test suite() {
    //     return new TestSuite(...);
    // }

    /**
     * Returns the blocker object used by tests in this file.
     * Any old object will do; we'll return a convenient one.
     */
    static Object theBlocker() {
        return LockSupportTest.class;
    }

    enum ParkMethod {
        park() {
            void park() {
                LockSupport.park();
            }
            void park(long millis) {
                throw new UnsupportedOperationException();
            }
        },
        parkUntil() {
            void park(long millis) {
                LockSupport.parkUntil(deadline(millis));
            }
        },
        parkNanos() {
            void park(long millis) {
                LockSupport.parkNanos(MILLISECONDS.toNanos(millis));
            }
        },
        parkBlocker() {
            void park() {
                LockSupport.park(theBlocker());
            }
            void park(long millis) {
                throw new UnsupportedOperationException();
            }
        },
        parkUntilBlocker() {
            void park(long millis) {
                LockSupport.parkUntil(theBlocker(), deadline(millis));
            }
        },
        parkNanosBlocker() {
            void park(long millis) {
                LockSupport.parkNanos(theBlocker(),
                                      MILLISECONDS.toNanos(millis));
            }
        };

        void park() { park(2 * LONG_DELAY_MS); }
        abstract void park(long millis);

        /** Returns a deadline to use with parkUntil. */
        long deadline(long millis) {
            // beware of rounding
            return System.currentTimeMillis() + millis + 1;
        }
    }

    /**
     * park is released by subsequent unpark
     */
    public void testParkBeforeUnpark_park() {
        testParkBeforeUnpark(ParkMethod.park);
    }
    public void testParkBeforeUnpark_parkNanos() {
        testParkBeforeUnpark(ParkMethod.parkNanos);
    }
    public void testParkBeforeUnpark_parkUntil() {
        testParkBeforeUnpark(ParkMethod.parkUntil);
    }
    public void testParkBeforeUnpark_parkBlocker() {
        testParkBeforeUnpark(ParkMethod.parkBlocker);
    }
    public void testParkBeforeUnpark_parkNanosBlocker() {
        testParkBeforeUnpark(ParkMethod.parkNanosBlocker);
    }
    public void testParkBeforeUnpark_parkUntilBlocker() {
        testParkBeforeUnpark(ParkMethod.parkUntilBlocker);
    }
    public void testParkBeforeUnpark(final ParkMethod parkMethod) {
        final CountDownLatch pleaseUnpark = new CountDownLatch(1);
        Thread t = newStartedThread(new CheckedRunnable() {
            public void realRun() {
                pleaseUnpark.countDown();
                parkMethod.park();
            }});

        await(pleaseUnpark);
        LockSupport.unpark(t);
        awaitTermination(t);
    }

    /**
     * park is released by preceding unpark
     */
    public void testParkAfterUnpark_park() {
        testParkAfterUnpark(ParkMethod.park);
    }
    public void testParkAfterUnpark_parkNanos() {
        testParkAfterUnpark(ParkMethod.parkNanos);
    }
    public void testParkAfterUnpark_parkUntil() {
        testParkAfterUnpark(ParkMethod.parkUntil);
    }
    public void testParkAfterUnpark_parkBlocker() {
        testParkAfterUnpark(ParkMethod.parkBlocker);
    }
    public void testParkAfterUnpark_parkNanosBlocker() {
        testParkAfterUnpark(ParkMethod.parkNanosBlocker);
    }
    public void testParkAfterUnpark_parkUntilBlocker() {
        testParkAfterUnpark(ParkMethod.parkUntilBlocker);
    }
    public void testParkAfterUnpark(final ParkMethod parkMethod) {
        final CountDownLatch pleaseUnpark = new CountDownLatch(1);
        final AtomicBoolean pleasePark = new AtomicBoolean(false);
        Thread t = newStartedThread(new CheckedRunnable() {
            public void realRun() {
                pleaseUnpark.countDown();
                while (!pleasePark.get())
                    Thread.yield();
                parkMethod.park();
            }});

        await(pleaseUnpark);
        LockSupport.unpark(t);
        pleasePark.set(true);
        awaitTermination(t);
    }

    /**
     * park is released by subsequent interrupt
     */
    public void testParkBeforeInterrupt_park() {
        testParkBeforeInterrupt(ParkMethod.park);
    }
    public void testParkBeforeInterrupt_parkNanos() {
        testParkBeforeInterrupt(ParkMethod.parkNanos);
    }
    public void testParkBeforeInterrupt_parkUntil() {
        testParkBeforeInterrupt(ParkMethod.parkUntil);
    }
    public void testParkBeforeInterrupt_parkBlocker() {
        testParkBeforeInterrupt(ParkMethod.parkBlocker);
    }
    public void testParkBeforeInterrupt_parkNanosBlocker() {
        testParkBeforeInterrupt(ParkMethod.parkNanosBlocker);
    }
    public void testParkBeforeInterrupt_parkUntilBlocker() {
        testParkBeforeInterrupt(ParkMethod.parkUntilBlocker);
    }
    public void testParkBeforeInterrupt(final ParkMethod parkMethod) {
        final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
        Thread t = newStartedThread(new CheckedRunnable() {
            public void realRun() {
                pleaseInterrupt.countDown();
                do {
                    parkMethod.park();
                    // park may return spuriously
                } while (! Thread.currentThread().isInterrupted());
            }});

        await(pleaseInterrupt);
        assertThreadStaysAlive(t);
        t.interrupt();
        awaitTermination(t);
    }

    /**
     * park is released by preceding interrupt
     */
    public void testParkAfterInterrupt_park() {
        testParkAfterInterrupt(ParkMethod.park);
    }
    public void testParkAfterInterrupt_parkNanos() {
        testParkAfterInterrupt(ParkMethod.parkNanos);
    }
    public void testParkAfterInterrupt_parkUntil() {
        testParkAfterInterrupt(ParkMethod.parkUntil);
    }
    public void testParkAfterInterrupt_parkBlocker() {
        testParkAfterInterrupt(ParkMethod.parkBlocker);
    }
    public void testParkAfterInterrupt_parkNanosBlocker() {
        testParkAfterInterrupt(ParkMethod.parkNanosBlocker);
    }
    public void testParkAfterInterrupt_parkUntilBlocker() {
        testParkAfterInterrupt(ParkMethod.parkUntilBlocker);
    }
    public void testParkAfterInterrupt(final ParkMethod parkMethod) {
        final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
        final AtomicBoolean pleasePark = new AtomicBoolean(false);
        Thread t = newStartedThread(new CheckedRunnable() {
            public void realRun() throws Exception {
                pleaseInterrupt.countDown();
                while (!pleasePark.get())
                    Thread.yield();
                assertTrue(Thread.currentThread().isInterrupted());
                parkMethod.park();
                assertTrue(Thread.currentThread().isInterrupted());
            }});

        await(pleaseInterrupt);
        t.interrupt();
        pleasePark.set(true);
        awaitTermination(t);
    }

    /**
     * timed park times out if not unparked
     */
    public void testParkTimesOut_parkNanos() {
        testParkTimesOut(ParkMethod.parkNanos);
    }
    public void testParkTimesOut_parkUntil() {
        testParkTimesOut(ParkMethod.parkUntil);
    }
    public void testParkTimesOut_parkNanosBlocker() {
        testParkTimesOut(ParkMethod.parkNanosBlocker);
    }
    public void testParkTimesOut_parkUntilBlocker() {
        testParkTimesOut(ParkMethod.parkUntilBlocker);
    }
    public void testParkTimesOut(final ParkMethod parkMethod) {
        Thread t = newStartedThread(new CheckedRunnable() {
            public void realRun() {
                for (;;) {
                    long startTime = System.nanoTime();
                    parkMethod.park(timeoutMillis());
                    // park may return spuriously
                    if (millisElapsedSince(startTime) >= timeoutMillis())
                        return;
                }
            }});

        awaitTermination(t);
    }

    /**
     * getBlocker(null) throws NullPointerException
     */
    public void testGetBlockerNull() {
        try {
            LockSupport.getBlocker(null);
            shouldThrow();
        } catch (NullPointerException success) {}
    }

    /**
     * getBlocker returns the blocker object passed to park
     */
    public void testGetBlocker_parkBlocker() {
        testGetBlocker(ParkMethod.parkBlocker);
    }
    public void testGetBlocker_parkNanosBlocker() {
        testGetBlocker(ParkMethod.parkNanosBlocker);
    }
    public void testGetBlocker_parkUntilBlocker() {
        testGetBlocker(ParkMethod.parkUntilBlocker);
    }
    public void testGetBlocker(final ParkMethod parkMethod) {
        final CountDownLatch started = new CountDownLatch(1);
        Thread t = newStartedThread(new CheckedRunnable() {
            public void realRun() {
                Thread t = Thread.currentThread();
                started.countDown();
                do {
                    assertNull(LockSupport.getBlocker(t));
                    parkMethod.park();
                    assertNull(LockSupport.getBlocker(t));
                    // park may return spuriously
                } while (! Thread.currentThread().isInterrupted());
            }});

        long startTime = System.nanoTime();
        await(started);
        for (;;) {
            Object x = LockSupport.getBlocker(t);
            if (x == theBlocker()) { // success
                t.interrupt();
                awaitTermination(t);
                assertNull(LockSupport.getBlocker(t));
                return;
            } else {
                assertNull(x);  // ok
                if (millisElapsedSince(startTime) > LONG_DELAY_MS)
                    fail("timed out");
                Thread.yield();
            }
        }
    }

    /**
     * timed park(0) returns immediately.
     *
     * Requires hotspot fix for:
     * 6763959 java.util.concurrent.locks.LockSupport.parkUntil(0) blocks forever
     * which is in jdk7-b118 and 6u25.
     */
    public void testPark0_parkNanos() {
        testPark0(ParkMethod.parkNanos);
    }
    public void testPark0_parkUntil() {
        testPark0(ParkMethod.parkUntil);
    }
    public void testPark0_parkNanosBlocker() {
        testPark0(ParkMethod.parkNanosBlocker);
    }
    public void testPark0_parkUntilBlocker() {
        testPark0(ParkMethod.parkUntilBlocker);
    }
    public void testPark0(final ParkMethod parkMethod) {
        Thread t = newStartedThread(new CheckedRunnable() {
            public void realRun() {
                parkMethod.park(0L);
            }});

        awaitTermination(t);
    }

    /**
     * timed park(Long.MIN_VALUE) returns immediately.
     */
    public void testParkNeg_parkNanos() {
        testParkNeg(ParkMethod.parkNanos);
    }
    public void testParkNeg_parkUntil() {
        testParkNeg(ParkMethod.parkUntil);
    }
    public void testParkNeg_parkNanosBlocker() {
        testParkNeg(ParkMethod.parkNanosBlocker);
    }
    public void testParkNeg_parkUntilBlocker() {
        testParkNeg(ParkMethod.parkUntilBlocker);
    }
    public void testParkNeg(final ParkMethod parkMethod) {
        Thread t = newStartedThread(new CheckedRunnable() {
            public void realRun() {
                parkMethod.park(Long.MIN_VALUE);
            }});

        awaitTermination(t);
    }
}
