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    */