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