1 /** 2 * ae.ui.timer.thread.timer 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.ui.timer.thread.timer; 15 16 import core.thread; 17 import core.sync.semaphore; 18 19 public import ae.ui.timer.timer; 20 import ae.ui.app.application; 21 import ae.sys.timing; 22 23 alias ae.sys.timing.Timer SysTimer; 24 alias ae.ui.timer.timer.Timer Timer; 25 26 final class ThreadTimer : Timer 27 { 28 SysTimer sysTimer; 29 Semaphore semaphore; 30 shared bool prodding; 31 32 this() 33 { 34 sysTimer = new SysTimer; 35 semaphore = new Semaphore; 36 auto thread = new Thread(&threadProc); 37 thread.isDaemon = true; 38 thread.start(); 39 } 40 41 override TimerEvent setTimeout (AppCallback fn, uint ms) { return new ThreadTimerEvent(fn, ms, false); } 42 override TimerEvent setInterval(AppCallback fn, uint ms) { return new ThreadTimerEvent(fn, ms, true ); } 43 44 private: 45 void threadProc() 46 { 47 while (true) 48 { 49 Duration remainingTime; 50 51 synchronized(sysTimer) 52 { 53 prodding = true; 54 sysTimer.prod(); 55 prodding = false; 56 remainingTime = sysTimer.getRemainingTime(); 57 } 58 59 if (remainingTime == Duration.max) 60 semaphore.wait(); 61 else 62 semaphore.wait(remainingTime); 63 } 64 } 65 66 final class ThreadTimerEvent : TimerEvent 67 { 68 AppCallback fn; 69 bool recurring; 70 TimerTask task; 71 72 this(AppCallback fn, uint ms, bool recurring) 73 { 74 this.fn = fn; 75 this.recurring = recurring; 76 this.task = new TimerTask(ms.msecs, &taskCallback); 77 synchronized(sysTimer) 78 sysTimer.add(task); 79 } 80 81 void taskCallback(SysTimer timer, TimerTask task) 82 { 83 if (recurring) 84 timer.add(task); 85 fn.call(); 86 } 87 88 override void cancel() 89 { 90 if (prodding) // cancel called from timer event handler, synchronization would cause a deadlock 91 task.cancel(); 92 else 93 synchronized(sysTimer) 94 task.cancel(); 95 } 96 } 97 }