Mercurial > projects > dwt2
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 |