1 /*******************************************************************************
2 3 Handles a set of selected epoll keys and handles registered select clients
4 that timed out.
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.selector.TimeoutSelectedKeysHandler;
18 19 20 importocean.core.Verify;
21 22 importocean.io.select.selector.SelectedKeysHandler,
23 ocean.io.select.selector.EpollException;
24 25 importocean.sys.Epoll: epoll_event_t;
26 27 importocean.io.select.client.model.ISelectClient;
28 29 importocean.time.timeout.model.ITimeoutManager,
30 ocean.time.timeout.model.ITimeoutClient;
31 importocean.meta.types.Qualifiers;
32 33 importocean.util.container.AppendBuffer: AppendBuffer;
34 35 importcore.stdc.stdlib: bsearch, qsort;
36 37 debug (ISelectClient) importocean.io.Stdout;
38 39 /******************************************************************************/40 41 classTimeoutSelectedKeysHandler: SelectedKeysHandler42 {
43 /***************************************************************************
44 45 Timeout manager instance to obtain the timed out clients.
46 47 **************************************************************************/48 49 privateITimeoutManagertimeout_manager;
50 51 /***************************************************************************
52 53 Re-usable set of timed out clients. opCall() populates this list with
54 the timed out clients as reported by timeout_manager, unregisters and
55 finalizes all timed out clients, then handles the selected keys that are
56 not in the list.
57 58 **************************************************************************/59 60 privatealiasAppendBuffer!(ISelectClient) TimedOutClientList;
61 62 privateTimedOutClientListtimed_out_clients;
63 64 /***************************************************************************
65 66 Constructor.
67 68 Params:
69 unregister = callback delegate to remove a client registration,
70 must be available during the lifetime of this
71 instance
72 e = exception to keep and throw if an error event was
73 reported for a selected key
74 timeout_manager = timeout manager to obtain the timed out clients in
75 handle()
76 num_clients = an estimate of the number of clients that will be
77 registered. Used to preallocate the list of timed
78 out clients
79 80 ***************************************************************************/81 82 publicthis ( scopeUnregisterDgunregister, EpollExceptione,
83 ITimeoutManagertimeout_manager, uintnum_clients = 0 )
84 {
85 super(unregister, e);
86 87 this.timeout_manager = timeout_manager;
88 this.timed_out_clients = newTimedOutClientList(num_clients);
89 }
90 91 /***************************************************************************
92 93 Handles the clients in selected_set that did not time out, then reports
94 a timeout to the timed out clients and unregisters them.
95 96 Note that any timed out clients will *not* be handled, even if they have
97 an event fired. Instead they are finalized with status = timeout and
98 unregistered.
99 100 Params:
101 selected_set = the result list of epoll_wait()
102 unhandled_exception_hook = if not null, will be called each time
103 event call results in unhandled exception. May both rethrow
104 and consume exception instance after processing it.
105 106 ***************************************************************************/107 108 publicoverridevoidopCall ( epoll_event_t[] selected_set,
109 scopebooldelegate (Exception) unhandled_exception_hook )
110 {
111 if (this.timeout_manager.us_left < timeout_manager.us_left.max)
112 {
113 this.timeout_manager.checkTimeouts((ITimeoutClienttimeout_client)
114 {
115 autoclient = cast (ISelectClient)timeout_client;
116 117 verify(client !isnull, "timeout client is not a select client");
118 119 debug ( ISelectClient )
120 Stderr.formatln("{} :: Client timed out, unregistering", client).flush();
121 122 this.timed_out_clients ~= client;
123 124 returntrue;
125 });
126 127 autotimed_out_clients = this.timed_out_clients[];
128 129 if (timed_out_clients.length)
130 {
131 /*
132 * Handle the clients in the selected set that didn't time out.
133 * To do so, look up every timed out client in the selected set
134 * using bsearch and handle it if it didn't time.
135 * Using bsearch requires the list to be sorted.
136 */137 138 qsort(timed_out_clients.ptr, timed_out_clients.length,
139 timed_out_clients[0].sizeof, &cmpPtr!(false));
140 141 foreach (key; selected_set)
142 {
143 ISelectClientclient = cast (ISelectClient) key.data.ptr;
144 145 verify(client !isnull);
146 147 const(void)* typed_ptr = timed_out_clients.ptr;
148 if (!bsearch(cast (void*) client, typed_ptr,
149 timed_out_clients.length, timed_out_clients[0].sizeof, &cmpPtr!(true)))
150 {
151 this.handleSelectedKey(key, unhandled_exception_hook);
152 }
153 }
154 155 foreach ( client; this.timed_out_clients[] )
156 {
157 this.unregisterAndFinalize(client, client.FinalizeStatus.Timeout);
158 }
159 160 this.timed_out_clients.clear();
161 162 /*
163 * The selected set and the timed out clients are handled:
164 * We're done.
165 */166 167 return;
168 }
169 170 /*
171 * No client timed out: Handle the selected set normally.
172 */173 }
174 175 super.opCall(selected_set, unhandled_exception_hook);
176 }
177 178 /***************************************************************************
179 180 Compares the pointer referred to by a_ to that referred to by b_.
181 182 Params:
183 searching = false: a_ points to the pointer to compare (called from
184 qsort()), true: a_ is the pointer to compare (called
185 from bsearch).
186 a_ = either the pointer (searching = true) or a pointer to the
187 pointer (searching = false) to compare against the pointer
188 pointed to by b_
189 b_ = pointer to the pointer to compare against a_ or the pointer a_
190 points to
191 192 Returns:
193 a value greater 0 if a_ compares greater than b_, a value less than
194 0 if less or 0 if a_ and b_ compare equal.
195 196 ***************************************************************************/197 198 extern (C) privatestaticintcmpPtr ( boolsearching ) (
199 scopeconst(void*) a_,
200 scopeconst(void*) b_ )
201 {
202 staticif (searching)
203 {
204 aliasa_a;
205 }
206 else207 {
208 void* a = *cast (void**) a_;
209 }
210 211 void* b = *cast (void**) b_;
212 213 return (a >= b)? a > b : -1;
214 }
215 }