1 /*******************************************************************************
2 3 Fiber-suspending timer event. Allows a fiber to be suspended for a fixed
4 time period.
5 6 Copyright:
7 Copyright (c) 2009-2016 dunnhumby Germany GmbH.
8 All rights reserved.
9 10 License:
11 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
12 Alternatively, this file may be distributed under the terms of the Tango
13 3-Clause BSD License (see LICENSE_BSD.txt for details).
14 15 *******************************************************************************/16 17 moduleocean.io.select.client.FiberTimerEvent;
18 19 20 21 22 importocean.core.MessageFiber;
23 24 importocean.core.Verify;
25 26 importocean.sys.TimerFD;
27 28 importocean.io.select.client.model.IFiberSelectClient;
29 30 importocean.meta.types.Qualifiers;
31 importcore.stdc.math: modf;
32 33 34 35 /*******************************************************************************
36 37 Fiber-suspending timer event. Allows a fiber to be suspended for a fixed
38 time period.
39 40 *******************************************************************************/41 42 publicclassFiberTimerEvent : IFiberSelectClient43 {
44 /***************************************************************************
45 46 Token used when suspending / resuming fiber.
47 48 ***************************************************************************/49 50 staticprivateMessageFiber.TokenTimerFired;
51 52 53 /***************************************************************************
54 55 Static ctor. Initialises fiber token.
56 57 ***************************************************************************/58 59 staticthis ( )
60 {
61 TimerFired = MessageFiber.Token("timer_fired");
62 }
63 64 65 /***************************************************************************
66 67 Timer fd.
68 69 ***************************************************************************/70 71 privateTimerFDtimer;
72 73 74 /***************************************************************************
75 76 Constructor. Initialises (but does not register) the timer fd.
77 78 Params:
79 fiber = fiber instance to be suspended/resumed by the timer
80 realtime = true: use a settable system-wide clock.
81 false: use a non-settable clock that is not affected by
82 discontinuous changes in the system clock (e.g., manual
83 changes to system time).
84 85 ***************************************************************************/86 87 publicthis ( SelectFiberfiber, boolrealtime = false )
88 {
89 super(fiber);
90 91 this.timer = newTimerFD(realtime);
92 }
93 94 95 /***************************************************************************
96 97 Returs:
98 the epoll events to register for.
99 100 ***************************************************************************/101 102 publicoverrideEventevents ( )
103 {
104 returnEvent.EPOLLIN;
105 }
106 107 108 /***************************************************************************
109 110 Required by ISelectable interface.
111 112 Returns:
113 file descriptor used to manage custom event
114 115 ***************************************************************************/116 117 publicoverrideHandlefileHandle ( )
118 {
119 returnthis.timer.fileHandle;
120 }
121 122 123 /***************************************************************************
124 125 Sets the timer to a number of seconds and milliseconds approximating the
126 floating point value specified, registers it, and suspends the fiber
127 until it fires.
128 129 Params:
130 s = number of seconds to suspend fiber for
131 132 In:
133 s must be at least 0, which implies it must not be NaN. +∞ is
134 tolerated and uses the highest possible timer value.
135 136 ***************************************************************************/137 138 publicvoidwait ( doubles )
139 {
140 verify(s >= 0); // tolerate +∞141 doubleint_s;
142 automs = cast(uint)(modf(s, &int_s) * 1000);
143 this.wait(cast(uint)int_s, ms);
144 }
145 146 /***************************************************************************
147 148 Sets the timer to the specified number of seconds and milliseconds,
149 registers it, and suspends the fiber until it fires. If both seconds and
150 milliseconds are 0, the fiber is not suspended and the event is not
151 registered with epoll -- no pause occurs.
152 153 Params:
154 s = number of seconds to suspend fiber for
155 ms = number of additional milliseconds to suspend fiber for
156 157 ***************************************************************************/158 159 publicvoidwait ( uints, uintms = 0 )
160 {
161 if ( s == 0 && ms == 0 ) return;
162 163 this.timer.set(s, ms, 0, 0);
164 this.fiber.register(this);
165 this.fiber.suspend(TimerFired, this, this.fiber.Message(true));
166 }
167 168 169 /***************************************************************************
170 171 Handles events which occurred for the timer event fd. Resumes the fiber.
172 173 (Implements an abstract super class method.)
174 175 Params:
176 events = events which occurred for the fd
177 178 Returns:
179 false if the fiber is finished or true if it keeps going
180 181 ***************************************************************************/182 183 publicoverrideboolhandle ( Eventevents )
184 {
185 verify(this.fiber.waiting);
186 this.timer.handle();
187 188 SelectFiber.Messagemessage = this.fiber.resume(TimerFired, this);
189 190 // FIXME: this should actually always return false, as we always want191 // the timer to be one-shot. However, there is a fundamental bug with192 // the way the messages are handled. The problem is that193 // IFiberSelectClient.finalize() does not know whether the fiber is194 // still in use (suspended with no client registered) or whether it195 // should be killed. This will need to be revisited and fixed.196 return (message.active == message.active.num)? message.num != 0 : false;
197 }
198 199 200 /***************************************************************************
201 202 Returns:
203 identifier string for this instance, including the remaining time
204 205 ***************************************************************************/206 207 debug208 {
209 privatemstringtime_buffer;
210 importocean.core.Array : copy;
211 importocean.text.convert.Formatter;
212 213 publicoverridecstringid ( )
214 {
215 this.time_buffer.copy(super.id());
216 autotime = this.timer.time();
217 218 sformat(this.time_buffer, ": {}s {}ns",
219 time.it_value.tv_sec, time.it_value.tv_nsec);
220 returnthis.time_buffer;
221 }
222 }
223 224 }