Line data Source code
1 :
2 : /* Copyright (c) 2013-2015, Stefan.Eilemann@epfl.ch
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 : #ifndef LUNCHBOX_REQUEST_H
19 : #define LUNCHBOX_REQUEST_H
20 :
21 : #include <boost/mpl/if.hpp>
22 : #include <boost/type_traits/is_same.hpp>
23 : #include <lunchbox/future.h>
24 :
25 : namespace lunchbox
26 : {
27 1 : class UnregisteredRequest : public std::runtime_error
28 : {
29 : public:
30 1 : UnregisteredRequest()
31 1 : : std::runtime_error("wait on an unregistered request")
32 : {
33 1 : }
34 : };
35 :
36 : /**
37 : * A Future implementation for a RequestHandler request.
38 : * @version 1.9.1
39 : */
40 : template <class T>
41 : class Request : public Future<T>
42 : {
43 : class Impl;
44 :
45 : public:
46 : /** Construct a new request. */
47 : Request(RequestHandler& handler, const uint32_t request);
48 :
49 : /**
50 : * Destruct and wait for completion of the request, unless relinquished.
51 : * @version 1.9.1
52 : */
53 : virtual ~Request();
54 :
55 : /** @return the identifier of the request. @version 1.9.1 */
56 : uint32_t getID() const;
57 :
58 : /**
59 : * Unregister this request from the request handler.
60 : *
61 : * If called, wait will not be called at destruction and wait() will throw.
62 : * If the future has already been resolved this function has no effect.
63 : * @version 1.13
64 : */
65 : void unregister();
66 : };
67 : } // namespace lunchbox
68 :
69 : // Implementation: Here be dragons
70 :
71 : #include <lunchbox/requestHandler.h>
72 : namespace lunchbox
73 : {
74 : template <class T>
75 : class Request<T>::Impl : public FutureImpl<T>
76 : {
77 : typedef typename boost::mpl::if_<boost::is_same<T, void>, void*, T>::type
78 : value_t;
79 :
80 : public:
81 5 : Impl(RequestHandler& handler, const uint32_t req)
82 : : request(req)
83 : , result(0)
84 : , handler_(handler)
85 5 : , state_(UNRESOLVED)
86 : {
87 5 : }
88 10 : virtual ~Impl() {}
89 : const uint32_t request;
90 : value_t result;
91 :
92 1 : void unregister()
93 : {
94 1 : if (state_ == UNRESOLVED)
95 : {
96 1 : state_ = UNREGISTERED;
97 1 : handler_.unregisterRequest(request);
98 : }
99 1 : }
100 :
101 5 : bool isUnresolved() const { return state_ == UNRESOLVED; }
102 :
103 : protected:
104 3 : T wait(const uint32_t timeout) final
105 : {
106 3 : switch (state_)
107 : {
108 : case UNREGISTERED:
109 0 : throw UnregisteredRequest();
110 : case UNRESOLVED:
111 2 : if (!handler_.waitRequest(request, result, timeout))
112 0 : throw FutureTimeout();
113 2 : state_ = DONE;
114 2 : break;
115 : case DONE:
116 : default:
117 1 : break;
118 : }
119 3 : return result;
120 : }
121 :
122 1 : bool isReady() const final
123 : {
124 1 : switch (state_)
125 : {
126 : case UNRESOLVED:
127 1 : return handler_.isRequestReady(request);
128 : case UNREGISTERED:
129 0 : return false;
130 : default: // DONE:
131 0 : return true;
132 : }
133 : }
134 :
135 : private:
136 : RequestHandler& handler_;
137 : enum State
138 : {
139 : UNRESOLVED,
140 : DONE,
141 : UNREGISTERED
142 : };
143 : State state_;
144 : };
145 :
146 : template <>
147 4 : inline void Request<void>::Impl::wait(const uint32_t timeout)
148 : {
149 4 : switch (state_)
150 : {
151 : case UNREGISTERED:
152 1 : throw UnregisteredRequest();
153 : case UNRESOLVED:
154 3 : if (!handler_.waitRequest(request, result, timeout))
155 1 : throw FutureTimeout();
156 2 : state_ = DONE;
157 : // No break
158 : case DONE:;
159 : }
160 2 : }
161 :
162 : template <class T>
163 5 : inline Request<T>::Request(RequestHandler& handler, const uint32_t request)
164 5 : : Future<T>(new Impl(handler, request))
165 : {
166 5 : }
167 :
168 : template <class T>
169 5 : inline Request<T>::~Request()
170 : {
171 5 : if (static_cast<const Impl*>(this->impl_.get())->isUnresolved())
172 1 : this->wait();
173 10 : }
174 :
175 : template <class T>
176 4 : inline uint32_t Request<T>::getID() const
177 : {
178 4 : return static_cast<const Impl*>(this->impl_.get())->request;
179 : }
180 :
181 : template <class T>
182 1 : inline void Request<T>::unregister()
183 : {
184 1 : static_cast<Impl*>(this->impl_.get())->unregister();
185 1 : }
186 : } // namespace lunchbox
187 :
188 : #endif // LUNCHBOX_REQUEST_H
|