Adnvance wheel and return all timers expired during wheel turn.
Cancel timer
Return internal view on current time - it is time at the call to init plus total number of steps multiplied by tick duration.
Schedule timer to ticks ticks forward from internal 'now'.
Number of ticks to rotate wheels until internal wheel 'now' catch up with real world realTime. Calculation based on time when wheels were stared and total numer of ticks pasded.
Time until next scheduled timer event. You provide tick size and current real world time. This function find ticks until next event and use time of the start and total steps executed to calculate time delta from realNow to next event.
1 import std; 2 globalLogLevel = LogLevel.info; 3 auto rnd = Random(142); 4 auto Tick = getValue!Duration(); 5 /// track execution 6 int counter; 7 SysTime last; 8 9 /// this is our Timer 10 class Timer 11 { 12 static ulong __id; 13 private ulong _id; 14 private string _name; 15 this(string name) 16 { 17 _id = __id++; 18 _name = name; 19 } 20 /// must provide id() method 21 ulong id() 22 { 23 return _id; 24 } 25 } 26 27 enum IOWakeUpInterval = 100; // to simulate random IO wakeups in interval 0 - 100.msecs 28 29 // each tick span 5 msecs - this is our link with time in reality 30 TimingWheels!Timer w; 31 w.init(); 32 auto durationToTicks(Duration d) 33 { 34 // we have to adjust w.now and realtime 'now' before scheduling timer 35 auto real_now = Clock.currStdTime; 36 auto tw_now = w.currStdTime(Tick); 37 auto delay = (real_now - tw_now).hnsecs; 38 return (d + delay)/Tick; 39 } 40 void process_timer(Timer t) 41 { 42 switch(t._name) 43 { 44 case "periodic": 45 if ( last.stdTime == 0) 46 { 47 // initialize tracking 48 last = Clock.currTime - 50.msecs; 49 } 50 auto delta = Clock.currTime - last; 51 assert(delta - 50.msecs <= max(Tick + Tick/20, 5.msecs), "delta-50.msecs=%s".format(delta-50.msecs)); 52 writefln("@ %s - delta: %sms (should be 50ms)", t._name, (Clock.currTime - last).split!"msecs".msecs); 53 last = Clock.currTime; 54 counter++; 55 w.schedule(t, durationToTicks(50.msecs)); // rearm 56 break; 57 default: 58 writefln("@ %s", t._name); 59 break; 60 } 61 } 62 // emulate some random initial delay 63 auto randomInitialDelay = uniform(0, 500, rnd).msecs; 64 Thread.sleep(randomInitialDelay); 65 // 66 // start one arbitrary timer and one periodic timer 67 // 68 auto some_timer = new Timer("some"); 69 auto periodic_timer = new Timer("periodic"); 70 w.schedule(some_timer, durationToTicks(32.msecs)); 71 w.schedule(periodic_timer, durationToTicks(50.msecs)); 72 73 while(counter < 10) 74 { 75 auto realNow = Clock.currStdTime; 76 auto randomIoInterval = uniform(0, IOWakeUpInterval, rnd).msecs; 77 auto nextTimerEvent = max(w.timeUntilNextEvent(Tick, realNow), 0.msecs); 78 // wait for what should happen earlier 79 auto time_to_sleep = min(randomIoInterval, nextTimerEvent); 80 writefln("* sleep until timer event or random I/O for %s", time_to_sleep); 81 Thread.sleep(time_to_sleep); 82 // make steps if required 83 int ticks = w.ticksToCatchUp(Tick, Clock.currStdTime); 84 if (ticks > 0) 85 { 86 auto wr = w.advance(ticks); 87 foreach(t; wr.timers) 88 { 89 process_timer(t); 90 } 91 } 92 // emulate some random processing time 93 Thread.sleep(uniform(0, 5, rnd).msecs); 94 }
This structure implements scheme 6.2 thom the http://www.cs.columbia.edu/~nahum/w6998/papers/sosp87-timing-wheels.pdf and supports several primitives:
Each operation take O(1) time.