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 6725789
  37  * @summary Check for long overflow in task time comparison.
  38  * @library /test/lib
  39  */
  40 
  41 import static java.util.concurrent.TimeUnit.DAYS;
  42 import static java.util.concurrent.TimeUnit.MILLISECONDS;
  43 import static java.util.concurrent.TimeUnit.NANOSECONDS;
  44 
  45 import java.util.concurrent.CountDownLatch;
  46 import java.util.concurrent.Executors;
  47 import java.util.concurrent.ScheduledThreadPoolExecutor;
  48 import jdk.test.lib.Utils;
  49 
  50 public class DelayOverflow {
  51     static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
  52 
  53     static void waitForNanoTimeTick() {
  54         for (long t0 = System.nanoTime(); t0 == System.nanoTime(); )
  55             ;
  56     }
  57 
  58     void scheduleNow(ScheduledThreadPoolExecutor pool,
  59                      Runnable r, int how) {
  60         switch (how) {
  61         case 0:
  62             pool.schedule(r, 0, MILLISECONDS);
  63             break;
  64         case 1:
  65             pool.schedule(Executors.callable(r), 0, DAYS);
  66             break;
  67         case 2:
  68             pool.scheduleWithFixedDelay(r, 0, 1000, NANOSECONDS);
  69             break;
  70         case 3:
  71             pool.scheduleAtFixedRate(r, 0, 1000, MILLISECONDS);
  72             break;
  73         default:
  74             fail(String.valueOf(how));
  75         }
  76     }
  77 
  78     void scheduleAtTheEndOfTime(ScheduledThreadPoolExecutor pool,
  79                                 Runnable r, int how) {
  80         switch (how) {
  81         case 0:
  82             pool.schedule(r, Long.MAX_VALUE, MILLISECONDS);
  83             break;
  84         case 1:
  85             pool.schedule(Executors.callable(r), Long.MAX_VALUE, DAYS);
  86             break;
  87         case 2:
  88             pool.scheduleWithFixedDelay(r, Long.MAX_VALUE, 1000, NANOSECONDS);
  89             break;
  90         case 3:
  91             pool.scheduleAtFixedRate(r, Long.MAX_VALUE, 1000, MILLISECONDS);
  92             break;
  93         default:
  94             fail(String.valueOf(how));
  95         }
  96     }
  97 
  98     /**
  99      * Attempts to test exhaustively and deterministically, all 20
 100      * possible ways that one task can be scheduled in the maximal
 101      * distant future, while at the same time an existing task's time
 102      * has already expired.
 103      */
 104     void test(String[] args) throws Throwable {
 105         for (int nowHow = 0; nowHow < 4; nowHow++) {
 106             for (int thenHow = 0; thenHow < 4; thenHow++) {
 107 
 108                 final ScheduledThreadPoolExecutor pool
 109                     = new ScheduledThreadPoolExecutor(1);
 110                 final CountDownLatch runLatch     = new CountDownLatch(1);
 111                 final CountDownLatch busyLatch    = new CountDownLatch(1);
 112                 final CountDownLatch proceedLatch = new CountDownLatch(1);
 113                 final Runnable notifier = new Runnable() {
 114                         public void run() { runLatch.countDown(); }};
 115                 final Runnable neverRuns = new Runnable() {
 116                         public void run() { fail(); }};
 117                 final Runnable keepPoolBusy = new Runnable() {
 118                         public void run() {
 119                             try {
 120                                 busyLatch.countDown();
 121                                 proceedLatch.await();
 122                             } catch (Throwable t) { unexpected(t); }
 123                         }};
 124                 pool.schedule(keepPoolBusy, 0, DAYS);
 125                 busyLatch.await();
 126                 scheduleNow(pool, notifier, nowHow);
 127                 waitForNanoTimeTick();
 128                 scheduleAtTheEndOfTime(pool, neverRuns, thenHow);
 129                 proceedLatch.countDown();
 130 
 131                 check(runLatch.await(LONG_DELAY_MS, MILLISECONDS));
 132                 equal(runLatch.getCount(), 0L);
 133 
 134                 pool.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
 135                 pool.shutdown();
 136             }
 137 
 138             final int nowHowCopy = nowHow;
 139             final ScheduledThreadPoolExecutor pool
 140                 = new ScheduledThreadPoolExecutor(1);
 141             final CountDownLatch runLatch = new CountDownLatch(1);
 142             final Runnable notifier = new Runnable() {
 143                     public void run() { runLatch.countDown(); }};
 144             final Runnable scheduleNowScheduler = new Runnable() {
 145                     public void run() {
 146                         try {
 147                             scheduleNow(pool, notifier, nowHowCopy);
 148                             waitForNanoTimeTick();
 149                         } catch (Throwable t) { unexpected(t); }
 150                     }};
 151             pool.scheduleWithFixedDelay(scheduleNowScheduler,
 152                                         0, Long.MAX_VALUE, NANOSECONDS);
 153 
 154             check(runLatch.await(LONG_DELAY_MS, MILLISECONDS));
 155             equal(runLatch.getCount(), 0L);
 156 
 157             pool.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
 158             pool.shutdown();
 159         }
 160     }
 161 
 162     //--------------------- Infrastructure ---------------------------
 163     volatile int passed = 0, failed = 0;
 164     void pass() {passed++;}
 165     void fail() {failed++; Thread.dumpStack();}
 166     void fail(String msg) {System.err.println(msg); fail();}
 167     void unexpected(Throwable t) {failed++; t.printStackTrace();}
 168     void check(boolean cond) {if (cond) pass(); else fail();}
 169     void equal(Object x, Object y) {
 170         if (x == null ? y == null : x.equals(y)) pass();
 171         else fail(x + " not equal to " + y);}
 172     public static void main(String[] args) throws Throwable {
 173         new DelayOverflow().instanceMain(args);}
 174     void instanceMain(String[] args) throws Throwable {
 175         try {test(args);} catch (Throwable t) {unexpected(t);}
 176         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
 177         if (failed > 0) throw new AssertionError("Some tests failed");}
 178 }