Commit 93267019 by Tom Tromey Committed by Tom Tromey

* java/util/Timer.java: New version from Classpath.

From-SVN: r39573
parent 0e206b71
2001-02-09 Tom Tromey <tromey@redhat.com>
* java/util/Timer.java: New version from Classpath.
2001-02-09 Bryce McKinlay <bryce@albatross.co.nz> 2001-02-09 Bryce McKinlay <bryce@albatross.co.nz>
* java/lang/Double.java (doubleToRawLongBits): Now native. * java/lang/Double.java (doubleToRawLongBits): Now native.
......
/* Timer.java -- Timer that runs TimerTasks at a later time. /* Timer.java -- Timer that runs TimerTasks at a later time.
Copyright (C) 2000 Free Software Foundation, Inc. Copyright (C) 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -50,8 +50,8 @@ package java.util; ...@@ -50,8 +50,8 @@ package java.util;
* @since 1.3 * @since 1.3
* @author Mark Wielaard (mark@klomp.org) * @author Mark Wielaard (mark@klomp.org)
*/ */
public class Timer { public class Timer
{
/** /**
* Priority Task Queue. * Priority Task Queue.
* TimerTasks are kept in a binary heap. * TimerTasks are kept in a binary heap.
...@@ -60,8 +60,8 @@ public class Timer { ...@@ -60,8 +60,8 @@ public class Timer {
* which is automatically called by the enqueue(), cancel() and * which is automatically called by the enqueue(), cancel() and
* timerFinalized() methods. * timerFinalized() methods.
*/ */
private static final class TaskQueue { private static final class TaskQueue
{
/** Default size of this queue */ /** Default size of this queue */
private final int DEFAULT_SIZE = 32; private final int DEFAULT_SIZE = 32;
...@@ -85,7 +85,8 @@ public class Timer { ...@@ -85,7 +85,8 @@ public class Timer {
/** /**
* Creates a TaskQueue of default size without any elements in it. * Creates a TaskQueue of default size without any elements in it.
*/ */
public TaskQueue() { public TaskQueue()
{
heap = new TimerTask[DEFAULT_SIZE]; heap = new TimerTask[DEFAULT_SIZE];
elements = 0; elements = 0;
nullOnEmpty = false; nullOnEmpty = false;
...@@ -95,10 +96,12 @@ public class Timer { ...@@ -95,10 +96,12 @@ public class Timer {
* Adds a TimerTask at the end of the heap. * Adds a TimerTask at the end of the heap.
* Grows the heap if necessary by doubling the heap in size. * Grows the heap if necessary by doubling the heap in size.
*/ */
private void add(TimerTask task) { private void add(TimerTask task)
{
elements++; elements++;
if (elements == heap.length) { if (elements == heap.length)
TimerTask new_heap[] = new TimerTask[heap.length*2]; {
TimerTask new_heap[] = new TimerTask[heap.length * 2];
System.arraycopy(heap, 0, new_heap, 0, heap.length); System.arraycopy(heap, 0, new_heap, 0, heap.length);
heap = new_heap; heap = new_heap;
} }
...@@ -110,13 +113,16 @@ public class Timer { ...@@ -110,13 +113,16 @@ public class Timer {
* Shrinks the heap in half if * Shrinks the heap in half if
* elements+DEFAULT_SIZE/2 <= heap.length/4. * elements+DEFAULT_SIZE/2 <= heap.length/4.
*/ */
private void remove() { private void remove()
{
// clear the entry first // clear the entry first
heap[elements] = null; heap[elements] = null;
elements--; elements--;
if (elements+DEFAULT_SIZE/2 <= (heap.length/4)) { if (elements + DEFAULT_SIZE / 2 <= (heap.length / 4))
TimerTask new_heap[] = new TimerTask[heap.length/2]; {
System.arraycopy(heap, 0, new_heap, 0, elements+1); TimerTask new_heap[] = new TimerTask[heap.length / 2];
System.arraycopy(heap, 0, new_heap, 0, elements + 1);
heap = new_heap;
} }
} }
...@@ -124,10 +130,11 @@ public class Timer { ...@@ -124,10 +130,11 @@ public class Timer {
* Adds a task to the queue and puts it at the correct place * Adds a task to the queue and puts it at the correct place
* in the heap. * in the heap.
*/ */
public synchronized void enqueue(TimerTask task) { public synchronized void enqueue(TimerTask task)
{
// Check if it is legal to add another element // Check if it is legal to add another element
if (heap == null) { if (heap == null)
{
throw new IllegalStateException throw new IllegalStateException
("cannot enqueue when stop() has been called on queue"); ("cannot enqueue when stop() has been called on queue");
} }
...@@ -137,7 +144,8 @@ public class Timer { ...@@ -137,7 +144,8 @@ public class Timer {
// Now push the task up in the heap until it has reached its place // Now push the task up in the heap until it has reached its place
int child = elements; int child = elements;
int parent = child / 2; int parent = child / 2;
while (heap[parent].scheduled > task.scheduled) { while (heap[parent].scheduled > task.scheduled)
{
heap[child] = heap[parent]; heap[child] = heap[parent];
child = parent; child = parent;
parent = child / 2; parent = child / 2;
...@@ -153,10 +161,14 @@ public class Timer { ...@@ -153,10 +161,14 @@ public class Timer {
* Returns the top element of the queue. * Returns the top element of the queue.
* Can return null when no task is in the queue. * Can return null when no task is in the queue.
*/ */
private TimerTask top() { private TimerTask top()
if (elements == 0) { {
if (elements == 0)
{
return null; return null;
} else { }
else
{
return heap[1]; return heap[1];
} }
} }
...@@ -166,39 +178,54 @@ public class Timer { ...@@ -166,39 +178,54 @@ public class Timer {
* Removes the element from the heap and reorders the heap first. * Removes the element from the heap and reorders the heap first.
* Can return null when there is nothing in the queue. * Can return null when there is nothing in the queue.
*/ */
public synchronized TimerTask serve() { public synchronized TimerTask serve()
{
// The task to return // The task to return
TimerTask task = null; TimerTask task = null;
while (task == null) { while (task == null)
{
// Get the next task // Get the next task
task = top(); task = top();
// return null when asked to stop // return null when asked to stop
// or if asked to return null when the queue is empty // or if asked to return null when the queue is empty
if ((heap == null) || (task == null && nullOnEmpty)) { if ((heap == null) || (task == null && nullOnEmpty))
{
return null; return null;
} }
// Do we have a task? // Do we have a task?
if (task != null) { if (task != null)
{
// The time to wait until the task should be served // The time to wait until the task should be served
long time = task.scheduled-System.currentTimeMillis(); long time = task.scheduled - System.currentTimeMillis();
if (time > 0) { if (time > 0)
{
// This task should not yet be served // This task should not yet be served
// So wait until this task is ready // So wait until this task is ready
// or something else happens to the queue // or something else happens to the queue
task = null; // set to null to make sure we call top() task = null; // set to null to make sure we call top()
try { try
{
this.wait(time); this.wait(time);
} catch (InterruptedException _) {}
} }
} else { catch (InterruptedException _)
{
}
}
}
else
{
// wait until a task is added // wait until a task is added
// or something else happens to the queue // or something else happens to the queue
try { try
{
this.wait(); this.wait();
} catch (InterruptedException _) {} }
catch (InterruptedException _)
{
}
} }
} }
...@@ -210,9 +237,12 @@ public class Timer { ...@@ -210,9 +237,12 @@ public class Timer {
int parent = 1; int parent = 1;
int child = 2; int child = 2;
heap[1] = lastTask; heap[1] = lastTask;
while(child <= elements) { while (child <= elements)
if (child < elements) { {
if (heap[child].scheduled > heap[child+1].scheduled) { if (child < elements)
{
if (heap[child].scheduled > heap[child + 1].scheduled)
{
child++; child++;
} }
} }
...@@ -222,7 +252,7 @@ public class Timer { ...@@ -222,7 +252,7 @@ public class Timer {
heap[parent] = heap[child]; heap[parent] = heap[child];
parent = child; parent = child;
child = parent*2; child = parent * 2;
} }
// this is the correct new place for the lastTask // this is the correct new place for the lastTask
...@@ -232,14 +262,14 @@ public class Timer { ...@@ -232,14 +262,14 @@ public class Timer {
return task; return task;
} }
/** /**
* When nullOnEmpty is true the serve() method will return null when * When nullOnEmpty is true the serve() method will return null when
* there are no tasks in the queue, otherwise it will wait until * there are no tasks in the queue, otherwise it will wait until
* a new element is added to the queue. It is used to indicate to * a new element is added to the queue. It is used to indicate to
* the scheduler that no new tasks will ever be added to the queue. * the scheduler that no new tasks will ever be added to the queue.
*/ */
public synchronized void setNullOnEmpty(boolean nullOnEmpty) { public synchronized void setNullOnEmpty(boolean nullOnEmpty)
{
this.nullOnEmpty = nullOnEmpty; this.nullOnEmpty = nullOnEmpty;
this.notify(); this.notify();
} }
...@@ -249,7 +279,8 @@ public class Timer { ...@@ -249,7 +279,8 @@ public class Timer {
* serve() will return null. It is used to indicate to the Scheduler * serve() will return null. It is used to indicate to the Scheduler
* that it should stop executing since no more tasks will come. * that it should stop executing since no more tasks will come.
*/ */
public synchronized void stop() { public synchronized void stop()
{
this.heap = null; this.heap = null;
this.notify(); this.notify();
} }
...@@ -262,8 +293,8 @@ public class Timer { ...@@ -262,8 +293,8 @@ public class Timer {
* executed immediatly. Stops running when canceled or when the parent * executed immediatly. Stops running when canceled or when the parent
* Timer has been finalized and no more tasks have to be executed. * Timer has been finalized and no more tasks have to be executed.
*/ */
private static final class Scheduler implements Runnable { private static final class Scheduler implements Runnable
{
// The priority queue containing all the TimerTasks. // The priority queue containing all the TimerTasks.
private TaskQueue queue; private TaskQueue queue;
...@@ -271,38 +302,51 @@ public class Timer { ...@@ -271,38 +302,51 @@ public class Timer {
* Creates a new Scheduler that will schedule the tasks on the * Creates a new Scheduler that will schedule the tasks on the
* given TaskQueue. * given TaskQueue.
*/ */
public Scheduler(TaskQueue queue) { public Scheduler(TaskQueue queue)
{
this.queue = queue; this.queue = queue;
} }
public void run() { public void run()
{
TimerTask task; TimerTask task;
while((task = queue.serve()) != null) { while ((task = queue.serve()) != null)
{
// If this task has not been canceled // If this task has not been canceled
if (task.scheduled >= 0) { if (task.scheduled >= 0)
{
// Mark execution time // Mark execution time
task.lastExecutionTime = task.scheduled; task.lastExecutionTime = task.scheduled;
// Repeatable task? // Repeatable task?
if (task.period < 0) { if (task.period < 0)
{
// Last time this task is executed // Last time this task is executed
task.scheduled = -1; task.scheduled = -1;
} }
// Run the task // Run the task
try { try
{
task.run(); task.run();
} catch (Throwable t) {/* ignore all errors */} }
catch (Throwable t)
{
/* ignore all errors */
}
} }
// Calculate next time and possibly re-enqueue // Calculate next time and possibly re-enqueue
if (task.scheduled >= 0) { if (task.scheduled >= 0)
if (task.fixed) { {
if (task.fixed)
{
task.scheduled += task.period; task.scheduled += task.period;
} else { }
task.scheduled = task.period + else
System.currentTimeMillis(); {
task.scheduled = task.period + System.currentTimeMillis();
} }
queue.enqueue(task); queue.enqueue(task);
} }
...@@ -334,7 +378,8 @@ public class Timer { ...@@ -334,7 +378,8 @@ public class Timer {
* Creates a new Timer with a non deamon Thread as Scheduler, with normal * Creates a new Timer with a non deamon Thread as Scheduler, with normal
* priority and a default name. * priority and a default name.
*/ */
public Timer() { public Timer()
{
this(false); this(false);
} }
...@@ -342,7 +387,8 @@ public class Timer { ...@@ -342,7 +387,8 @@ public class Timer {
* Creates a new Timer with a deamon Thread as scheduler if deamon is true, * Creates a new Timer with a deamon Thread as scheduler if deamon is true,
* with normal priority and a default name. * with normal priority and a default name.
*/ */
public Timer(boolean daemon) { public Timer(boolean daemon)
{
this(daemon, Thread.NORM_PRIORITY); this(daemon, Thread.NORM_PRIORITY);
} }
...@@ -350,7 +396,8 @@ public class Timer { ...@@ -350,7 +396,8 @@ public class Timer {
* Creates a new Timer with a deamon Thread as scheduler if deamon is true, * Creates a new Timer with a deamon Thread as scheduler if deamon is true,
* with the priority given and a default name. * with the priority given and a default name.
*/ */
private Timer(boolean daemon, int priority) { private Timer(boolean daemon, int priority)
{
this(daemon, priority, "Timer-" + (++nr)); this(daemon, priority, "Timer-" + (++nr));
} }
...@@ -358,7 +405,8 @@ public class Timer { ...@@ -358,7 +405,8 @@ public class Timer {
* Creates a new Timer with a deamon Thread as scheduler if deamon is true, * Creates a new Timer with a deamon Thread as scheduler if deamon is true,
* with the priority and name given.E * with the priority and name given.E
*/ */
private Timer(boolean daemon, int priority, String name) { private Timer(boolean daemon, int priority, String name)
{
canceled = false; canceled = false;
queue = new TaskQueue(); queue = new TaskQueue();
scheduler = new Scheduler(queue); scheduler = new Scheduler(queue);
...@@ -373,7 +421,8 @@ public class Timer { ...@@ -373,7 +421,8 @@ public class Timer {
* normally finish execution, but no other tasks will be executed and no * normally finish execution, but no other tasks will be executed and no
* more tasks can be scheduled. * more tasks can be scheduled.
*/ */
public void cancel() { public void cancel()
{
canceled = true; canceled = true;
queue.stop(); queue.stop();
} }
...@@ -386,39 +435,46 @@ public class Timer { ...@@ -386,39 +435,46 @@ public class Timer {
* @exception IllegalStateException if the task was already scheduled or * @exception IllegalStateException if the task was already scheduled or
* canceled or this Timer is canceled or the scheduler thread has died * canceled or this Timer is canceled or the scheduler thread has died
*/ */
private void schedule(TimerTask task, private void schedule(TimerTask task, long time, long period, boolean fixed)
long time, {
long period,
boolean fixed) {
if (time < 0) if (time < 0)
throw new IllegalArgumentException("negative time"); throw new IllegalArgumentException("negative time");
if (task.scheduled == 0 && task.lastExecutionTime == -1) { if (task.scheduled == 0 && task.lastExecutionTime == -1)
{
task.scheduled = time; task.scheduled = time;
task.period = period; task.period = period;
task.fixed = fixed; task.fixed = fixed;
} else { }
else
{
throw new IllegalStateException throw new IllegalStateException
("task was already scheduled or canceled"); ("task was already scheduled or canceled");
} }
if (!this.canceled && this.thread != null) { if (!this.canceled && this.thread != null)
{
queue.enqueue(task); queue.enqueue(task);
} else { }
else
{
throw new IllegalStateException throw new IllegalStateException
("timer was canceled or scheduler thread has died"); ("timer was canceled or scheduler thread has died");
} }
} }
private static void positiveDelay(long delay) { private static void positiveDelay(long delay)
if (delay < 0) { {
if (delay < 0)
{
throw new IllegalArgumentException("delay is negative"); throw new IllegalArgumentException("delay is negative");
} }
} }
private static void positivePeriod(long period) { private static void positivePeriod(long period)
if (period < 0) { {
if (period < 0)
{
throw new IllegalArgumentException("period is negative"); throw new IllegalArgumentException("period is negative");
} }
} }
...@@ -430,7 +486,8 @@ public class Timer { ...@@ -430,7 +486,8 @@ public class Timer {
* @exception IllegalStateException if the task was already scheduled or * @exception IllegalStateException if the task was already scheduled or
* canceled or this Timer is canceled or the scheduler thread has died * canceled or this Timer is canceled or the scheduler thread has died
*/ */
public void schedule(TimerTask task, Date date) { public void schedule(TimerTask task, Date date)
{
long time = date.getTime(); long time = date.getTime();
schedule(task, time, -1, false); schedule(task, time, -1, false);
} }
...@@ -445,7 +502,8 @@ public class Timer { ...@@ -445,7 +502,8 @@ public class Timer {
* @exception IllegalStateException if the task was already scheduled or * @exception IllegalStateException if the task was already scheduled or
* canceled or this Timer is canceled or the scheduler thread has died * canceled or this Timer is canceled or the scheduler thread has died
*/ */
public void schedule(TimerTask task, Date date, long period) { public void schedule(TimerTask task, Date date, long period)
{
positivePeriod(period); positivePeriod(period);
long time = date.getTime(); long time = date.getTime();
schedule(task, time, period, false); schedule(task, time, period, false);
...@@ -460,7 +518,8 @@ public class Timer { ...@@ -460,7 +518,8 @@ public class Timer {
* @exception IllegalStateException if the task was already scheduled or * @exception IllegalStateException if the task was already scheduled or
* canceled or this Timer is canceled or the scheduler thread has died * canceled or this Timer is canceled or the scheduler thread has died
*/ */
public void schedule(TimerTask task, long delay) { public void schedule(TimerTask task, long delay)
{
positiveDelay(delay); positiveDelay(delay);
long time = System.currentTimeMillis() + delay; long time = System.currentTimeMillis() + delay;
schedule(task, time, -1, false); schedule(task, time, -1, false);
...@@ -475,7 +534,8 @@ public class Timer { ...@@ -475,7 +534,8 @@ public class Timer {
* @exception IllegalStateException if the task was already scheduled or * @exception IllegalStateException if the task was already scheduled or
* canceled or this Timer is canceled or the scheduler thread has died * canceled or this Timer is canceled or the scheduler thread has died
*/ */
public void schedule(TimerTask task, long delay, long period) { public void schedule(TimerTask task, long delay, long period)
{
positiveDelay(delay); positiveDelay(delay);
positivePeriod(period); positivePeriod(period);
long time = System.currentTimeMillis() + delay; long time = System.currentTimeMillis() + delay;
...@@ -492,7 +552,8 @@ public class Timer { ...@@ -492,7 +552,8 @@ public class Timer {
* @exception IllegalStateException if the task was already scheduled or * @exception IllegalStateException if the task was already scheduled or
* canceled or this Timer is canceled or the scheduler thread has died * canceled or this Timer is canceled or the scheduler thread has died
*/ */
public void scheduleAtFixedRate(TimerTask task, Date date, long period) { public void scheduleAtFixedRate(TimerTask task, Date date, long period)
{
positivePeriod(period); positivePeriod(period);
long time = date.getTime(); long time = date.getTime();
schedule(task, time, period, true); schedule(task, time, period, true);
...@@ -508,7 +569,8 @@ public class Timer { ...@@ -508,7 +569,8 @@ public class Timer {
* @exception IllegalStateException if the task was already scheduled or * @exception IllegalStateException if the task was already scheduled or
* canceled or this Timer is canceled or the scheduler thread has died * canceled or this Timer is canceled or the scheduler thread has died
*/ */
public void scheduleAtFixedRate(TimerTask task, long delay, long period) { public void scheduleAtFixedRate(TimerTask task, long delay, long period)
{
positiveDelay(delay); positiveDelay(delay);
positivePeriod(period); positivePeriod(period);
long time = System.currentTimeMillis() + delay; long time = System.currentTimeMillis() + delay;
...@@ -519,7 +581,8 @@ public class Timer { ...@@ -519,7 +581,8 @@ public class Timer {
* Tells the scheduler that the Timer task died * Tells the scheduler that the Timer task died
* so there will be no more new tasks scheduled. * so there will be no more new tasks scheduled.
*/ */
protected void finalize() { protected void finalize()
{
queue.setNullOnEmpty(true); queue.setNullOnEmpty(true);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment