Line data Source code
1 : /** \file mzmqClient.hpp
2 : * \brief The MagAO-X milkzmqClient wrapper
3 : *
4 : * \author Jared R. Males (jaredmales@gmail.com)
5 : *
6 : * \ingroup mzmqClient_files
7 : */
8 :
9 : #ifndef mzmqClient_hpp
10 : #define mzmqClient_hpp
11 :
12 : // #include <ImageStreamIO/ImageStruct.h>
13 : // #include <ImageStreamIO/ImageStreamIO.h>
14 :
15 : #include <milkzmqClient.hpp>
16 :
17 : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
18 : #include "../../magaox_git_version.h"
19 :
20 : namespace MagAOX
21 : {
22 : namespace app
23 : {
24 :
25 : /** \defgroup mzmqClient ImageStreamIO 0mq Stream Client
26 : * \brief Reads the contents of an ImageStreamIO image stream over a zeroMQ channel
27 : *
28 : * <a href="../handbook/operating/software/apps/mzmqClient.html">Application Documentation</a>
29 : *
30 : * \ingroup apps
31 : *
32 : */
33 :
34 : /** \defgroup mzmqClient_files ImageStreamIO Stream Synchronization
35 : * \ingroup mzmqClient
36 : */
37 :
38 : /// MagAO-X application to control reading ImageStreamIO streams from a zeroMQ channel
39 : /** Contents are published to a local ImageStreamIO shmem buffer.
40 : *
41 : * \todo handle the alternate local name option as in the base milkzmqClient
42 : * \todo md docs for this.
43 : *
44 : * \ingroup mzmqClient
45 : *
46 : */
47 : class mzmqClient : public MagAOXApp<>, public milkzmq::milkzmqClient
48 : {
49 :
50 : public:
51 : /// Default c'tor
52 : mzmqClient();
53 :
54 : /// Destructor
55 : ~mzmqClient() noexcept;
56 :
57 : /// Setup the configuration system (called by MagAOXApp::setup())
58 : virtual void setupConfig();
59 :
60 : /// load the configuration system results (called by MagAOXApp::setup())
61 : virtual void loadConfig();
62 :
63 : /// Startup functions
64 : /** Sets up the INDI vars.
65 : *
66 : */
67 : virtual int appStartup();
68 :
69 : /// Implementation of the FSM for the Siglent SDG
70 : virtual int appLogic();
71 :
72 : /// Do any needed shutdown tasks. Currently nothing in this app.
73 : virtual int appShutdown();
74 :
75 : protected:
76 : std::vector<std::string> m_shMemImNames;
77 :
78 : /** \name SIGSEGV & SIGBUS signal handling
79 : * These signals occur as a result of a ImageStreamIO source server resetting (e.g. changing frame sizes).
80 : * When they occur a restart of the framegrabber and framewriter thread main loops is triggered.
81 : *
82 : * @{
83 : */
84 : bool m_restart{ false };
85 :
86 : static mzmqClient *m_selfClient; ///< Static pointer to this (set in constructor). Used for getting out of the
87 : ///< static SIGSEGV handler.
88 :
89 : /// Sets the handler for SIGSEGV and SIGBUS
90 : /** These are caused by ImageStreamIO server resets.
91 : */
92 : int setSigSegvHandler();
93 :
94 : /// The handler called when SIGSEGV or SIGBUS is received, which will be due to ImageStreamIO server resets. Just a
95 : /// wrapper for handlerSigSegv.
96 : static void _handlerSigSegv( int signum, siginfo_t *siginf, void *ucont );
97 :
98 : /// Handles SIGSEGV and SIGBUS. Sets m_restart to true.
99 : void handlerSigSegv( int signum, siginfo_t *siginf, void *ucont );
100 : ///@}
101 :
102 : /** \name milkzmq Status and Error Handling
103 : * Implementation of status updates, warnings, and errors from milkzmq using logs.
104 : *
105 : * @{
106 : */
107 :
108 : /// Log status (with LOG_INFO level of priority).
109 : virtual void reportInfo( const std::string &msg /**< [in] the status message */ );
110 :
111 : /// Log status (with LOG_NOTICE level of priority).
112 : virtual void reportNotice( const std::string &msg /**< [in] the status message */ );
113 :
114 : /// Log a warning.
115 : virtual void reportWarning( const std::string &msg /**< [in] the warning message */ );
116 :
117 : /// Log an error.
118 : virtual void reportError( const std::string &msg, ///< [in] the error message
119 : const std::string &file, ///< [in] the name of the file where the error occurred
120 : int line ///< [in] the line number of the error
121 : );
122 : ///@}
123 : };
124 :
125 : // Set self pointer to null so app starts up uninitialized.
126 : mzmqClient *mzmqClient::m_selfClient = nullptr;
127 :
128 3 : inline mzmqClient::mzmqClient() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
129 : {
130 1 : m_powerMgtEnabled = false;
131 1 : m_selfClient = this;
132 :
133 1 : return;
134 0 : }
135 :
136 1 : inline mzmqClient::~mzmqClient() noexcept
137 : {
138 1 : return;
139 1 : }
140 :
141 0 : inline void mzmqClient::setupConfig()
142 : {
143 0 : config.add( "server.address",
144 : "",
145 : "server.address",
146 : argType::Required,
147 : "server",
148 : "address",
149 : false,
150 : "string",
151 : "The server's remote address. Usually localhost if using a tunnel." );
152 0 : config.add( "server.imagePort",
153 : "",
154 : "server.imagePort",
155 : argType::Required,
156 : "server",
157 : "imagePort",
158 : false,
159 : "int",
160 : "The server's port. Usually the port on localhost forwarded to the host." );
161 :
162 0 : config.add( "server.shmimNames",
163 : "",
164 : "server.shmimNames",
165 : argType::Required,
166 : "server",
167 : "shmimNames",
168 : false,
169 : "string",
170 : "List of names of the remote shmim streams to get." );
171 0 : }
172 :
173 0 : inline void mzmqClient::loadConfig()
174 : {
175 0 : m_argv0 = m_configName;
176 :
177 0 : config( m_address, "server.address" );
178 0 : config( m_imagePort, "server.imagePort" );
179 :
180 0 : config( m_shMemImNames, "server.shmimNames" );
181 :
182 0 : std::cerr << "m_imagePort = " << m_imagePort << "\n";
183 0 : }
184 :
185 : #include <sys/syscall.h>
186 :
187 0 : inline int mzmqClient::appStartup()
188 : {
189 0 : if( setSigSegvHandler() < 0 )
190 : {
191 0 : log<software_error>( { __FILE__, __LINE__ } );
192 0 : return -1;
193 : }
194 :
195 0 : for( size_t n = 0; n < m_shMemImNames.size(); ++n )
196 : {
197 0 : shMemImName( m_shMemImNames[n] );
198 : }
199 :
200 0 : for( size_t n = 0; n < m_imageThreads.size(); ++n )
201 : {
202 0 : if( imageThreadStart( n ) > 0 )
203 : {
204 0 : log<software_critical>( { __FILE__, __LINE__, "Starting image thread " + m_imageThreads[n].m_imageName } );
205 0 : return -1;
206 : }
207 : }
208 :
209 0 : return 0;
210 : }
211 :
212 0 : inline int mzmqClient::appLogic()
213 : {
214 : // first do a join check to see if other threads have exited.
215 :
216 0 : for( size_t n = 0; n < m_imageThreads.size(); ++n )
217 : {
218 0 : if( pthread_tryjoin_np( m_imageThreads[n].m_thread->native_handle(), 0 ) == 0 )
219 : {
220 0 : log<software_error>(
221 0 : { __FILE__, __LINE__, "image thread " + m_imageThreads[n].m_imageName + " has exited" } );
222 :
223 0 : return -1;
224 : }
225 : }
226 :
227 0 : return 0;
228 : }
229 :
230 0 : inline int mzmqClient::appShutdown()
231 : {
232 0 : m_timeToDie.store( true, std::memory_order_relaxed );
233 :
234 0 : for( size_t n = 0; n < m_imageThreads.size(); ++n )
235 : {
236 0 : imageThreadKill( n );
237 : }
238 :
239 0 : for( size_t n = 0; n < m_imageThreads.size(); ++n )
240 : {
241 0 : if( m_imageThreads[n].m_thread->joinable() )
242 : {
243 0 : m_imageThreads[n].m_thread->join();
244 : }
245 : }
246 :
247 0 : return 0;
248 : }
249 :
250 0 : inline int mzmqClient::setSigSegvHandler()
251 : {
252 : struct sigaction act;
253 : sigset_t set;
254 :
255 0 : act.sa_sigaction = &mzmqClient::_handlerSigSegv;
256 0 : act.sa_flags = SA_SIGINFO;
257 0 : sigemptyset( &set );
258 0 : act.sa_mask = set;
259 :
260 0 : errno = 0;
261 0 : if( sigaction( SIGSEGV, &act, 0 ) < 0 )
262 : {
263 0 : std::string logss = "Setting handler for SIGSEGV failed. Errno says: ";
264 0 : logss += strerror( errno );
265 :
266 0 : log<software_error>( { __FILE__, __LINE__, errno, 0, logss } );
267 :
268 0 : return -1;
269 0 : }
270 :
271 0 : errno = 0;
272 0 : if( sigaction( SIGBUS, &act, 0 ) < 0 )
273 : {
274 0 : std::string logss = "Setting handler for SIGBUS failed. Errno says: ";
275 0 : logss += strerror( errno );
276 :
277 0 : log<software_error>( { __FILE__, __LINE__, errno, 0, logss } );
278 :
279 0 : return -1;
280 0 : }
281 :
282 0 : log<text_log>( "Installed SIGSEGV/SIGBUS signal handler.", logPrio::LOG_DEBUG );
283 :
284 0 : return 0;
285 : }
286 :
287 0 : inline void mzmqClient::_handlerSigSegv( int signum, siginfo_t *siginf, void *ucont )
288 : {
289 0 : m_selfClient->handlerSigSegv( signum, siginf, ucont );
290 0 : }
291 :
292 0 : inline void mzmqClient::handlerSigSegv( int signum, siginfo_t *siginf, void *ucont )
293 : {
294 : static_cast<void>( signum );
295 : static_cast<void>( siginf );
296 : static_cast<void>( ucont );
297 :
298 0 : m_restart = true;
299 :
300 0 : return;
301 : }
302 :
303 0 : inline void mzmqClient::reportInfo( const std::string &msg )
304 : {
305 0 : log<text_log>( msg, logPrio::LOG_INFO );
306 0 : }
307 :
308 0 : inline void mzmqClient::reportNotice( const std::string &msg )
309 : {
310 0 : log<text_log>( msg, logPrio::LOG_NOTICE );
311 0 : }
312 :
313 0 : inline void mzmqClient::reportWarning( const std::string &msg )
314 : {
315 0 : log<text_log>( msg, logPrio::LOG_WARNING );
316 0 : }
317 :
318 0 : inline void mzmqClient::reportError( const std::string &msg, const std::string &file, int line )
319 : {
320 0 : log<software_error>( { file.c_str(), (uint32_t)line, msg } );
321 0 : }
322 :
323 : } // namespace app
324 : } // namespace MagAOX
325 : #endif
|