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 : const bool requestServed =
100 7 : request->lock.try_lock_for(std::chrono::milliseconds(timeout));
101 7 : if (requestServed)
102 : {
103 6 : result = request->result;
104 6 : unregisterRequest(requestID_);
105 : }
106 :
107 7 : return requestServed;
108 : }
109 :
110 7 : void unregisterRequest(const uint32_t requestID_)
111 : {
112 14 : ScopedFastWrite mutex(lock);
113 7 : RecordHash::iterator i = requests.find(requestID_);
114 7 : if (i == requests.end())
115 0 : return;
116 :
117 7 : Record* request = i->second;
118 7 : requests.erase(i);
119 7 : freeRecords.push_front(request);
120 : }
121 :
122 : mutable lunchbox::SpinLock lock;
123 : uint32_t requestID;
124 : RecordHash requests;
125 : std::list<Record*> freeRecords;
126 : };
127 : }
128 : // @endcond
129 :
130 1 : RequestHandler::RequestHandler()
131 1 : : _impl(new detail::RequestHandler)
132 : {
133 1 : }
134 :
135 5 : RequestHandler::~RequestHandler()
136 : {
137 7 : while (!_impl->freeRecords.empty())
138 : {
139 3 : Record* request = _impl->freeRecords.front();
140 3 : _impl->freeRecords.pop_front();
141 3 : delete request;
142 : }
143 1 : delete _impl;
144 1 : }
145 :
146 7 : uint32_t RequestHandler::_register(void* data)
147 : {
148 7 : return _impl->registerRequest(data);
149 : }
150 :
151 1 : void RequestHandler::unregisterRequest(const uint32_t requestID)
152 : {
153 1 : _impl->unregisterRequest(requestID);
154 1 : }
155 :
156 3 : bool RequestHandler::waitRequest(const uint32_t requestID, void*& rPointer,
157 : const uint32_t timeout)
158 : {
159 : Record::Result result;
160 3 : if (!_impl->waitRequest(requestID, result, timeout))
161 1 : return false;
162 :
163 2 : rPointer = result.rPointer;
164 2 : return true;
165 : }
166 1 : bool RequestHandler::waitRequest(const uint32_t requestID, uint32_t& rUint32,
167 : const uint32_t timeout)
168 : {
169 : Record::Result result;
170 1 : if (!_impl->waitRequest(requestID, result, timeout))
171 0 : return false;
172 :
173 1 : rUint32 = result.rUint32;
174 1 : return true;
175 : }
176 :
177 1 : bool RequestHandler::waitRequest(const uint32_t requestID,
178 : servus::uint128_t& rUint128,
179 : const uint32_t timeout)
180 : {
181 : Record::Result result;
182 1 : if (!_impl->waitRequest(requestID, result, timeout))
183 0 : return false;
184 :
185 1 : rUint128.high() = result.rUint128.high;
186 1 : rUint128.low() = result.rUint128.low;
187 1 : return true;
188 : }
189 :
190 1 : bool RequestHandler::waitRequest(const uint32_t requestID, bool& rBool,
191 : const uint32_t timeout)
192 : {
193 : Record::Result result;
194 1 : if (!_impl->waitRequest(requestID, result, timeout))
195 0 : return false;
196 :
197 1 : rBool = result.rBool;
198 1 : return true;
199 : }
200 1 : bool RequestHandler::waitRequest(const uint32_t requestID)
201 : {
202 : Record::Result result;
203 1 : return _impl->waitRequest(requestID, result, LB_TIMEOUT_INDEFINITE);
204 : }
205 :
206 6 : void* RequestHandler::getRequestData(const uint32_t requestID)
207 : {
208 12 : ScopedFastWrite mutex(_impl->lock);
209 6 : RecordHashCIter i = _impl->requests.find(requestID);
210 6 : if (i == _impl->requests.end())
211 0 : return 0;
212 :
213 6 : return i->second->data;
214 : }
215 :
216 3 : void RequestHandler::serveRequest(const uint32_t requestID, void* result)
217 : {
218 3 : Record* request = 0;
219 : {
220 6 : ScopedFastWrite mutex(_impl->lock);
221 3 : RecordHashCIter i = _impl->requests.find(requestID);
222 :
223 3 : if (i != _impl->requests.end())
224 3 : request = i->second;
225 : }
226 3 : if (request)
227 : {
228 3 : request->result.rPointer = result;
229 3 : request->lock.unlock();
230 : }
231 3 : }
232 :
233 1 : void RequestHandler::serveRequest(const uint32_t requestID, uint32_t result)
234 : {
235 1 : Record* request = 0;
236 : {
237 2 : ScopedFastWrite mutex(_impl->lock);
238 1 : RecordHashCIter i = _impl->requests.find(requestID);
239 :
240 1 : if (i != _impl->requests.end())
241 1 : request = i->second;
242 : }
243 1 : if (request)
244 : {
245 1 : request->result.rUint32 = result;
246 1 : request->lock.unlock();
247 : }
248 1 : }
249 :
250 1 : void RequestHandler::serveRequest(const uint32_t requestID, bool result)
251 : {
252 1 : Record* request = 0;
253 : {
254 2 : ScopedFastWrite mutex(_impl->lock);
255 1 : RecordHashCIter i = _impl->requests.find(requestID);
256 :
257 1 : if (i != _impl->requests.end())
258 1 : request = i->second;
259 : }
260 1 : if (request)
261 : {
262 1 : request->result.rBool = result;
263 1 : request->lock.unlock();
264 : }
265 1 : }
266 :
267 1 : void RequestHandler::serveRequest(const uint32_t requestID,
268 : const servus::uint128_t& result)
269 : {
270 1 : Record* request = 0;
271 : {
272 2 : ScopedFastWrite mutex(_impl->lock);
273 1 : RecordHashCIter i = _impl->requests.find(requestID);
274 :
275 1 : if (i != _impl->requests.end())
276 1 : request = i->second;
277 : }
278 :
279 1 : if (request)
280 : {
281 1 : request->result.rUint128.low = result.low();
282 1 : request->result.rUint128.high = result.high();
283 1 : request->lock.unlock();
284 : }
285 1 : }
286 :
287 1 : bool RequestHandler::isRequestReady(const uint32_t requestID) const
288 : {
289 2 : ScopedFastWrite mutex(_impl->lock);
290 1 : RecordHashCIter i = _impl->requests.find(requestID);
291 1 : if (i == _impl->requests.end())
292 0 : return false;
293 :
294 1 : Record* request = i->second;
295 1 : const bool isReady = request->lock.try_lock();
296 1 : if (isReady)
297 1 : request->lock.unlock();
298 1 : return isReady;
299 : }
300 :
301 2 : bool RequestHandler::hasPendingRequests() const
302 : {
303 2 : return !_impl->requests.empty();
304 : }
305 75 : }
|