view src/ch/ethz/ssh2/util/TimeoutService.java @ 352:2bc6805cbc91
update jsocks to 2011-03-19
author
Carl Byington <carl@five-ten-sg.com>
date
Fri, 01 Aug 2014 11:32:33 -0700 (2014-08-01)
parents
071eccdff8ea
children
line source
+ − /*
+ − * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
+ − * Please refer to the LICENSE.txt for licensing details.
+ − */
+ −
+ − package ch.ethz.ssh2.util;
+ −
+ − import java.io.PrintWriter;
+ − import java.io.StringWriter;
+ − import java.util.Collections;
+ − import java.util.Comparator;
+ − import java.util.LinkedList;
+ −
+ − import ch.ethz.ssh2.log.Logger;
+ −
+ − /**
+ − * TimeoutService (beta). Here you can register a timeout.
+ − * <p>
+ − * Implemented having large scale programs in mind: if you open many concurrent SSH connections
+ − * that rely on timeouts, then there will be only one timeout thread. Once all timeouts
+ − * have expired/are cancelled, the thread will (sooner or later) exit.
+ − * Only after new timeouts arrive a new thread (singleton) will be instantiated.
+ − *
+ − * @author Christian Plattner
+ − * @version $Id: TimeoutService.java 89 2014-04-07 14:36:24Z dkocher@sudo.ch $
+ − */
+ − public class TimeoutService {
+ − private static final Logger log = Logger.getLogger(TimeoutService.class);
+ −
+ − public static class TimeoutToken {
+ − private long runTime;
+ − private Runnable handler;
+ −
+ − private TimeoutToken(long runTime, Runnable handler) {
+ − this.runTime = runTime;
+ − this.handler = handler;
+ − }
+ − }
+ −
+ − private static class TimeoutThread extends Thread {
+ − @Override
+ − public void run() {
+ − synchronized (todolist) {
+ − while (true) {
+ − if (todolist.size() == 0) {
+ − timeoutThread = null;
+ − return;
+ − }
+ −
+ − long now = System.currentTimeMillis();
+ − TimeoutToken tt = todolist.getFirst();
+ −
+ − if (tt.runTime > now) {
+ − /* Not ready yet, sleep a little bit */
+ − try {
+ − todolist.wait(tt.runTime - now);
+ − }
+ − catch (InterruptedException ignored) {
+ − }
+ −
+ − /* We cannot simply go on, since it could be that the token
+ − * was removed (cancelled) or another one has been inserted in
+ − * the meantime.
+ − */
+ − continue;
+ − }
+ −
+ − todolist.removeFirst();
+ −
+ − try {
+ − tt.handler.run();
+ − }
+ − catch (Exception e) {
+ − StringWriter sw = new StringWriter();
+ − e.printStackTrace(new PrintWriter(sw));
+ − log.warning("Exeception in Timeout handler:" + e.getMessage() + "(" + sw.toString() + ")");
+ − }
+ − }
+ − }
+ − }
+ − }
+ −
+ − /* The list object is also used for locking purposes */
+ − private static final LinkedList<TimeoutToken> todolist = new LinkedList<TimeoutService.TimeoutToken>();
+ −
+ − private static Thread timeoutThread = null;
+ −
+ − /**
+ − * It is assumed that the passed handler will not execute for a long time.
+ − *
+ − * @param runTime
+ − * @param handler
+ − * @return a TimeoutToken that can be used to cancel the timeout.
+ − */
+ − public static TimeoutToken addTimeoutHandler(long runTime, Runnable handler) {
+ − TimeoutToken token = new TimeoutToken(runTime, handler);
+ −
+ − synchronized (todolist) {
+ − todolist.add(token);
+ − Collections.sort(todolist, new Comparator<TimeoutToken>() {
+ − public int compare(TimeoutToken o1, TimeoutToken o2) {
+ − if (o1.runTime > o2.runTime)
+ − return 1;
+ −
+ − if (o1.runTime == o2.runTime)
+ − return 0;
+ −
+ − return -1;
+ − }
+ − });
+ −
+ − if (timeoutThread != null)
+ − timeoutThread.interrupt();
+ − else {
+ − timeoutThread = new TimeoutThread();
+ − timeoutThread.setDaemon(true);
+ − timeoutThread.start();
+ − }
+ − }
+ −
+ − return token;
+ − }
+ −
+ − public static void cancelTimeoutHandler(TimeoutToken token) {
+ − synchronized (todolist) {
+ − todolist.remove(token);
+ −
+ − if (timeoutThread != null)
+ − timeoutThread.interrupt();
+ − }
+ − }
+ −
+ − }