Line data Source code
1 :
2 : /* Copyright (c) 2005-2016, Stefan Eilemann <eile@equalizergraphics.com>
3 : *
4 : * This library is free software; you can redistribute it and/or modify it under
5 : * the terms of the GNU Lesser General Public License version 2.1 as published
6 : * by the Free Software Foundation.
7 : *
8 : * This library is distributed in the hope that it will be useful, but WITHOUT
9 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
11 : * details.
12 : *
13 : * You should have received a copy of the GNU Lesser General Public License
14 : * along with this library; if not, write to the Free Software Foundation, Inc.,
15 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 : */
17 :
18 : #include "requestHandler.h"
19 :
20 : #include "scopedMutex.h"
21 :
22 : #include <lunchbox/debug.h>
23 : #include <lunchbox/stdExt.h>
24 : #include <lunchbox/spinLock.h>
25 : #include <lunchbox/timedLock.h>
26 :
27 : #include <list>
28 :
29 : namespace lunchbox
30 : {
31 : //! @cond IGNORE
32 : namespace
33 : {
34 : struct Record
35 : {
36 3 : Record() { lock.set(); }
37 3 : ~Record(){}
38 :
39 : TimedLock lock;
40 : void* data;
41 :
42 : union Result
43 : {
44 : void* rPointer;
45 : uint32_t rUint32;
46 : bool rBool;
47 : struct
48 : {
49 : uint64_t low;
50 : uint64_t high;
51 : } rUint128;
52 : } result;
53 : };
54 : typedef stde::hash_map< uint32_t, Record* > RecordHash;
55 : typedef RecordHash::const_iterator RecordHashCIter;
56 : }
57 :
58 : namespace detail
59 : {
60 1 : class RequestHandler
61 : {
62 : public:
63 1 : RequestHandler() : requestID( 1 ) {}
64 :
65 7 : uint32_t registerRequest( void* data )
66 : {
67 14 : ScopedFastWrite mutex( lock );
68 :
69 : Record* request;
70 7 : if( freeRecords.empty( ))
71 3 : request = new Record;
72 : else
73 : {
74 4 : request = freeRecords.front();
75 4 : freeRecords.pop_front();
76 : }
77 :
78 7 : request->data = data;
79 7 : requestID = ( requestID + 1 ) % LB_MAX_UINT32;
80 7 : requests[ requestID ] = request;
81 14 : return requestID;
82 : }
83 :
84 7 : bool waitRequest( const uint32_t requestID_, Record::Result& result,
85 : const uint32_t timeout )
86 : {
87 7 : result.rUint128.low = 0;
88 7 : result.rUint128.high = 0;
89 7 : Record* request = 0;
90 : {
91 14 : ScopedFastWrite mutex( lock );
92 7 : RecordHashCIter i = requests.find( requestID_ );
93 7 : if( i == requests.end( ))
94 0 : return false;
95 :
96 7 : request = i->second;
97 : }
98 :
99 7 : const bool requestServed = request->lock.set( timeout );
100 7 : if( requestServed )
101 : {
102 6 : result = request->result;
103 6 : unregisterRequest( requestID_ );
104 : }
105 :
106 7 : return requestServed;
107 : }
108 :
109 7 : void unregisterRequest( const uint32_t requestID_ )
110 : {
111 14 : ScopedFastWrite mutex( lock );
112 7 : RecordHash::iterator i = requests.find( requestID_ );
113 7 : if( i == requests.end( ))
114 0 : return;
115 :
116 7 : Record* request = i->second;
117 7 : requests.erase( i );
118 7 : freeRecords.push_front( request );
119 : }
120 :
121 : mutable lunchbox::SpinLock lock;
122 : uint32_t requestID;
123 : RecordHash requests;
124 : std::list<Record*> freeRecords;
125 : };
126 : }
127 : // @endcond
128 :
129 1 : RequestHandler::RequestHandler()
130 1 : : _impl( new detail::RequestHandler )
131 1 : {}
132 :
133 5 : RequestHandler::~RequestHandler()
134 : {
135 7 : while( !_impl->freeRecords.empty( ))
136 : {
137 3 : Record* request = _impl->freeRecords.front();
138 3 : _impl->freeRecords.pop_front();
139 3 : delete request;
140 : }
141 1 : delete _impl;
142 1 : }
143 :
144 7 : uint32_t RequestHandler::_register( void* data )
145 : {
146 7 : return _impl->registerRequest( data );
147 : }
148 :
149 1 : void RequestHandler::unregisterRequest( const uint32_t requestID )
150 : {
151 1 : _impl->unregisterRequest( requestID );
152 1 : }
153 :
154 3 : bool RequestHandler::waitRequest( const uint32_t requestID, void*& rPointer,
155 : const uint32_t timeout )
156 : {
157 : Record::Result result;
158 3 : if( !_impl->waitRequest( requestID, result, timeout ))
159 1 : return false;
160 :
161 2 : rPointer = result.rPointer;
162 2 : return true;
163 : }
164 1 : bool RequestHandler::waitRequest( const uint32_t requestID, uint32_t& rUint32,
165 : const uint32_t timeout )
166 : {
167 : Record::Result result;
168 1 : if( !_impl->waitRequest( requestID, result, timeout ))
169 0 : return false;
170 :
171 1 : rUint32 = result.rUint32;
172 1 : return true;
173 : }
174 :
175 1 : bool RequestHandler::waitRequest( const uint32_t requestID,
176 : servus::uint128_t& rUint128,
177 : const uint32_t timeout )
178 : {
179 : Record::Result result;
180 1 : if( !_impl->waitRequest( requestID, result, timeout ))
181 0 : return false;
182 :
183 1 : rUint128.high() = result.rUint128.high;
184 1 : rUint128.low() = result.rUint128.low;
185 1 : return true;
186 : }
187 :
188 1 : bool RequestHandler::waitRequest( const uint32_t requestID, bool& rBool,
189 : const uint32_t timeout )
190 : {
191 : Record::Result result;
192 1 : if( !_impl->waitRequest( requestID, result, timeout ))
193 0 : return false;
194 :
195 1 : rBool = result.rBool;
196 1 : return true;
197 : }
198 1 : bool RequestHandler::waitRequest( const uint32_t requestID )
199 : {
200 : Record::Result result;
201 1 : return _impl->waitRequest( requestID, result, LB_TIMEOUT_INDEFINITE );
202 : }
203 :
204 6 : void* RequestHandler::getRequestData( const uint32_t requestID )
205 : {
206 12 : ScopedFastWrite mutex( _impl->lock );
207 6 : RecordHashCIter i = _impl->requests.find( requestID );
208 6 : if( i == _impl->requests.end( ))
209 0 : return 0;
210 :
211 6 : return i->second->data;
212 : }
213 :
214 3 : void RequestHandler::serveRequest( const uint32_t requestID, void* result )
215 : {
216 3 : Record* request = 0;
217 : {
218 6 : ScopedFastWrite mutex( _impl->lock );
219 3 : RecordHashCIter i = _impl->requests.find( requestID );
220 :
221 3 : if( i != _impl->requests.end( ))
222 3 : request = i->second;
223 : }
224 3 : if( request )
225 : {
226 3 : request->result.rPointer = result;
227 3 : request->lock.unset();
228 : }
229 3 : }
230 :
231 1 : void RequestHandler::serveRequest( const uint32_t requestID, uint32_t result )
232 : {
233 1 : Record* request = 0;
234 : {
235 2 : ScopedFastWrite mutex( _impl->lock );
236 1 : RecordHashCIter i = _impl->requests.find( requestID );
237 :
238 1 : if( i != _impl->requests.end( ))
239 1 : request = i->second;
240 : }
241 1 : if( request )
242 : {
243 1 : request->result.rUint32 = result;
244 1 : request->lock.unset();
245 : }
246 1 : }
247 :
248 1 : void RequestHandler::serveRequest( const uint32_t requestID, bool result )
249 : {
250 1 : Record* request = 0;
251 : {
252 2 : ScopedFastWrite mutex( _impl->lock );
253 1 : RecordHashCIter i = _impl->requests.find( requestID );
254 :
255 1 : if( i != _impl->requests.end( ))
256 1 : request = i->second;
257 : }
258 1 : if( request )
259 : {
260 1 : request->result.rBool = result;
261 1 : request->lock.unset();
262 : }
263 1 : }
264 :
265 1 : void RequestHandler::serveRequest( const uint32_t requestID,
266 : const servus::uint128_t& result )
267 : {
268 1 : Record* request = 0;
269 : {
270 2 : ScopedFastWrite mutex( _impl->lock );
271 1 : RecordHashCIter i = _impl->requests.find( requestID );
272 :
273 1 : if( i != _impl->requests.end( ))
274 1 : request = i->second;
275 : }
276 :
277 1 : if( request )
278 : {
279 1 : request->result.rUint128.low = result.low();
280 1 : request->result.rUint128.high = result.high();
281 1 : request->lock.unset();
282 : }
283 1 : }
284 :
285 1 : bool RequestHandler::isRequestReady( const uint32_t requestID ) const
286 : {
287 2 : ScopedFastWrite mutex( _impl->lock );
288 1 : RecordHashCIter i = _impl->requests.find( requestID );
289 1 : if( i == _impl->requests.end( ))
290 0 : return false;
291 :
292 1 : Record* request = i->second;
293 1 : return !request->lock.isSet();
294 : }
295 :
296 2 : bool RequestHandler::hasPendingRequests() const
297 : {
298 2 : return !_impl->requests.empty();
299 : }
300 :
301 0 : std::ostream& operator << ( std::ostream& os, const detail::RequestHandler& rh )
302 : {
303 0 : ScopedFastWrite mutex( rh.lock );
304 0 : for( RecordHashCIter i = rh.requests.begin(); i != rh.requests.end(); ++i )
305 : {
306 0 : os << "request " << i->first << " served " << i->second->lock.isSet()
307 0 : << std::endl;
308 : }
309 :
310 0 : return os;
311 : }
312 :
313 0 : std::ostream& operator << ( std::ostream& os, const RequestHandler& rh )
314 : {
315 0 : return os << *rh._impl;
316 : }
317 :
318 72 : }
|