1 /*
   2  * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @bug 6405995
  26  * @summary Unit test for selector wakeup and interruption
  27  * @library .. /lib/testlibrary/
  28  */
  29 
  30 import java.io.*;
  31 import java.net.*;
  32 import java.nio.*;
  33 import java.nio.channels.*;
  34 import java.util.concurrent.CyclicBarrier;
  35 
  36 public class Wakeup {
  37 
  38     static void sleep(int millis) {
  39         try {
  40             Thread.sleep(millis);
  41         } catch (InterruptedException x) {
  42             x.printStackTrace();
  43         }
  44     }
  45 
  46     static class Sleeper extends TestThread {
  47         private static final long TIMEOUT = jdk.testlibrary.Utils.adjustTimeout(20_000);
  48 
  49         // barrier is used to synchronize sleeper thread and checking
  50         // thread which is the main thread: when go() get to the end,
  51         // then start checking the sleeper's status.
  52         private static CyclicBarrier barrier = new CyclicBarrier(2);
  53         private static int wakeups = 0;
  54         private static int waits = 0;
  55 
  56         volatile boolean interruptBeforeSelect = false;
  57         volatile boolean started = false;
  58         volatile boolean wantInterrupt = false;
  59         volatile boolean closed = false;
  60         Object gate = new Object();
  61 
  62         Selector sel;
  63 
  64         Sleeper(Selector sel, boolean wantInterrupt, boolean interruptBeforeSelect) {
  65             super("Sleeper", System.err);
  66             this.sel = sel;
  67             this.wantInterrupt = wantInterrupt;
  68             this.interruptBeforeSelect = interruptBeforeSelect;
  69         }
  70 
  71         public void go() throws Exception {
  72             started = true;
  73             if (interruptBeforeSelect) {
  74                 synchronized (gate) { }
  75             }
  76             wakeups++;
  77             System.err.println("Wakeup, selecting, " + wakeups);
  78             try {
  79                 sel.select();
  80             } catch (ClosedSelectorException x) {
  81                 closed = true;
  82             }
  83             boolean intr = Thread.currentThread().isInterrupted();
  84             System.err.println("Wakeup " + wakeups
  85                                + (closed ? " (closed)" : "")
  86                                + (intr ? " (intr)" : ""));
  87             if (closed)
  88                 return;
  89             if (wantInterrupt) {
  90                 while (!Thread.interrupted())
  91                     Thread.yield();
  92             }
  93             System.err.println("Wakeup, waiting, " + wakeups);
  94             barrier.await();
  95             System.err.println("Wakeup, wait successfully, " + wakeups);
  96         }
  97 
  98         void check(boolean close) throws Exception {
  99             waits++;
 100             System.err.println("waiting sleeper, " + waits);
 101             if (!close) {
 102                 barrier.await();
 103                 System.err.println("wait barrier successfully, " + waits);
 104             }
 105             if (finish(TIMEOUT) == 0)
 106                 throw new Exception("Test failed");
 107             if (this.closed != close)
 108                 throw new Exception("Selector was closed");
 109         }
 110 
 111         void check() throws Exception {
 112             check(false);
 113         }
 114 
 115         static Sleeper createSleeper(Selector sel, boolean wantInterrupt,
 116                 boolean interruptBeforeSelect) throws Exception {
 117             if (!wantInterrupt && interruptBeforeSelect) {
 118                 throw new RuntimeException("Wrong parameters!");
 119             }
 120 
 121             Sleeper sleeper = new Sleeper(sel, wantInterrupt, interruptBeforeSelect);
 122 
 123             if (interruptBeforeSelect) {
 124                 synchronized(sleeper.gate) {
 125                     sleeper.start();
 126                     while (!sleeper.started)
 127                         sleep(50);
 128                     sleeper.interrupt();
 129                 }
 130             } else {
 131                 sleeper.start();
 132                 while (!sleeper.started)
 133                     sleep(50);
 134                 if (wantInterrupt) {
 135                     sleep(50);
 136                     sleeper.interrupt();
 137                 }
 138             }
 139             return sleeper;
 140         }
 141     }
 142 
 143     static Sleeper newSleeper(Selector sel) throws Exception {
 144         return Sleeper.createSleeper(sel, false, false);
 145     }
 146 
 147     static Sleeper newSleeperWantInterrupt(Selector sel) throws Exception {
 148         return Sleeper.createSleeper(sel, true, false);
 149     }
 150 
 151     static Sleeper newSleeperWantInterruptBeforeSelect(Selector sel) throws Exception {
 152         return Sleeper.createSleeper(sel, true, true);
 153     }
 154 
 155     public static void main(String[] args) throws Exception {
 156 
 157         Selector sel = Selector.open();
 158 
 159         // Wakeup before select
 160         sel.wakeup();
 161 
 162         Sleeper sleeper = newSleeper(sel); // 1
 163         sleeper.check();
 164 
 165         for (int i = 2; i < 5; i++) {
 166             // Wakeup during select
 167             sleeper = newSleeper(sel);
 168             sel.wakeup();
 169             sleeper.check();         // 2 .. 4
 170         }
 171 
 172         // Double wakeup
 173         sel.wakeup();
 174         sel.wakeup();
 175         sleeper = newSleeper(sel);
 176         sleeper.check();            // 5
 177 
 178         // Interrupt
 179         sleeper = newSleeperWantInterrupt(sel);
 180         sleeper.check();            // 6
 181 
 182         // Interrupt before select
 183         sleeper = newSleeperWantInterruptBeforeSelect(sel);
 184         sleeper.check();            // 7
 185 
 186         // Close during select
 187         sleeper = newSleeper(sel);
 188         sel.close();
 189         sleeper.check();           // 8
 190 
 191         sleeper = newSleeper(sel);
 192         sleeper.check(true);
 193     }
 194 
 195 }