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