Mercurial > 510Connectbot
diff src/com/trilead/ssh2/util/TimeoutService.java @ 0:0ce5cc452d02
initial version
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 22 May 2014 10:41:19 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/trilead/ssh2/util/TimeoutService.java Thu May 22 10:41:19 2014 -0700 @@ -0,0 +1,130 @@ + +package com.trilead.ssh2.util; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Collections; +import java.util.LinkedList; + +import com.trilead.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, plattner@trilead.com + * @version $Id: TimeoutService.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ + */ +public class TimeoutService { + private static final Logger log = Logger.getLogger(TimeoutService.class); + + public static class TimeoutToken implements Comparable { + private long runTime; + private Runnable handler; + + private TimeoutToken(long runTime, Runnable handler) { + this.runTime = runTime; + this.handler = handler; + } + + public int compareTo(Object o) { + TimeoutToken t = (TimeoutToken) o; + + if (runTime > t.runTime) + return 1; + + if (runTime == t.runTime) + return 0; + + return -1; + } + } + + private static class TimeoutThread extends Thread { + public void run() { + synchronized (todolist) { + while (true) { + if (todolist.size() == 0) { + timeoutThread = null; + return; + } + + long now = System.currentTimeMillis(); + TimeoutToken tt = (TimeoutToken) todolist.getFirst(); + + if (tt.runTime > now) { + /* Not ready yet, sleep a little bit */ + try { + todolist.wait(tt.runTime - now); + } + catch (InterruptedException e) { + } + + /* 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.log(20, "Exeception in Timeout handler:" + e.getMessage() + "(" + sw.toString() + ")"); + } + } + } + } + } + + /* The list object is also used for locking purposes */ + private static final LinkedList todolist = new LinkedList(); + + 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 final TimeoutToken addTimeoutHandler(long runTime, Runnable handler) { + TimeoutToken token = new TimeoutToken(runTime, handler); + + synchronized (todolist) { + todolist.add(token); + Collections.sort(todolist); + + if (timeoutThread != null) + timeoutThread.interrupt(); + else { + timeoutThread = new TimeoutThread(); + timeoutThread.setDaemon(true); + timeoutThread.start(); + } + } + + return token; + } + + public static final void cancelTimeoutHandler(TimeoutToken token) { + synchronized (todolist) { + todolist.remove(token); + + if (timeoutThread != null) + timeoutThread.interrupt(); + } + } + +}