418N/A/*
2362N/A * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
418N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
418N/A *
418N/A * This code is free software; you can redistribute it and/or modify it
418N/A * under the terms of the GNU General Public License version 2 only, as
418N/A * published by the Free Software Foundation.
418N/A *
418N/A * This code is distributed in the hope that it will be useful, but WITHOUT
418N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
418N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
418N/A * version 2 for more details (a copy is included in the LICENSE file that
418N/A * accompanied this code).
418N/A *
418N/A * You should have received a copy of the GNU General Public License version
418N/A * 2 along with this work; if not, write to the Free Software Foundation,
418N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
418N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
418N/A */
418N/A
418N/A/* @test
418N/A * @bug 6405995
418N/A * @summary Unit test for selector wakeup and interruption
418N/A * @library ..
418N/A */
418N/A
418N/Aimport java.io.*;
418N/Aimport java.net.*;
418N/Aimport java.nio.*;
418N/Aimport java.nio.channels.*;
418N/Aimport java.util.Random;
418N/A
418N/Apublic class Wakeup {
418N/A
418N/A static void sleep(int millis) {
418N/A try {
418N/A Thread.sleep(millis);
418N/A } catch (InterruptedException x) {
418N/A x.printStackTrace();
418N/A }
418N/A }
418N/A
418N/A static class Sleeper extends TestThread {
418N/A volatile boolean started = false;
418N/A volatile int entries = 0;
418N/A volatile int wakeups = 0;
418N/A volatile boolean wantInterrupt = false;
418N/A volatile boolean gotInterrupt = false;
418N/A volatile Exception exception = null;
418N/A volatile boolean closed = false;
418N/A Object gate = new Object();
418N/A
418N/A Selector sel;
418N/A
418N/A Sleeper(Selector sel) {
418N/A super("Sleeper", System.err);
418N/A this.sel = sel;
418N/A }
418N/A
418N/A public void go() throws Exception {
418N/A started = true;
418N/A for (;;) {
418N/A synchronized (gate) { }
418N/A entries++;
418N/A try {
418N/A sel.select();
418N/A } catch (ClosedSelectorException x) {
418N/A closed = true;
418N/A }
418N/A boolean intr = Thread.currentThread().isInterrupted();
418N/A wakeups++;
418N/A System.err.println("Wakeup " + wakeups
418N/A + (closed ? " (closed)" : "")
418N/A + (intr ? " (intr)" : ""));
418N/A if (wakeups > 1000)
418N/A throw new Exception("Too many wakeups");
418N/A if (closed)
418N/A return;
418N/A if (wantInterrupt) {
418N/A while (!Thread.interrupted())
418N/A Thread.yield();
418N/A gotInterrupt = true;
418N/A wantInterrupt = false;
418N/A }
418N/A }
418N/A }
418N/A
418N/A }
418N/A
418N/A private static int checkedWakeups = 0;
418N/A
418N/A private static void check(Sleeper sleeper, boolean intr)
418N/A throws Exception
418N/A {
418N/A checkedWakeups++;
418N/A if (sleeper.wakeups > checkedWakeups) {
418N/A sleeper.finish(100);
418N/A throw new Exception("Sleeper has run ahead");
418N/A }
418N/A int n = 0;
418N/A while (sleeper.wakeups < checkedWakeups) {
418N/A sleep(50);
418N/A if ((n += 50) > 1000) {
418N/A sleeper.finish(100);
418N/A throw new Exception("Sleeper appears to be dead ("
418N/A + checkedWakeups + ")");
418N/A }
418N/A }
418N/A if (sleeper.wakeups > checkedWakeups) {
418N/A sleeper.finish(100);
418N/A throw new Exception("Too many wakeups: Expected "
418N/A + checkedWakeups
418N/A + ", got " + sleeper.wakeups);
418N/A }
418N/A if (intr) {
418N/A n = 0;
418N/A // Interrupts can sometimes be delayed, so wait
418N/A while (!sleeper.gotInterrupt) {
418N/A sleep(50);
418N/A if ((n += 50) > 1000) {
418N/A sleeper.finish(100);
418N/A throw new Exception("Interrupt never delivered");
418N/A }
418N/A }
418N/A sleeper.gotInterrupt = false;
418N/A }
418N/A System.err.println("Check " + checkedWakeups
418N/A + (intr ? " (intr " + n + ")" : ""));
418N/A }
418N/A
418N/A public static void main(String[] args) throws Exception {
418N/A
418N/A Selector sel = Selector.open();
418N/A
418N/A // Wakeup before select
418N/A sel.wakeup();
418N/A
418N/A Sleeper sleeper = new Sleeper(sel);
418N/A
418N/A sleeper.start();
418N/A while (!sleeper.started)
418N/A sleep(50);
418N/A
418N/A check(sleeper, false); // 1
418N/A
418N/A for (int i = 2; i < 5; i++) {
418N/A // Wakeup during select
418N/A sel.wakeup();
418N/A check(sleeper, false); // 2 .. 4
418N/A }
418N/A
418N/A // Double wakeup
418N/A synchronized (sleeper.gate) {
418N/A sel.wakeup();
418N/A check(sleeper, false); // 5
418N/A sel.wakeup();
418N/A sel.wakeup();
418N/A }
418N/A check(sleeper, false); // 6
418N/A
418N/A // Interrupt
418N/A synchronized (sleeper.gate) {
418N/A sleeper.wantInterrupt = true;
418N/A sleeper.interrupt();
418N/A check(sleeper, true); // 7
418N/A }
418N/A
418N/A // Interrupt before select
418N/A while (sleeper.entries < 8)
418N/A Thread.yield();
418N/A synchronized (sleeper.gate) {
418N/A sel.wakeup();
418N/A check(sleeper, false); // 8
418N/A sleeper.wantInterrupt = true;
418N/A sleeper.interrupt();
418N/A sleep(50);
418N/A }
418N/A check(sleeper, true); // 9
418N/A
418N/A // Close during select
418N/A while (sleeper.entries < 10)
418N/A Thread.yield();
418N/A synchronized (sleeper.gate) {
418N/A sel.close();
418N/A check(sleeper, false); // 10
418N/A }
418N/A
418N/A if (sleeper.finish(200) == 0)
418N/A throw new Exception("Test failed");
418N/A if (!sleeper.closed)
418N/A throw new Exception("Selector not closed");
418N/A }
418N/A
418N/A}