All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cucumber.runtime.Timeout Maven / Gradle / Ivy

There is a newer version: 7.17.0
Show newest version
package cucumber.runtime;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;

public class Timeout {
    private Timeout() {
    }

    public static  T timeout(Callback callback, long timeoutMillis) throws Throwable {
        if (timeoutMillis == 0) {
            return callback.call();
        }

        /* We need to ensure a happens before relation exists between these events;
         *   a. the timer setting the interrupt flag on the execution thread.
         *   b. terminating and cleaning up the timer
         * To do this we synchronize on monitor. The atomic boolean is merely a convenient container.
         */
        final Thread executionThread = Thread.currentThread();
        final Object monitor = new Object();
        final AtomicBoolean done = new AtomicBoolean();

        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        ScheduledFuture timer = executorService.schedule(new Runnable() {
            @Override
            public void run() {
                synchronized (monitor) {
                    if (!done.get()) {
                        executionThread.interrupt();
                    }
                }
            }
        }, timeoutMillis, TimeUnit.MILLISECONDS);

        try {
            T result = callback.call();
            // The callback may have been busy waiting.
            if (Thread.interrupted()) {
                throw new TimeoutException("Timed out after " + timeoutMillis + "ms.");
            }
            return result;
        } catch (InterruptedException timeout) {
            throw new TimeoutException("Timed out after " + timeoutMillis + "ms.");
        } finally {
            synchronized (monitor) {
                done.set(true);
                timer.cancel(true);
                executorService.shutdownNow();
                // Clear the interrupted flag. It may have been set by the timer just before we returned the result.
                Thread.interrupted();
            }
        }
    }

    public interface Callback {
        T call() throws Throwable;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy