001 /*
002 * LAPIS lightweight structured text processing system
003 *
004 * Copyright (C) 1998-2002 Carnegie Mellon University,
005 * Copyright (C) 2003 Massachusetts Institute of Technology.
006 * All rights reserved.
007 *
008 * This library is free software; you can redistribute it
009 * and/or modify it under the terms of the GNU General
010 * Public License as published by the Free Software
011 * Foundation, version 2.
012 *
013 * LAPIS homepage: http://graphics.lcs.mit.edu/lapis/
014 */
015
016
017 package lapisx.util;
018
019 //import java.util.Vector;
020
021 public class Timer {
022
023 int interval;
024 boolean periodic;
025 boolean isExpired = false;
026
027 static TimerManager manager = new TimerManager ();
028 long deadline;
029 Timer next, prev;
030
031 public Timer () {
032 }
033
034 public void set (int msecDelay, boolean periodic) {
035 interval = msecDelay;
036 this.periodic = periodic;
037 isExpired = false;
038 if (!manager.isAlive ()) {
039 System.err.println ("TimerManager: restarting");
040 manager = new TimerManager ();
041 }
042 manager.register (this, System.currentTimeMillis () + msecDelay);
043 }
044
045 public int getInterval () {
046 return interval;
047 }
048
049 public boolean getPeriodic () {
050 return periodic;
051 }
052
053 public void cancel () {
054 manager.delete (this);
055 }
056
057 protected void alarm () {
058 }
059
060 public boolean expired () {
061 return isExpired;
062 }
063
064 /*
065 public static void main (String[] args) {
066 for (int i=0; i<args.length; ++i) {
067 boolean periodic = (args[i].charAt (0) == 'p');
068 if (periodic) args[i] = args[i].substring (1);
069 new TestTimer (args[i], Integer.parseInt (args[i]), periodic);
070 }
071 while (true) Thread.yield ();
072 }
073 */
074 }
075
076 class TimerManager extends Thread {
077 Timer first, last;
078
079 /*
080 static ThreadGroup rootThreadGroup;
081 static {
082 rootThreadGroup = Thread.currentThread().getThreadGroup();
083 while (rootThreadGroup.getParent() != null)
084 rootThreadGroup = rootThreadGroup.getParent();
085 }
086 */
087
088 public TimerManager () {
089 super (/* rootThreadGroup, */ "Timer Manager");
090 setDaemon (true);
091 start ();
092 }
093
094 public synchronized void register (Timer t, long deadline) {
095 t.deadline = deadline;
096 delete (t); // just in case it's already registered
097
098 //System.err.println ("TimerManager: set " + t + " to go off at " + deadline);
099 insertion:
100 {
101 for (Timer u = first; u != null; u = u.next) {
102 if (t.deadline < u.deadline) {
103 if (u.prev != null)
104 u.prev.next = t;
105 else
106 first = t;
107 t.prev = u.prev;
108 t.next = u;
109 u.prev = t;
110 break insertion;
111 }
112 }
113 if (last != null) {
114 last.next = t;
115 t.prev = last;
116 t.next = null;
117 last = t;
118 } else {
119 first = last = t;
120 }
121 }
122
123 //System.err.println ("TimerManager: waking up background thread");
124 notifyAll ();
125 }
126
127 public synchronized void delete (Timer t) {
128 if (t.next != null)
129 t.next.prev = t.prev;
130 if (t.prev != null)
131 t.prev.next = t.next;
132 if (t == last)
133 last = t.prev;
134 if (t == first)
135 first = t.next;
136 t.next = null;
137 t.prev = null;
138 }
139
140 static final int FOREVER = 60000; // wake up at least every 60 seconds
141
142 public synchronized void run () {
143 while (true) {
144 try {
145 //System.err.println ("TimerManager: awake");
146 if (first == null) {
147 //System.err.println ("TimerManager: waiting forever");
148 wait (FOREVER);
149 //System.err.println ("TimerManager: woke up");
150 }
151 else {
152 Timer t = first;
153 long now = System.currentTimeMillis ();
154 if (t.deadline <= now) {
155 // System.err.println ("TimerManager: timer " + t + " just went off at " + now);
156 try {
157 t.isExpired = true;
158 t.alarm ();
159 } catch (Throwable e) {
160 if (e instanceof ThreadDeath)
161 throw (ThreadDeath)e;
162 else
163 e.printStackTrace ();
164 }
165 if (t.periodic) {
166 register (t, now + t.interval);
167 }
168 else {
169 delete (t);
170 }
171 }
172 else {
173 //System.err.println ("TimerManager: waiting for " + (t.deadline - now) + " msec");
174 wait (t.deadline - now);
175 //System.err.println ("TimerManager: woke up");
176 }
177 }
178 } catch (InterruptedException e) {}
179 }
180 }
181 }
182
183 /*
184 class TestTimer extends Timer {
185 String message;
186
187 public TestTimer (String message, int millisec, boolean periodic) {
188 this.message = message;
189 set (millisec, periodic);
190 }
191
192 public void alarm () {
193 System.out.println (message);
194 }
195 }
196 */