11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2011 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License.
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License.
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.util.concurrent;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static java.util.concurrent.TimeUnit.MILLISECONDS;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static java.util.concurrent.TimeUnit.NANOSECONDS;
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static junit.framework.Assert.fail;
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.testing.TearDown;
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.testing.TearDownAccepter;
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.TimeUnit;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.logging.Logger;
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Utilities for performing thread interruption in tests
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Kevin Bourrillion
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Chris Povirk
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertfinal class InterruptionUtil {
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final Logger logger =
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Logger.getLogger(InterruptionUtil.class.getName());
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Runnable which will interrupt the target thread repeatedly when run.
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final class Interruptenator implements Runnable {
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private final long everyMillis;
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private final Thread interruptee;
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private volatile boolean shouldStop = false;
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Interruptenator(Thread interruptee, long everyMillis) {
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.everyMillis = everyMillis;
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.interruptee = interruptee;
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void run() {
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      while (true) {
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        try {
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          Thread.sleep(everyMillis);
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        } catch (InterruptedException e) {
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          // ok. just stop sleeping.
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (shouldStop) {
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          break;
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        interruptee.interrupt();
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    void stopInterrupting() {
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      shouldStop = true;
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Interrupts the current thread after sleeping for the specified delay.
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static void requestInterruptIn(final long time, final TimeUnit unit) {
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Thread interruptee = Thread.currentThread();
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    new Thread(new Runnable() {
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public void run() {
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        try {
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          unit.sleep(time);
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        } catch (InterruptedException wontHappen) {
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          throw new AssertionError(wontHappen);
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        interruptee.interrupt();
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }).start();
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static void repeatedlyInterruptTestThread(
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      long interruptPeriodMillis, TearDownAccepter tearDownAccepter) {
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Interruptenator interruptingTask =
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        new Interruptenator(Thread.currentThread(), interruptPeriodMillis);
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Thread interruptingThread = new Thread(interruptingTask);
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    interruptingThread.start();
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    tearDownAccepter.addTearDown(new TearDown() {
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override public void tearDown() throws Exception {
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        interruptingTask.stopInterrupting();
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        interruptingThread.interrupt();
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        joinUninterruptibly(interruptingThread, 2500, MILLISECONDS);
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Thread.interrupted();
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (interruptingThread.isAlive()) {
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          // This will be hidden by test-output redirection:
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          logger.severe(
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              "InterruptenatorTask did not exit; future tests may be affected");
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          /*
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert           * This won't do any good under JUnit 3, but I'll leave it around in
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert           * case we ever switch to JUnit 4:
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert           */
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          fail();
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    });
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // TODO(cpovirk): promote to Uninterruptibles, and add untimed version
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static void joinUninterruptibly(
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Thread thread, long timeout, TimeUnit unit) {
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    boolean interrupted = false;
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      long remainingNanos = unit.toNanos(timeout);
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      long end = System.nanoTime() + remainingNanos;
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      while (true) {
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        try {
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          // TimeUnit.timedJoin() treats negative timeouts just like zero.
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          NANOSECONDS.timedJoin(thread, remainingNanos);
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return;
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        } catch (InterruptedException e) {
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          interrupted = true;
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          remainingNanos = end - System.nanoTime();
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } finally {
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (interrupted) {
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Thread.currentThread().interrupt();
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
141