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 <ae@cy.md> 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 private alias ae.sys.timing.Timer SysTimer; 24 private alias ae.ui.timer.timer.Timer Timer; 25 26 /// A simple thread-based `Timer` implementation. 27 final class ThreadTimer : Timer 28 { 29 this() 30 { 31 sysTimer = new SysTimer; 32 semaphore = new Semaphore; 33 auto thread = new Thread(&threadProc); 34 thread.isDaemon = true; 35 thread.start(); 36 } /// 37 38 protected: 39 SysTimer sysTimer; 40 Semaphore semaphore; 41 shared bool prodding; 42 43 override TimerEvent setTimeout (AppCallback fn, uint ms) { return new ThreadTimerEvent(fn, ms, false); } 44 override TimerEvent setInterval(AppCallback fn, uint ms) { return new ThreadTimerEvent(fn, ms, true ); } 45 46 private: 47 void threadProc() 48 { 49 while (true) 50 { 51 Duration remainingTime; 52 53 synchronized(sysTimer) 54 { 55 prodding = true; 56 sysTimer.prod(); 57 prodding = false; 58 remainingTime = sysTimer.getRemainingTime(); 59 } 60 61 if (remainingTime == Duration.max) 62 semaphore.wait(); 63 else 64 semaphore.wait(remainingTime); 65 } 66 } 67 68 final class ThreadTimerEvent : TimerEvent 69 { 70 AppCallback fn; 71 bool recurring; 72 TimerTask task; 73 74 this(AppCallback fn, uint ms, bool recurring) 75 { 76 this.fn = fn; 77 this.recurring = recurring; 78 this.task = new TimerTask(ms.msecs, &taskCallback); 79 synchronized(sysTimer) 80 sysTimer.add(task); 81 } 82 83 void taskCallback(SysTimer timer, TimerTask task) 84 { 85 if (recurring) 86 timer.add(task); 87 fn.call(); 88 } 89 90 override void cancel() 91 { 92 if (prodding) // cancel called from timer event handler, synchronization would cause a deadlock 93 task.cancel(); 94 else 95 synchronized(sysTimer) 96 task.cancel(); 97 } 98 } 99 }