1/* 2 * Copyright (C) 2011 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.common.util.concurrent; 18 19import static java.util.concurrent.TimeUnit.MILLISECONDS; 20import static java.util.concurrent.TimeUnit.NANOSECONDS; 21import static junit.framework.Assert.fail; 22 23import com.google.common.testing.TearDown; 24import com.google.common.testing.TearDownAccepter; 25 26import java.util.concurrent.TimeUnit; 27import java.util.logging.Logger; 28 29/** 30 * Utilities for performing thread interruption in tests 31 * 32 * @author Kevin Bourrillion 33 * @author Chris Povirk 34 */ 35final class InterruptionUtil { 36 private static final Logger logger = 37 Logger.getLogger(InterruptionUtil.class.getName()); 38 39 /** 40 * Runnable which will interrupt the target thread repeatedly when run. 41 */ 42 private static final class Interruptenator implements Runnable { 43 private final long everyMillis; 44 private final Thread interruptee; 45 private volatile boolean shouldStop = false; 46 47 Interruptenator(Thread interruptee, long everyMillis) { 48 this.everyMillis = everyMillis; 49 this.interruptee = interruptee; 50 } 51 52 @Override 53 public void run() { 54 while (true) { 55 try { 56 Thread.sleep(everyMillis); 57 } catch (InterruptedException e) { 58 // ok. just stop sleeping. 59 } 60 if (shouldStop) { 61 break; 62 } 63 interruptee.interrupt(); 64 } 65 } 66 67 void stopInterrupting() { 68 shouldStop = true; 69 } 70 } 71 72 /** 73 * Interrupts the current thread after sleeping for the specified delay. 74 */ 75 static void requestInterruptIn(final long time, final TimeUnit unit) { 76 final Thread interruptee = Thread.currentThread(); 77 new Thread(new Runnable() { 78 @Override 79 public void run() { 80 try { 81 unit.sleep(time); 82 } catch (InterruptedException wontHappen) { 83 throw new AssertionError(wontHappen); 84 } 85 interruptee.interrupt(); 86 } 87 }).start(); 88 } 89 90 static void repeatedlyInterruptTestThread( 91 long interruptPeriodMillis, TearDownAccepter tearDownAccepter) { 92 final Interruptenator interruptingTask = 93 new Interruptenator(Thread.currentThread(), interruptPeriodMillis); 94 final Thread interruptingThread = new Thread(interruptingTask); 95 interruptingThread.start(); 96 tearDownAccepter.addTearDown(new TearDown() { 97 @Override public void tearDown() throws Exception { 98 interruptingTask.stopInterrupting(); 99 interruptingThread.interrupt(); 100 joinUninterruptibly(interruptingThread, 2500, MILLISECONDS); 101 Thread.interrupted(); 102 if (interruptingThread.isAlive()) { 103 // This will be hidden by test-output redirection: 104 logger.severe( 105 "InterruptenatorTask did not exit; future tests may be affected"); 106 /* 107 * This won't do any good under JUnit 3, but I'll leave it around in 108 * case we ever switch to JUnit 4: 109 */ 110 fail(); 111 } 112 } 113 }); 114 } 115 116 // TODO(cpovirk): promote to Uninterruptibles, and add untimed version 117 private static void joinUninterruptibly( 118 Thread thread, long timeout, TimeUnit unit) { 119 boolean interrupted = false; 120 try { 121 long remainingNanos = unit.toNanos(timeout); 122 long end = System.nanoTime() + remainingNanos; 123 124 while (true) { 125 try { 126 // TimeUnit.timedJoin() treats negative timeouts just like zero. 127 NANOSECONDS.timedJoin(thread, remainingNanos); 128 return; 129 } catch (InterruptedException e) { 130 interrupted = true; 131 remainingNanos = end - System.nanoTime(); 132 } 133 } 134 } finally { 135 if (interrupted) { 136 Thread.currentThread().interrupt(); 137 } 138 } 139 } 140} 141