Mercurial > projects > dwt2
diff base/src/java/util/Timer.d @ 27:1bf55a6eb092
Renamed java tree to base
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 21 Mar 2009 11:33:57 +0100 |
parents | java/src/java/util/Timer.d@9b96950f2c3c |
children | 536e43f63c81 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/src/java/util/Timer.d Sat Mar 21 11:33:57 2009 +0100 @@ -0,0 +1,445 @@ +module java.util.Timer; + +import java.lang.all; +import java.util.TimerTask; +import java.lang.Thread; + +version(Tango){ + import tango.core.sync.Mutex; + import tango.core.sync.Condition; + import tango.text.convert.Format; +} else { // Phobos +} + + +class Timer { + private static final class TaskQueue { + version(Tango){ + private Mutex mutex; + private Condition cond; + } else { // Phobos + } + + + private static const int DEFAULT_SIZE = 32; + private bool nullOnEmpty; + private TimerTask heap[]; + private int elements; + public this() { + version(Tango){ + mutex = new Mutex(); + cond = new Condition( mutex ); + heap = new TimerTask[DEFAULT_SIZE]; + elements = 0; + nullOnEmpty = false; + } else { // Phobos + implMissing(__FILE__,__LINE__); + } + } + + private void add(TimerTask task) { + elements++; + if (elements is heap.length) { + TimerTask new_heap[] = new TimerTask[heap.length * 2]; + System.arraycopy(heap, 0, new_heap, 0, heap.length); + heap = new_heap; + } + heap[elements] = task; + } + + private void remove() { + // clear the entry first + heap[elements] = null; + elements--; + 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); + heap = new_heap; + } + } + + public void enqueue(TimerTask task) { + version(Tango){ + synchronized( mutex ){ + if (heap is null) { + throw new IllegalStateException("cannot enqueue when stop() has been called on queue"); + } + + heap[0] = task; + add(task); + int child = elements; + int parent = child / 2; + while (heap[parent].scheduled > task.scheduled) { + heap[child] = heap[parent]; + child = parent; + parent = child / 2; + } + heap[child] = task; + heap[0] = null; + cond.notify(); + } + } else { // Phobos + implMissing(__FILE__,__LINE__); + } + } + + private TimerTask top() { + if (elements is 0) { + return null; + } + else { + return heap[1]; + } + } + + public TimerTask serve() { + version(Tango){ + synchronized( mutex ){ + TimerTask task = null; + while (task is null) { + task = top(); + + if ((heap is null) || (task is null && nullOnEmpty)) { + return null; + } + + if (task !is null) { + // The time to wait until the task should be served + long time = task.scheduled - System.currentTimeMillis(); + if (time > 0) { + // This task should not yet be served + // So wait until this task is ready + // or something else happens to the queue + task = null; // set to null to make sure we call top() + try { + cond.wait(time); + } + catch (InterruptedException _) { + } + } + } + else { + // wait until a task is added + // or something else happens to the queue + try { + cond.wait(); + } + catch (InterruptedException _) { + } + } + } + + TimerTask lastTask = heap[elements]; + remove(); + + int parent = 1; + int child = 2; + heap[1] = lastTask; + while (child <= elements) { + if (child < elements) { + if (heap[child].scheduled > heap[child + 1].scheduled) { + child++; + } + } + + if (lastTask.scheduled <= heap[child].scheduled) + break; + + heap[parent] = heap[child]; + parent = child; + child = parent * 2; + } + + heap[parent] = lastTask; + return task; + } + } else { // Phobos + implMissing(__FILE__,__LINE__); + return null; + } + } + + public void setNullOnEmpty(bool nullOnEmpty) { + version(Tango){ + synchronized( mutex ){ + this.nullOnEmpty = nullOnEmpty; + cond.notify(); + } + } else { // Phobos + implMissing(__FILE__,__LINE__); + } + } + + public void stop() { + version(Tango){ + synchronized( mutex ){ + this.heap = null; + this.elements = 0; + cond.notify(); + } + } else { // Phobos + implMissing(__FILE__,__LINE__); + } + } + + } + + private static final class Scheduler : Runnable { + private TaskQueue queue; + + public this(TaskQueue queue) { + this.queue = queue; + } + + public void run() { + TimerTask task; + while ((task = queue.serve()) !is null) { + if (task.scheduled >= 0) { + task.lastExecutionTime = task.scheduled; + if (task.period < 0) { + task.scheduled = -1; + } + try { + task.run(); + } + // catch (ThreadDeath death) { + // // If an exception escapes, the Timer becomes invalid. + // queue.stop(); + // throw death; + // } + catch (Exception t) { + queue.stop(); + } + } + if (task.scheduled >= 0) { + if (task.fixed) { + task.scheduled += task.period; + } + else { + task.scheduled = task.period + System.currentTimeMillis(); + } + + try { + queue.enqueue(task); + } + catch (IllegalStateException ise) { + // Ignore. Apparently the Timer queue has been stopped. + } + } + } + } + } + + private static int nr; + private TaskQueue queue; + private Scheduler scheduler; + private Thread thread; + private bool canceled; + + public this() { + this(false); + } + + public this(bool daemon) { + this(daemon, Thread.NORM_PRIORITY); + } + + private this(bool daemon, int priority) { + this(daemon, priority, Format( "Timer-{}", ++nr)); + } + + private this(bool daemon, int priority, String name) { + canceled = false; + queue = new TaskQueue(); + scheduler = new Scheduler(queue); + thread = new Thread(scheduler, name); + thread.setDaemon(daemon); + thread.setPriority(priority); + thread.start(); + } + + public void cancel() { + canceled = true; + queue.stop(); + } + + private void schedule(TimerTask task, long time, long period, bool fixed) { + if (time < 0) + throw new IllegalArgumentException("negative time"); + + if (task.scheduled is 0 && task.lastExecutionTime is -1) { + task.scheduled = time; + task.period = period; + task.fixed = fixed; + } + else { + throw new IllegalStateException("task was already scheduled or canceled"); + } + + if (!this.canceled && this.thread !is null) { + queue.enqueue(task); + } + else { + throw new IllegalStateException("timer was canceled or scheduler thread has died"); + } + } + + private static void positiveDelay(long delay) { + if (delay < 0) { + throw new IllegalArgumentException("delay is negative"); + } + } + + private static void positivePeriod(long period) { + if (period < 0) { + throw new IllegalArgumentException("period is negative"); + } + } + + // public void schedule(TimerTask task, Date date) { + // long time = date.getTime(); + // schedule(task, time, -1, false); + // } + + // public void schedule(TimerTask task, Date date, long period) { + // positivePeriod(period); + // long time = date.getTime(); + // schedule(task, time, period, false); + // } + + public void schedule(TimerTask task, long delay) { + positiveDelay(delay); + long time = System.currentTimeMillis() + delay; + schedule(task, time, -1, false); + } + + public void schedule(TimerTask task, long delay, long period) { + positiveDelay(delay); + positivePeriod(period); + long time = System.currentTimeMillis() + delay; + schedule(task, time, period, false); + } + + // public void scheduleAtFixedRate(TimerTask task, Date date, long period) { + // positivePeriod(period); + // long time = date.getTime(); + // schedule(task, time, period, true); + // } + + public void scheduleAtFixedRate(TimerTask task, long delay, long period) { + positiveDelay(delay); + positivePeriod(period); + long time = System.currentTimeMillis() + delay; + schedule(task, time, period, true); + } + + protected void finalize() { + queue.setNullOnEmpty(true); + } + + + /////////////////////////////////////////////////// + /+ alias CircularList!( TimerTask ) ListType; + + private Thread thread; + private ListType schedules; + private Mutex mutex; + private Condition cond; + private bool isCanceled = false; + + this(){ + this(false); + } + this(bool isDaemon){ + mutex = new Mutex(); + cond = new Condition( mutex ); + + schedules = new ListType(); + thread = new Thread( &run ); + thread.setDaemon( isDaemon ); + thread.start(); + } + private void run(){ + + while( !isCanceled ){ + TimerTask timerTask = null; + synchronized(mutex){ + bool isReady = false; + do{ + if( isCanceled ){ + return; + } + + if( schedules.size() is 0 ){ + cond.wait(); + } + else{ + timerTask = schedules.head(); + TimeSpan toWait = timerTask.executionTime - Clock.now(); + if( toWait.interval() > 0 ){ + cond.wait( toWait.interval() ); + } + else{ + schedules.removeHead(); + isReady = true; + } + } + }while( !isReady ); + } + if( timerTask ){ + timerTask.run(); + if( timerTask.period.millis > 0 ){ + timerTask.executionTime += timerTask.period; + synchronized(mutex){ + int index = 0; + foreach( tt; schedules ){ + if( tt.executionTime > timerTask.executionTime ){ + break; + } + index++; + } + schedules.addAt( index, timerTask ); + } + } + } + } + } + void cancel(){ + synchronized(mutex){ + isCanceled = true; + cond.notifyAll(); + } + } + void schedule(TimerTask task, long delay){ + scheduleAtFixedRate( task, delay, 0 ); + } + void scheduleAtFixedRate(TimerTask task, long delay, long period){ + assert( task ); + version(TANGOSVN){ + task.executionTime = Clock.now + TimeSpan.fromMillis(delay); + } else { + task.executionTime = Clock.now + TimeSpan.millis(delay); + } + task.timer = this; + synchronized(mutex){ + int index = 0; + if( schedules.size() > 0 ) + foreach( tt; schedules ){ + if( tt.executionTime > task.executionTime ){ + break; + } + index++; + } + schedules.addAt( index, task ); + cond.notifyAll(); + } + } + + // void schedule(TimerTask task, Date time){} + // void schedule(TimerTask task, Date firstTime, long period){} + // void schedule(TimerTask task, long delay, long period){} + // void scheduleAtFixedRate(TimerTask task, Date firstTime, long period){} + +/ +} + +