Line data Source code
1 :
2 : /* Copyright (c) 2005-2014, 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 5 : uint32_t registerRequest( void* data )
66 : {
67 5 : ScopedFastWrite mutex( lock );
68 :
69 : Record* request;
70 5 : if( freeRecords.empty( ))
71 3 : request = new Record;
72 : else
73 : {
74 2 : request = freeRecords.front();
75 2 : freeRecords.pop_front();
76 : }
77 :
78 5 : request->data = data;
79 5 : requestID = ( requestID + 1 ) % LB_MAX_UINT32;
80 5 : requests[ requestID ] = request;
81 5 : return requestID;
82 : }
83 :
84 5 : bool waitRequest( const uint32_t requestID_, Record::Result& result,
85 : const uint32_t timeout )
86 : {
87 5 : result.rUint128.low = 0;
88 5 : result.rUint128.high = 0;
89 5 : Record* request = 0;
90 : {
91 5 : ScopedFastWrite mutex( lock );
92 5 : RecordHashCIter i = requests.find( requestID_ );
93 5 : if( i == requests.end( ))
94 0 : return false;
95 :
96 5 : request = i->second;
97 : }
98 :
99 5 : const bool requestServed = request->lock.set( timeout );
100 5 : if( requestServed )
101 5 : result = request->result;
102 :
103 5 : unregisterRequest( requestID_ );
104 5 : return requestServed;
105 : }
106 :
107 5 : void unregisterRequest( const uint32_t requestID_ )
108 : {
109 5 : ScopedFastWrite mutex( lock );
110 5 : RecordHash::iterator i = requests.find( requestID_ );
111 5 : if( i == requests.end( ))
112 5 : return;
113 :
114 5 : Record* request = i->second;
115 5 : requests.erase( i );
116 5 : freeRecords.push_front( request );
117 : }
118 :
119 : mutable lunchbox::SpinLock lock;
120 : uint32_t requestID;
121 : RecordHash requests;
122 : std::list<Record*> freeRecords;
123 : };
124 : }
125 : // @endcond
126 :
127 1 : RequestHandler::RequestHandler()
128 1 : : _impl( new detail::RequestHandler )
129 1 : {}
130 :
131 2 : RequestHandler::~RequestHandler()
132 : {
133 5 : while( !_impl->freeRecords.empty( ))
134 : {
135 3 : Record* request = _impl->freeRecords.front();
136 3 : _impl->freeRecords.pop_front();
137 3 : delete request;
138 : }
139 1 : delete _impl;
140 1 : }
141 :
142 5 : uint32_t RequestHandler::_register( void* data )
143 : {
144 5 : return _impl->registerRequest( data );
145 : }
146 :
147 0 : void RequestHandler::unregisterRequest( const uint32_t requestID )
148 : {
149 0 : _impl->unregisterRequest( requestID );
150 0 : }
151 :
152 1 : bool RequestHandler::waitRequest( const uint32_t requestID, void*& rPointer,
153 : const uint32_t timeout )
154 : {
155 : Record::Result result;
156 1 : if( !_impl->waitRequest( requestID, result, timeout ))
157 0 : return false;
158 :
159 1 : rPointer = result.rPointer;
160 1 : return true;
161 : }
162 1 : bool RequestHandler::waitRequest( const uint32_t requestID, uint32_t& rUint32,
163 : const uint32_t timeout )
164 : {
165 : Record::Result result;
166 1 : if( !_impl->waitRequest( requestID, result, timeout ))
167 0 : return false;
168 :
169 1 : rUint32 = result.rUint32;
170 1 : return true;
171 : }
172 :
173 1 : bool RequestHandler::waitRequest( const uint32_t requestID,
174 : servus::uint128_t& rUint128,
175 : const uint32_t timeout )
176 : {
177 : Record::Result result;
178 1 : if( !_impl->waitRequest( requestID, result, timeout ))
179 0 : return false;
180 :
181 1 : rUint128.high() = result.rUint128.high;
182 1 : rUint128.low() = result.rUint128.low;
183 1 : return true;
184 : }
185 :
186 1 : bool RequestHandler::waitRequest( const uint32_t requestID, bool& rBool,
187 : const uint32_t timeout )
188 : {
189 : Record::Result result;
190 1 : if( !_impl->waitRequest( requestID, result, timeout ))
191 0 : return false;
192 :
193 1 : rBool = result.rBool;
194 1 : return true;
195 : }
196 1 : bool RequestHandler::waitRequest( const uint32_t requestID )
197 : {
198 : Record::Result result;
199 1 : return _impl->waitRequest( requestID, result, LB_TIMEOUT_INDEFINITE );
200 : }
201 :
202 5 : void* RequestHandler::getRequestData( const uint32_t requestID )
203 : {
204 5 : ScopedFastWrite mutex( _impl->lock );
205 5 : RecordHashCIter i = _impl->requests.find( requestID );
206 5 : if( i == _impl->requests.end( ))
207 0 : return 0;
208 :
209 5 : return i->second->data;
210 : }
211 :
212 2 : void RequestHandler::serveRequest( const uint32_t requestID, void* result )
213 : {
214 2 : Record* request = 0;
215 : {
216 2 : ScopedFastWrite mutex( _impl->lock );
217 2 : RecordHashCIter i = _impl->requests.find( requestID );
218 :
219 2 : if( i != _impl->requests.end( ))
220 2 : request = i->second;
221 : }
222 2 : if( request )
223 : {
224 2 : request->result.rPointer = result;
225 2 : request->lock.unset();
226 : }
227 2 : }
228 :
229 1 : void RequestHandler::serveRequest( const uint32_t requestID, uint32_t result )
230 : {
231 1 : Record* request = 0;
232 : {
233 1 : ScopedFastWrite mutex( _impl->lock );
234 1 : RecordHashCIter i = _impl->requests.find( requestID );
235 :
236 1 : if( i != _impl->requests.end( ))
237 1 : request = i->second;
238 : }
239 1 : if( request )
240 : {
241 1 : request->result.rUint32 = result;
242 1 : request->lock.unset();
243 : }
244 1 : }
245 :
246 1 : void RequestHandler::serveRequest( const uint32_t requestID, bool result )
247 : {
248 1 : Record* request = 0;
249 : {
250 1 : ScopedFastWrite mutex( _impl->lock );
251 1 : RecordHashCIter i = _impl->requests.find( requestID );
252 :
253 1 : if( i != _impl->requests.end( ))
254 1 : request = i->second;
255 : }
256 1 : if( request )
257 : {
258 1 : request->result.rBool = result;
259 1 : request->lock.unset();
260 : }
261 1 : }
262 :
263 1 : void RequestHandler::serveRequest( const uint32_t requestID,
264 : const servus::uint128_t& result )
265 : {
266 1 : Record* request = 0;
267 : {
268 1 : ScopedFastWrite mutex( _impl->lock );
269 1 : RecordHashCIter i = _impl->requests.find( requestID );
270 :
271 1 : if( i != _impl->requests.end( ))
272 1 : request = i->second;
273 : }
274 :
275 1 : if( request )
276 : {
277 1 : request->result.rUint128.low = result.low();
278 1 : request->result.rUint128.high = result.high();
279 1 : request->lock.unset();
280 : }
281 1 : }
282 :
283 1 : bool RequestHandler::isRequestReady( const uint32_t requestID ) const
284 : {
285 1 : ScopedFastWrite mutex( _impl->lock );
286 1 : RecordHashCIter i = _impl->requests.find( requestID );
287 1 : if( i == _impl->requests.end( ))
288 0 : return false;
289 :
290 1 : Record* request = i->second;
291 1 : return !request->lock.isSet();
292 : }
293 :
294 0 : bool RequestHandler::hasPendingRequests() const
295 : {
296 0 : return !_impl->requests.empty();
297 : }
298 :
299 0 : std::ostream& operator << ( std::ostream& os, const detail::RequestHandler& rh )
300 : {
301 0 : ScopedFastWrite mutex( rh.lock );
302 0 : for( RecordHashCIter i = rh.requests.begin(); i != rh.requests.end(); ++i )
303 : {
304 0 : os << "request " << i->first << " served " << i->second->lock.isSet()
305 0 : << std::endl;
306 : }
307 :
308 0 : return os;
309 : }
310 :
311 0 : std::ostream& operator << ( std::ostream& os, const RequestHandler& rh )
312 : {
313 0 : return os << *rh._impl;
314 : }
315 :
316 81 : }
|