Line data Source code
1 :
2 : /* Copyright (c) 2005-2017, 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/spinLock.h>
24 :
25 : #include <list>
26 : #include <unordered_map>
27 :
28 : namespace lunchbox
29 : {
30 : //! @cond IGNORE
31 : namespace
32 : {
33 : struct Record
34 : {
35 3 : Record() { lock.lock(); }
36 3 : ~Record() {}
37 : std::timed_mutex lock;
38 : void* data;
39 :
40 : union Result {
41 : void* rPointer;
42 : uint32_t rUint32;
43 : bool rBool;
44 : struct
45 : {
46 : uint64_t low;
47 : uint64_t high;
48 : } rUint128;
49 : } result;
50 : };
51 : typedef std::unordered_map<uint32_t, Record*> RecordHash;
52 : typedef RecordHash::const_iterator RecordHashCIter;
53 : }
54 :
55 : namespace detail
56 : {
57 1 : class RequestHandler
58 : {
59 : public:
60 1 : RequestHandler()
61 1 : : requestID(1)
62 : {
63 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 : if (timeout == LB_TIMEOUT_INDEFINITE) // opt
100 : {
101 6 : request->lock.lock();
102 6 : result = request->result;
103 6 : unregisterRequest(requestID_);
104 6 : return true;
105 : }
106 :
107 : const bool requestServed =
108 1 : request->lock.try_lock_for(std::chrono::milliseconds(timeout));
109 1 : if (requestServed)
110 : {
111 0 : result = request->result;
112 0 : unregisterRequest(requestID_);
113 : }
114 :
115 1 : return requestServed;
116 : }
117 :
118 7 : void unregisterRequest(const uint32_t requestID_)
119 : {
120 14 : ScopedFastWrite mutex(lock);
121 7 : RecordHash::iterator i = requests.find(requestID_);
122 7 : if (i == requests.end())
123 0 : return;
124 :
125 7 : Record* request = i->second;
126 7 : requests.erase(i);
127 7 : freeRecords.push_front(request);
128 : }
129 :
130 : mutable lunchbox::SpinLock lock;
131 : uint32_t requestID;
132 : RecordHash requests;
133 : std::list<Record*> freeRecords;
134 : };
135 : }
136 : // @endcond
137 :
138 1 : RequestHandler::RequestHandler()
139 1 : : _impl(new detail::RequestHandler)
140 : {
141 1 : }
142 :
143 5 : RequestHandler::~RequestHandler()
144 : {
145 7 : while (!_impl->freeRecords.empty())
146 : {
147 3 : Record* request = _impl->freeRecords.front();
148 3 : _impl->freeRecords.pop_front();
149 3 : delete request;
150 : }
151 1 : delete _impl;
152 1 : }
153 :
154 7 : uint32_t RequestHandler::_register(void* data)
155 : {
156 7 : return _impl->registerRequest(data);
157 : }
158 :
159 1 : void RequestHandler::unregisterRequest(const uint32_t requestID)
160 : {
161 1 : _impl->unregisterRequest(requestID);
162 1 : }
163 :
164 3 : bool RequestHandler::waitRequest(const uint32_t requestID, void*& rPointer,
165 : const uint32_t timeout)
166 : {
167 : Record::Result result;
168 3 : if (!_impl->waitRequest(requestID, result, timeout))
169 1 : return false;
170 :
171 2 : rPointer = result.rPointer;
172 2 : return true;
173 : }
174 1 : bool RequestHandler::waitRequest(const uint32_t requestID, uint32_t& rUint32,
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 : rUint32 = result.rUint32;
182 1 : return true;
183 : }
184 :
185 1 : bool RequestHandler::waitRequest(const uint32_t requestID,
186 : servus::uint128_t& rUint128,
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 : rUint128.high() = result.rUint128.high;
194 1 : rUint128.low() = result.rUint128.low;
195 1 : return true;
196 : }
197 :
198 1 : bool RequestHandler::waitRequest(const uint32_t requestID, bool& rBool,
199 : const uint32_t timeout)
200 : {
201 : Record::Result result;
202 1 : if (!_impl->waitRequest(requestID, result, timeout))
203 0 : return false;
204 :
205 1 : rBool = result.rBool;
206 1 : return true;
207 : }
208 :
209 1 : bool RequestHandler::waitRequest(const uint32_t requestID)
210 : {
211 : Record::Result result;
212 1 : return _impl->waitRequest(requestID, result, LB_TIMEOUT_INDEFINITE);
213 : }
214 :
215 6 : void* RequestHandler::getRequestData(const uint32_t requestID)
216 : {
217 12 : ScopedFastWrite mutex(_impl->lock);
218 6 : RecordHashCIter i = _impl->requests.find(requestID);
219 6 : if (i == _impl->requests.end())
220 0 : return 0;
221 :
222 6 : return i->second->data;
223 : }
224 :
225 3 : void RequestHandler::serveRequest(const uint32_t requestID, void* result)
226 : {
227 3 : Record* request = 0;
228 : {
229 6 : ScopedFastWrite mutex(_impl->lock);
230 3 : RecordHashCIter i = _impl->requests.find(requestID);
231 :
232 3 : if (i != _impl->requests.end())
233 3 : request = i->second;
234 : }
235 3 : if (request)
236 : {
237 3 : request->result.rPointer = result;
238 3 : request->lock.unlock();
239 : }
240 3 : }
241 :
242 1 : void RequestHandler::serveRequest(const uint32_t requestID, uint32_t result)
243 : {
244 1 : Record* request = 0;
245 : {
246 2 : ScopedFastWrite mutex(_impl->lock);
247 1 : RecordHashCIter i = _impl->requests.find(requestID);
248 :
249 1 : if (i != _impl->requests.end())
250 1 : request = i->second;
251 : }
252 1 : if (request)
253 : {
254 1 : request->result.rUint32 = result;
255 1 : request->lock.unlock();
256 : }
257 1 : }
258 :
259 1 : void RequestHandler::serveRequest(const uint32_t requestID, bool result)
260 : {
261 1 : Record* request = 0;
262 : {
263 2 : ScopedFastWrite mutex(_impl->lock);
264 1 : RecordHashCIter i = _impl->requests.find(requestID);
265 :
266 1 : if (i != _impl->requests.end())
267 1 : request = i->second;
268 : }
269 1 : if (request)
270 : {
271 1 : request->result.rBool = result;
272 1 : request->lock.unlock();
273 : }
274 1 : }
275 :
276 1 : void RequestHandler::serveRequest(const uint32_t requestID,
277 : const servus::uint128_t& result)
278 : {
279 1 : Record* request = 0;
280 : {
281 2 : ScopedFastWrite mutex(_impl->lock);
282 1 : RecordHashCIter i = _impl->requests.find(requestID);
283 :
284 1 : if (i != _impl->requests.end())
285 1 : request = i->second;
286 : }
287 :
288 1 : if (request)
289 : {
290 1 : request->result.rUint128.low = result.low();
291 1 : request->result.rUint128.high = result.high();
292 1 : request->lock.unlock();
293 : }
294 1 : }
295 :
296 1 : bool RequestHandler::isRequestReady(const uint32_t requestID) const
297 : {
298 2 : ScopedFastWrite mutex(_impl->lock);
299 1 : RecordHashCIter i = _impl->requests.find(requestID);
300 1 : if (i == _impl->requests.end())
301 0 : return false;
302 :
303 1 : Record* request = i->second;
304 1 : const bool isReady = request->lock.try_lock();
305 1 : if (isReady)
306 1 : request->lock.unlock();
307 1 : return isReady;
308 : }
309 :
310 2 : bool RequestHandler::hasPendingRequests() const
311 : {
312 2 : return !_impl->requests.empty();
313 : }
314 75 : }
|