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 : }
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 : protected:
103 3 : T wait(const uint32_t timeout) final
104 : {
105 3 : switch (state_)
106 : {
107 : case UNREGISTERED:
108 0 : throw UnregisteredRequest();
109 : case UNRESOLVED:
110 2 : if (!handler_.waitRequest(request, result, timeout))
111 0 : throw FutureTimeout();
112 2 : state_ = DONE;
113 : // No break
114 : default: // DONE
115 3 : return result;
116 : }
117 : }
118 :
119 1 : bool isReady() const final
120 : {
121 1 : switch (state_)
122 : {
123 : case UNRESOLVED:
124 1 : return handler_.isRequestReady(request);
125 : case UNREGISTERED:
126 0 : return false;
127 : default: // DONE:
128 0 : return true;
129 : }
130 : }
131 :
132 : private:
133 : RequestHandler& handler_;
134 : enum State
135 : {
136 : UNRESOLVED,
137 : DONE,
138 : UNREGISTERED
139 : };
140 : State state_;
141 : };
142 :
143 : template <>
144 4 : inline void Request<void>::Impl::wait(const uint32_t timeout)
145 : {
146 4 : switch (state_)
147 : {
148 : case UNREGISTERED:
149 1 : throw UnregisteredRequest();
150 : case UNRESOLVED:
151 3 : if (!handler_.waitRequest(request, result, timeout))
152 1 : throw FutureTimeout();
153 2 : state_ = DONE;
154 : // No break
155 : case DONE:;
156 : }
157 2 : }
158 :
159 : template <class T>
160 5 : inline Request<T>::Request(RequestHandler& handler, const uint32_t request)
161 5 : : Future<T>(new Impl(handler, request))
162 : {
163 5 : }
164 :
165 : template <class T>
166 5 : inline Request<T>::~Request()
167 : {
168 5 : if (static_cast<const Impl*>(this->impl_.get())->isUnresolved())
169 1 : this->wait();
170 10 : }
171 :
172 : template <class T>
173 4 : inline uint32_t Request<T>::getID() const
174 : {
175 4 : return static_cast<const Impl*>(this->impl_.get())->request;
176 : }
177 :
178 : template <class T>
179 1 : inline void Request<T>::unregister()
180 : {
181 1 : static_cast<Impl*>(this->impl_.get())->unregister();
182 1 : }
183 : }
184 :
185 : #endif // LUNCHBOX_REQUEST_H
|