1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
/* -*- c++ -*- */
/*
* Copyright 2015 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef THRIFT_APPLICATION_BASE_H
#define THRIFT_APPLICATION_BASE_H
#include <gnuradio/api.h>
#include <gnuradio/logger.h>
#include <gnuradio/prefs.h>
#include <gnuradio/thread/thread.h>
#include <boost/date_time/posix_time/posix_time.hpp>
namespace {
// Time, in milliseconds, to wait between checks to the Thrift runtime to see if
// it has fully initialized.
static const unsigned int THRIFTAPPLICATION_ACTIVATION_TIMEOUT_MS(200);
};
namespace apache { namespace thrift { namespace server { class TServer; } } }
/*!
* \brief Class to be statically initialized by thrift_application_base. Used
* to store state for thrift_application_base's singleton functions.
*/
class thrift_application_base_impl
{
public:
thrift_application_base_impl() :
d_application_initilized(false),
d_endpointStr(""),
d_start_thrift_thread() {;}
// Used to ensure the Thrift runtime is initialized on the first call to ::i().
bool d_application_initilized;
// Stores the generated endpoint string after the Thrift runtime has initialized.
std::string d_endpointStr;
// Thread to execute the Thrift runtime's blocking serve() function.
boost::shared_ptr<gr::thread::thread> d_start_thrift_thread;
};
/*!
* \brief Base class for a Thrift application with a singleton with
* instance function thrift_application_base::i(). Lazy initialization
* is used to start the Thrift runtime, therefore the Thrift runtime
* is not started unless thrift_application_base::i() is called at
* least once. This typically means that at least one rpc variable
* must be registered by a block before the runtime will start.
*
* \param TserverBase Template parameter naming the type of the server
* base, which is typically rpcserverbase.
* \param TserverClass Template parameter naming the eventual type of
* the fully derived application.
* \param _app Reference to the fully derived application instance to
* be returned by thrift_application_base::i().
*/
template<typename TserverBase, typename TserverClass>
class thrift_application_base
{
public:
thrift_application_base(TserverClass* _app);
/*!
* Destructor for the application. Since shutdown and cleanup of the
* runtime is typically custom to a particular booter
* implementation, this must be implemented as a specalized function
* for a particular booter. Thus a template implementation is not
* provided here.
*/
~thrift_application_base();
/*!
* The application singleton instance function.
*/
static TserverBase* i();
/*!
* Returns the endpoint string of this application.
*/
static const std::vector<std::string> endpoints();
protected:
/*!
* Allows this application's booter to set the endpoint string after
* the Thrift runtime has initialized.
*
* \param[in] endpoint The endpoint string reported by this class.
*/
void set_endpoint(const std::string& endpoint);
virtual TserverBase* i_impl() = 0;
/*!
* Reference to the fully derived application instance.
*/
static TserverClass* d_application;
/*!
* Reference to the Thrift runtime.
*/
std::auto_ptr<apache::thrift::server::TServer> d_thriftserver;
/*!
* Max number of attempts when checking the Thrift runtime for
* Initialization before giving up. Set in the Thrift config file
* (see \ref ctrlport_thrift_prefs).
*/
static const unsigned int d_default_max_init_attempts;
/*!
* Default port for the runtime to listen on, if a static port is
* not specified. Set in the Thrift config file (see \ref
* ctrlport_thrift_prefs).
*/
static const unsigned int d_default_thrift_port;
/*!
* Maximum number of threads to create when serving multiple rpc
* clients. Set in the Thrift config file (see \ref
* ctrlport_thrift_prefs).
*/
static const unsigned int d_default_num_thrift_threads;
/*!
* Default packet size for the IP payload of thrift packets. Set in
* the Thrift config file (see \ref ctrlport_thrift_prefs).
*/
static const unsigned int d_default_thrift_buffer_size;
/*!
* \ref page_logger instances.
*/
gr::logger_ptr d_logger, d_debug_logger;
private:
// Function to be called in a separate thread to invoke the blocking
// ThriftServer::serve() function. Must be specialized for a particular
// booter implementation, therefore a template implementation is
// not provided here.
void start_thrift();
// Non-blocking function that returns true when the Thrift
// runtime has finished initialization. Must be implemented
// as a specialized template function for a particular booter
// implementation, therefore template implementation is not
// provided here.
bool application_started();
// Internal function to start the initialization of the runtime.
// Since this singleton uses lazy instantiation, this function
// will be called on the first call to the instance function ::i(),
// and since ::i() is static, this function must be static as well.
static void start_application();
// Pointer to the structure containing staticly allocated
// state information for the applicaiton_base singleton.
static std::auto_ptr<thrift_application_base_impl > p_impl;
// Mutex to protect the endpoint string.
gr::thread::mutex d_lock;
// Will be set to true by a the application_started() function,
// specialized for a particular booter implementation, once the
// thrift runtime has successfully initialized.
bool d_thirft_is_running;
};
template<typename TserverBase, typename TserverClass>
TserverClass* thrift_application_base<TserverBase, TserverClass>::d_application(0);
template<typename TserverBase, typename TserverClass>
thrift_application_base<TserverBase, TserverClass>::thrift_application_base(TserverClass* _app)
: d_lock(),
d_thirft_is_running(false)
{
gr::configure_default_loggers(d_logger, d_debug_logger, "controlport");
d_application = _app;
//GR_LOG_DEBUG(d_debug_logger, "thrift_application_base: ctor");
}
template<typename TserverBase, typename TserverClass>
void thrift_application_base<TserverBase, TserverClass>::start_application()
{
//std::cerr << "thrift_application_base: start_application" << std::endl;
unsigned int max_init_attempts = \
static_cast<unsigned int>(gr::prefs::singleton()->get_long("thrift", "init_attempts",
d_default_max_init_attempts));
if(!p_impl->d_application_initilized) {
p_impl->d_start_thrift_thread.reset(
(new gr::thread::thread(boost::bind(&thrift_application_base::start_thrift, d_application))));
bool app_started(false);
for(unsigned int attempts(0); (!app_started && attempts < max_init_attempts); ++attempts) {
boost::this_thread::sleep(boost::posix_time::milliseconds(THRIFTAPPLICATION_ACTIVATION_TIMEOUT_MS));
app_started = d_application->application_started();
}
if(!app_started) {
std::cerr << "thrift_application_base::start_application(), timeout waiting to port number might have failed?" << std::endl;
}
p_impl->d_application_initilized = true;
}
}
template<typename TserverBase, typename TserverClass>
const std::vector<std::string> thrift_application_base<TserverBase, TserverClass>::endpoints()
{
std::vector<std::string> ep;
ep.push_back(p_impl->d_endpointStr);
return ep;
}
template<typename TserverBase, typename TserverClass>
void thrift_application_base<TserverBase, TserverClass>::set_endpoint(const std::string& endpoint)
{
gr::thread::scoped_lock guard(d_lock);
p_impl->d_endpointStr = endpoint;
}
template<typename TserverBase, typename TserverClass>
TserverBase* thrift_application_base<TserverBase, TserverClass>::i()
{
if(!p_impl->d_application_initilized) {
start_application();
}
return d_application->i_impl();
}
#endif
|