comparison 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
comparison
equal deleted inserted replaced
26:f589fc20a5f9 27:1bf55a6eb092
1 module java.util.Timer;
2
3 import java.lang.all;
4 import java.util.TimerTask;
5 import java.lang.Thread;
6
7 version(Tango){
8 import tango.core.sync.Mutex;
9 import tango.core.sync.Condition;
10 import tango.text.convert.Format;
11 } else { // Phobos
12 }
13
14
15 class Timer {
16 private static final class TaskQueue {
17 version(Tango){
18 private Mutex mutex;
19 private Condition cond;
20 } else { // Phobos
21 }
22
23
24 private static const int DEFAULT_SIZE = 32;
25 private bool nullOnEmpty;
26 private TimerTask heap[];
27 private int elements;
28 public this() {
29 version(Tango){
30 mutex = new Mutex();
31 cond = new Condition( mutex );
32 heap = new TimerTask[DEFAULT_SIZE];
33 elements = 0;
34 nullOnEmpty = false;
35 } else { // Phobos
36 implMissing(__FILE__,__LINE__);
37 }
38 }
39
40 private void add(TimerTask task) {
41 elements++;
42 if (elements is heap.length) {
43 TimerTask new_heap[] = new TimerTask[heap.length * 2];
44 System.arraycopy(heap, 0, new_heap, 0, heap.length);
45 heap = new_heap;
46 }
47 heap[elements] = task;
48 }
49
50 private void remove() {
51 // clear the entry first
52 heap[elements] = null;
53 elements--;
54 if (elements + DEFAULT_SIZE / 2 <= (heap.length / 4)) {
55 TimerTask new_heap[] = new TimerTask[heap.length / 2];
56 System.arraycopy(heap, 0, new_heap, 0, elements + 1);
57 heap = new_heap;
58 }
59 }
60
61 public void enqueue(TimerTask task) {
62 version(Tango){
63 synchronized( mutex ){
64 if (heap is null) {
65 throw new IllegalStateException("cannot enqueue when stop() has been called on queue");
66 }
67
68 heap[0] = task;
69 add(task);
70 int child = elements;
71 int parent = child / 2;
72 while (heap[parent].scheduled > task.scheduled) {
73 heap[child] = heap[parent];
74 child = parent;
75 parent = child / 2;
76 }
77 heap[child] = task;
78 heap[0] = null;
79 cond.notify();
80 }
81 } else { // Phobos
82 implMissing(__FILE__,__LINE__);
83 }
84 }
85
86 private TimerTask top() {
87 if (elements is 0) {
88 return null;
89 }
90 else {
91 return heap[1];
92 }
93 }
94
95 public TimerTask serve() {
96 version(Tango){
97 synchronized( mutex ){
98 TimerTask task = null;
99 while (task is null) {
100 task = top();
101
102 if ((heap is null) || (task is null && nullOnEmpty)) {
103 return null;
104 }
105
106 if (task !is null) {
107 // The time to wait until the task should be served
108 long time = task.scheduled - System.currentTimeMillis();
109 if (time > 0) {
110 // This task should not yet be served
111 // So wait until this task is ready
112 // or something else happens to the queue
113 task = null; // set to null to make sure we call top()
114 try {
115 cond.wait(time);
116 }
117 catch (InterruptedException _) {
118 }
119 }
120 }
121 else {
122 // wait until a task is added
123 // or something else happens to the queue
124 try {
125 cond.wait();
126 }
127 catch (InterruptedException _) {
128 }
129 }
130 }
131
132 TimerTask lastTask = heap[elements];
133 remove();
134
135 int parent = 1;
136 int child = 2;
137 heap[1] = lastTask;
138 while (child <= elements) {
139 if (child < elements) {
140 if (heap[child].scheduled > heap[child + 1].scheduled) {
141 child++;
142 }
143 }
144
145 if (lastTask.scheduled <= heap[child].scheduled)
146 break;
147
148 heap[parent] = heap[child];
149 parent = child;
150 child = parent * 2;
151 }
152
153 heap[parent] = lastTask;
154 return task;
155 }
156 } else { // Phobos
157 implMissing(__FILE__,__LINE__);
158 return null;
159 }
160 }
161
162 public void setNullOnEmpty(bool nullOnEmpty) {
163 version(Tango){
164 synchronized( mutex ){
165 this.nullOnEmpty = nullOnEmpty;
166 cond.notify();
167 }
168 } else { // Phobos
169 implMissing(__FILE__,__LINE__);
170 }
171 }
172
173 public void stop() {
174 version(Tango){
175 synchronized( mutex ){
176 this.heap = null;
177 this.elements = 0;
178 cond.notify();
179 }
180 } else { // Phobos
181 implMissing(__FILE__,__LINE__);
182 }
183 }
184
185 }
186
187 private static final class Scheduler : Runnable {
188 private TaskQueue queue;
189
190 public this(TaskQueue queue) {
191 this.queue = queue;
192 }
193
194 public void run() {
195 TimerTask task;
196 while ((task = queue.serve()) !is null) {
197 if (task.scheduled >= 0) {
198 task.lastExecutionTime = task.scheduled;
199 if (task.period < 0) {
200 task.scheduled = -1;
201 }
202 try {
203 task.run();
204 }
205 // catch (ThreadDeath death) {
206 // // If an exception escapes, the Timer becomes invalid.
207 // queue.stop();
208 // throw death;
209 // }
210 catch (Exception t) {
211 queue.stop();
212 }
213 }
214 if (task.scheduled >= 0) {
215 if (task.fixed) {
216 task.scheduled += task.period;
217 }
218 else {
219 task.scheduled = task.period + System.currentTimeMillis();
220 }
221
222 try {
223 queue.enqueue(task);
224 }
225 catch (IllegalStateException ise) {
226 // Ignore. Apparently the Timer queue has been stopped.
227 }
228 }
229 }
230 }
231 }
232
233 private static int nr;
234 private TaskQueue queue;
235 private Scheduler scheduler;
236 private Thread thread;
237 private bool canceled;
238
239 public this() {
240 this(false);
241 }
242
243 public this(bool daemon) {
244 this(daemon, Thread.NORM_PRIORITY);
245 }
246
247 private this(bool daemon, int priority) {
248 this(daemon, priority, Format( "Timer-{}", ++nr));
249 }
250
251 private this(bool daemon, int priority, String name) {
252 canceled = false;
253 queue = new TaskQueue();
254 scheduler = new Scheduler(queue);
255 thread = new Thread(scheduler, name);
256 thread.setDaemon(daemon);
257 thread.setPriority(priority);
258 thread.start();
259 }
260
261 public void cancel() {
262 canceled = true;
263 queue.stop();
264 }
265
266 private void schedule(TimerTask task, long time, long period, bool fixed) {
267 if (time < 0)
268 throw new IllegalArgumentException("negative time");
269
270 if (task.scheduled is 0 && task.lastExecutionTime is -1) {
271 task.scheduled = time;
272 task.period = period;
273 task.fixed = fixed;
274 }
275 else {
276 throw new IllegalStateException("task was already scheduled or canceled");
277 }
278
279 if (!this.canceled && this.thread !is null) {
280 queue.enqueue(task);
281 }
282 else {
283 throw new IllegalStateException("timer was canceled or scheduler thread has died");
284 }
285 }
286
287 private static void positiveDelay(long delay) {
288 if (delay < 0) {
289 throw new IllegalArgumentException("delay is negative");
290 }
291 }
292
293 private static void positivePeriod(long period) {
294 if (period < 0) {
295 throw new IllegalArgumentException("period is negative");
296 }
297 }
298
299 // public void schedule(TimerTask task, Date date) {
300 // long time = date.getTime();
301 // schedule(task, time, -1, false);
302 // }
303
304 // public void schedule(TimerTask task, Date date, long period) {
305 // positivePeriod(period);
306 // long time = date.getTime();
307 // schedule(task, time, period, false);
308 // }
309
310 public void schedule(TimerTask task, long delay) {
311 positiveDelay(delay);
312 long time = System.currentTimeMillis() + delay;
313 schedule(task, time, -1, false);
314 }
315
316 public void schedule(TimerTask task, long delay, long period) {
317 positiveDelay(delay);
318 positivePeriod(period);
319 long time = System.currentTimeMillis() + delay;
320 schedule(task, time, period, false);
321 }
322
323 // public void scheduleAtFixedRate(TimerTask task, Date date, long period) {
324 // positivePeriod(period);
325 // long time = date.getTime();
326 // schedule(task, time, period, true);
327 // }
328
329 public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
330 positiveDelay(delay);
331 positivePeriod(period);
332 long time = System.currentTimeMillis() + delay;
333 schedule(task, time, period, true);
334 }
335
336 protected void finalize() {
337 queue.setNullOnEmpty(true);
338 }
339
340
341 ///////////////////////////////////////////////////
342 /+ alias CircularList!( TimerTask ) ListType;
343
344 private Thread thread;
345 private ListType schedules;
346 private Mutex mutex;
347 private Condition cond;
348 private bool isCanceled = false;
349
350 this(){
351 this(false);
352 }
353 this(bool isDaemon){
354 mutex = new Mutex();
355 cond = new Condition( mutex );
356
357 schedules = new ListType();
358 thread = new Thread( &run );
359 thread.setDaemon( isDaemon );
360 thread.start();
361 }
362 private void run(){
363
364 while( !isCanceled ){
365 TimerTask timerTask = null;
366 synchronized(mutex){
367 bool isReady = false;
368 do{
369 if( isCanceled ){
370 return;
371 }
372
373 if( schedules.size() is 0 ){
374 cond.wait();
375 }
376 else{
377 timerTask = schedules.head();
378 TimeSpan toWait = timerTask.executionTime - Clock.now();
379 if( toWait.interval() > 0 ){
380 cond.wait( toWait.interval() );
381 }
382 else{
383 schedules.removeHead();
384 isReady = true;
385 }
386 }
387 }while( !isReady );
388 }
389 if( timerTask ){
390 timerTask.run();
391 if( timerTask.period.millis > 0 ){
392 timerTask.executionTime += timerTask.period;
393 synchronized(mutex){
394 int index = 0;
395 foreach( tt; schedules ){
396 if( tt.executionTime > timerTask.executionTime ){
397 break;
398 }
399 index++;
400 }
401 schedules.addAt( index, timerTask );
402 }
403 }
404 }
405 }
406 }
407 void cancel(){
408 synchronized(mutex){
409 isCanceled = true;
410 cond.notifyAll();
411 }
412 }
413 void schedule(TimerTask task, long delay){
414 scheduleAtFixedRate( task, delay, 0 );
415 }
416 void scheduleAtFixedRate(TimerTask task, long delay, long period){
417 assert( task );
418 version(TANGOSVN){
419 task.executionTime = Clock.now + TimeSpan.fromMillis(delay);
420 } else {
421 task.executionTime = Clock.now + TimeSpan.millis(delay);
422 }
423 task.timer = this;
424 synchronized(mutex){
425 int index = 0;
426 if( schedules.size() > 0 )
427 foreach( tt; schedules ){
428 if( tt.executionTime > task.executionTime ){
429 break;
430 }
431 index++;
432 }
433 schedules.addAt( index, task );
434 cond.notifyAll();
435 }
436 }
437
438 // void schedule(TimerTask task, Date time){}
439 // void schedule(TimerTask task, Date firstTime, long period){}
440 // void schedule(TimerTask task, long delay, long period){}
441 // void scheduleAtFixedRate(TimerTask task, Date firstTime, long period){}
442 +/
443 }
444
445