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 module ocean.io.select.selector.TimeoutSelectedKeysHandler; 18 19 20 import ocean.core.Verify; 21 22 import ocean.io.select.selector.SelectedKeysHandler, 23 ocean.io.select.selector.EpollException; 24 25 import ocean.sys.Epoll: epoll_event_t; 26 27 import ocean.io.select.client.model.ISelectClient; 28 29 import ocean.time.timeout.model.ITimeoutManager, 30 ocean.time.timeout.model.ITimeoutClient; 31 import ocean.meta.types.Qualifiers; 32 33 import ocean.util.container.AppendBuffer: AppendBuffer; 34 35 import core.stdc.stdlib: bsearch, qsort; 36 37 debug (ISelectClient) import ocean.io.Stdout; 38 39 /******************************************************************************/ 40 41 class TimeoutSelectedKeysHandler: SelectedKeysHandler 42 { 43 /*************************************************************************** 44 45 Timeout manager instance to obtain the timed out clients. 46 47 **************************************************************************/ 48 49 private ITimeoutManager timeout_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 private alias AppendBuffer!(ISelectClient) TimedOutClientList; 61 62 private TimedOutClientList timed_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 public this ( scope UnregisterDg unregister, EpollException e, 83 ITimeoutManager timeout_manager, uint num_clients = 0 ) 84 { 85 super(unregister, e); 86 87 this.timeout_manager = timeout_manager; 88 this.timed_out_clients = new TimedOutClientList(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 public override void opCall ( epoll_event_t[] selected_set, 109 scope bool delegate (Exception) unhandled_exception_hook ) 110 { 111 if (this.timeout_manager.us_left < timeout_manager.us_left.max) 112 { 113 this.timeout_manager.checkTimeouts((ITimeoutClient timeout_client) 114 { 115 auto client = cast (ISelectClient)timeout_client; 116 117 verify(client !is null, "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 return true; 125 }); 126 127 auto timed_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 ISelectClient client = cast (ISelectClient) key.data.ptr; 144 145 verify(client !is null); 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) private static int cmpPtr ( bool searching ) ( 199 scope const(void*) a_, 200 scope const(void*) b_ ) 201 { 202 static if (searching) 203 { 204 alias a_ a; 205 } 206 else 207 { 208 void* a = *cast (void**) a_; 209 } 210 211 void* b = *cast (void**) b_; 212 213 return (a >= b)? a > b : -1; 214 } 215 }