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, uint128_t& rUint128,
174 : const uint32_t timeout )
175 : {
176 : Record::Result result;
177 1 : if( !_impl->waitRequest( requestID, result, timeout ))
178 0 : return false;
179 :
180 1 : rUint128.high() = result.rUint128.high;
181 1 : rUint128.low() = result.rUint128.low;
182 1 : return true;
183 : }
184 :
185 1 : bool RequestHandler::waitRequest( const uint32_t requestID, bool& rBool,
186 : const uint32_t timeout )
187 : {
188 : Record::Result result;
189 1 : if( !_impl->waitRequest( requestID, result, timeout ))
190 0 : return false;
191 :
192 1 : rBool = result.rBool;
193 1 : return true;
194 : }
195 1 : bool RequestHandler::waitRequest( const uint32_t requestID )
196 : {
197 : Record::Result result;
198 1 : return _impl->waitRequest( requestID, result, LB_TIMEOUT_INDEFINITE );
199 : }
200 :
201 5 : void* RequestHandler::getRequestData( const uint32_t requestID )
202 : {
203 5 : ScopedFastWrite mutex( _impl->lock );
204 5 : RecordHashCIter i = _impl->requests.find( requestID );
205 5 : if( i == _impl->requests.end( ))
206 0 : return 0;
207 :
208 5 : return i->second->data;
209 : }
210 :
211 2 : void RequestHandler::serveRequest( const uint32_t requestID, void* result )
212 : {
213 2 : Record* request = 0;
214 : {
215 2 : ScopedFastWrite mutex( _impl->lock );
216 2 : RecordHashCIter i = _impl->requests.find( requestID );
217 :
218 2 : if( i != _impl->requests.end( ))
219 2 : request = i->second;
220 : }
221 2 : if( request )
222 : {
223 2 : request->result.rPointer = result;
224 2 : request->lock.unset();
225 : }
226 2 : }
227 :
228 1 : void RequestHandler::serveRequest( const uint32_t requestID, uint32_t result )
229 : {
230 1 : Record* request = 0;
231 : {
232 1 : ScopedFastWrite mutex( _impl->lock );
233 1 : RecordHashCIter i = _impl->requests.find( requestID );
234 :
235 1 : if( i != _impl->requests.end( ))
236 1 : request = i->second;
237 : }
238 1 : if( request )
239 : {
240 1 : request->result.rUint32 = result;
241 1 : request->lock.unset();
242 : }
243 1 : }
244 :
245 1 : void RequestHandler::serveRequest( const uint32_t requestID, bool result )
246 : {
247 1 : Record* request = 0;
248 : {
249 1 : ScopedFastWrite mutex( _impl->lock );
250 1 : RecordHashCIter i = _impl->requests.find( requestID );
251 :
252 1 : if( i != _impl->requests.end( ))
253 1 : request = i->second;
254 : }
255 1 : if( request )
256 : {
257 1 : request->result.rBool = result;
258 1 : request->lock.unset();
259 : }
260 1 : }
261 :
262 1 : void RequestHandler::serveRequest( const uint32_t requestID,
263 : const uint128_t& result )
264 : {
265 1 : Record* request = 0;
266 : {
267 1 : ScopedFastWrite mutex( _impl->lock );
268 1 : RecordHashCIter i = _impl->requests.find( requestID );
269 :
270 1 : if( i != _impl->requests.end( ))
271 1 : request = i->second;
272 : }
273 :
274 1 : if( request )
275 : {
276 1 : request->result.rUint128.low = result.low();
277 1 : request->result.rUint128.high = result.high();
278 1 : request->lock.unset();
279 : }
280 1 : }
281 :
282 1 : bool RequestHandler::isRequestReady( const uint32_t requestID ) const
283 : {
284 1 : ScopedFastWrite mutex( _impl->lock );
285 1 : RecordHashCIter i = _impl->requests.find( requestID );
286 1 : if( i == _impl->requests.end( ))
287 0 : return false;
288 :
289 1 : Record* request = i->second;
290 1 : return !request->lock.isSet();
291 : }
292 :
293 0 : bool RequestHandler::hasPendingRequests() const
294 : {
295 0 : return !_impl->requests.empty();
296 : }
297 :
298 0 : std::ostream& operator << ( std::ostream& os, const detail::RequestHandler& rh )
299 : {
300 0 : ScopedFastWrite mutex( rh.lock );
301 0 : for( RecordHashCIter i = rh.requests.begin(); i != rh.requests.end(); ++i )
302 : {
303 0 : os << "request " << i->first << " served " << i->second->lock.isSet()
304 0 : << std::endl;
305 : }
306 :
307 0 : return os;
308 : }
309 :
310 0 : std::ostream& operator << ( std::ostream& os, const RequestHandler& rh )
311 : {
312 0 : return os << *rh._impl;
313 : }
314 :
315 90 : }
|