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