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