1 /******************************************************************************
2 3 Fiber that can register select clients in a dispatcher, optimizing
4 re-registrations and event changes.
5 6 MessageFiber that includes a select dispatcher and memorizes the last client
7 it has registered to optimize registrations by skipping unnecessary
8 register() or unregister() calls.
9 10 Copyright:
11 Copyright (c) 2009-2016 dunnhumby Germany GmbH.
12 All rights reserved.
13 14 License:
15 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
16 Alternatively, this file may be distributed under the terms of the Tango
17 3-Clause BSD License (see LICENSE_BSD.txt for details).
18 19 ******************************************************************************/20 21 moduleocean.io.select.fiber.SelectFiber;
22 23 24 importocean.core.MessageFiber;
25 26 importocean.core.Verify;
27 28 importcore.thread;
29 30 importocean.io.select.client.model.ISelectClient;
31 importocean.io.select.client.model.ISelectClientInfo;
32 33 importocean.io.select.EpollSelectDispatcher;
34 35 debug ( SelectFiber) importocean.io.Stdout : Stderr;
36 37 38 /******************************************************************************/39 40 publicclassSelectFiber : MessageFiber41 {
42 /**************************************************************************
43 44 Epoll instance to use
45 46 **************************************************************************/47 48 publicEpollSelectDispatcherepoll;
49 50 /**************************************************************************
51 52 Currently registered select client
53 54 **************************************************************************/55 56 privateISelectClientcurrent = null;
57 58 /**************************************************************************
59 60 Constructor
61 62 Params:
63 epoll = EpollSelectDispatcher instance
64 fiber = already created core.thread.Fiber
65 66 **************************************************************************/67 68 this ( EpollSelectDispatcherepoll, Fiberfiber )
69 {
70 this.epoll = epoll;
71 72 super(fiber);
73 }
74 75 /**************************************************************************
76 77 Constructor
78 79 Params:
80 epoll = EpollSelectDispatcher instance
81 coroutine = fiber coroutine
82 83 **************************************************************************/84 85 this ( EpollSelectDispatcherepoll, scopevoiddelegate ( ) coroutine )
86 {
87 this.epoll = epoll;
88 89 super(coroutine);
90 }
91 92 /**************************************************************************
93 94 Constructor
95 96 Params:
97 epoll = EpollSelectDispatcher instance
98 coroutine = fiber coroutine
99 sz = fiber stack size
100 101 **************************************************************************/102 103 this ( EpollSelectDispatcherepoll, scopevoiddelegate ( ) coroutine, size_tsz )
104 {
105 this.epoll = epoll;
106 107 super(coroutine, sz);
108 }
109 110 /**************************************************************************
111 112 Allows to change underlying core.thread.Fiber instance. Unregisters
113 the ISelectClient if necessary.
114 115 Params:
116 fiber = new fiber instance to use
117 118 **************************************************************************/119 120 overridepublicvoidreset ( Fiberfiber )
121 {
122 this.unregister();
123 super.reset(fiber);
124 }
125 126 /**************************************************************************
127 128 Registers client in epoll and sets client to the current client.
129 130 Params:
131 client = select client to register
132 133 Returns:
134 true if an epoll registration was actually added or modified or
135 false if the client was the currently registered client.
136 137 **************************************************************************/138 139 publicboolregister ( ISelectClientclient )
140 {
141 verify(client !isnull);
142 143 debug ( SelectFiber) Stderr.formatln("{}.register fd {}:",
144 typeof(this).stringof, client.fileHandle);
145 146 if ( this.currentisnull )
147 {
148 // No client is currently registered: Add an epoll registration for149 // the a new client.150 151 debug ( SelectFiber) Stderr.formatln(" Register new {}", client);
152 153 this.epoll.register(this.current = client);
154 155 returntrue;
156 }
157 elseif ( this.currentisclient )
158 {
159 // The currently registered client is used for another I/O160 // operation: Only refresh the timeout registration of the client,161 // no need to change the epoll registration.162 163 debug ( SelectFiber)
164 {
165 Stderr.formatln(" Leaving registered {}", this.current);
166 }
167 168 // As there is not way to modify a registration with the169 // timeout manager, it is necessary to call unregistered(), then170 // registered() even if this.current and client are identical. This171 // ensures that, even if the epoll registration doesn't need to be172 // updated, that the timeout timeout registration is updated173 // correctly.174 175 this.current.unregistered();
176 client.registered();
177 178 returnfalse;
179 }
180 elseif ( this.current.fileHandle == client.fileHandle )
181 {
182 // The currently registered client and the new client share the same183 // I/O device: Update the epoll registration of the I/O device to184 // the new client.185 186 debug ( SelectFiber)
187 {
188 Stderr.formatln(" Changing event registration {}",
189 this.current);
190 Stderr.formatln(" Register {}", client);
191 }
192 193 this.epoll.changeClient(this.current, client);
194 195 this.current = client;
196 197 returntrue;
198 }
199 else200 {
201 // The currently registered client and the new client have different202 // I/O devices: Unregister the epoll registration of the current203 // client and register the new client instead.204 205 debug ( SelectFiber) Stderr.formatln(" Unregister {}",
206 this.current);
207 208 this.epoll.unregister(this.current);
209 210 debug ( SelectFiber) Stderr.formatln(" Register {}", client);
211 212 this.epoll.register(this.current = client);
213 214 returntrue;
215 }
216 }
217 218 /**************************************************************************
219 220 Unegisters the current client from epoll and clears it, if any.
221 222 Returns:
223 true if the current client was unregistered or false if there was
224 no current client.
225 226 **************************************************************************/227 228 publicboolunregister ( )
229 {
230 if ( this.current !isnull )
231 {
232 debug ( SelectFiber) Stderr.formatln("{}.unregister fd {}",
233 typeof(this).stringof, this.current.fileHandle);
234 235 this.epoll.unregister(this.current);
236 this.current = null;
237 238 returntrue;
239 }
240 else241 {
242 returnfalse;
243 }
244 }
245 246 /**************************************************************************
247 248 Checks if client is identical to the current client.
249 Note that the client instance is compared, not the client conduit,
250 file descriptor or events.
251 252 Params:
253 client = client to compare for identity with the current client,
254 pass null to check if there is no current client.
255 256 Returns:
257 true if client is the current client or false otherwise.
258 259 **************************************************************************/260 261 publicboolisRegistered ( ISelectClientclient )
262 {
263 returnthis.currentisclient;
264 }
265 266 /**************************************************************************
267 268 Clears the current client; usually called from the client finalizer.
269 270 Note that the client does not need to be unregistered here, as the epoll
271 selector always unregisters the client after calling its finalizer.
272 273 Returns:
274 true if there actually was a current client or false otherwise.
275 276 **************************************************************************/277 278 publicboolclear ( )
279 {
280 scope (success) this.current = null;
281 282 returnthis.current !isnull;
283 }
284 285 /**************************************************************************
286 287 Returns:
288 informational interface to currently registered client (null if no
289 client is registered)
290 291 **************************************************************************/292 293 publicISelectClientInforegistered_client ( )
294 {
295 returnthis.current;
296 }
297 }
298 299