Line data Source code
1 : /** \file mzmqServer.hpp
2 : * \brief The MagAO-X milkzmqServer wrapper
3 : *
4 : * \author Jared R. Males (jaredmales@gmail.com)
5 : *
6 : * \ingroup mzmqServer_files
7 : */
8 :
9 : #ifndef mzmqServer_hpp
10 : #define mzmqServer_hpp
11 :
12 :
13 : //#include <ImageStruct.h>
14 : //#include <ImageStreamIO.h>
15 :
16 : #include <milkzmqServer.hpp>
17 :
18 : //#include <mx/timeUtils.hpp>
19 :
20 : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
21 : #include "../../magaox_git_version.h"
22 :
23 :
24 :
25 : namespace MagAOX
26 : {
27 : namespace app
28 : {
29 :
30 : /** \defgroup mzmqServer ImageStreamIO Stream Server
31 : * \brief Writes the contents of an ImageStreamIO image stream over a zeroMQ channel
32 : *
33 : * <a href="../handbook/operating/software/apps/mzmqServer.html">Application Documentation</a>
34 : *
35 : * \ingroup apps
36 : *
37 : */
38 :
39 : /** \defgroup mzmqServer_files ImageStreamIO Stream Synchronization
40 : * \ingroup mzmqServer
41 : */
42 :
43 : /// MagAO-X application to control writing ImageStreamIO streams to a zeroMQ channel
44 : /** \todo document this better
45 : * \todo implement thread-kills for shutdown. Maybe switch to USR1, with library wide empty handler, so it isn't logged.
46 : * \ingroup mzmqServer
47 : *
48 : */
49 : class mzmqServer : public MagAOXApp<>, public milkzmq::milkzmqServer
50 : {
51 :
52 :
53 : public:
54 :
55 : ///Default c'tor
56 : mzmqServer();
57 :
58 : ///Destructor
59 : ~mzmqServer() noexcept;
60 :
61 : /// Setup the configuration system (called by MagAOXApp::setup())
62 : virtual void setupConfig();
63 :
64 : /// load the configuration system results (called by MagAOXApp::setup())
65 : virtual void loadConfig();
66 :
67 : /// Startup functions
68 : /** Sets up the INDI vars.
69 : *
70 : */
71 : virtual int appStartup();
72 :
73 : /// Implementation of the FSM for the Siglent SDG
74 : virtual int appLogic();
75 :
76 :
77 : /// Do any needed shutdown tasks. Currently nothing in this app.
78 : virtual int appShutdown();
79 :
80 : protected:
81 :
82 : bool m_compress {false};
83 : std::vector<std::string> m_shMemImNames;
84 :
85 : /** \name SIGSEGV & SIGBUS signal handling
86 : * These signals occur as a result of a ImageStreamIO source server resetting (e.g. changing frame sizes).
87 : * When they occur a restart of the framegrabber and framewriter thread main loops is triggered.
88 : *
89 : * @{
90 : */
91 : static mzmqServer * m_selfWriter; ///< 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 :
136 : //Set self pointer to null so app starts up uninitialized.
137 : mzmqServer * mzmqServer::m_selfWriter = nullptr;
138 :
139 : inline
140 : mzmqServer::mzmqServer() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
141 : {
142 : m_powerMgtEnabled = false;
143 :
144 : return;
145 : }
146 :
147 : inline
148 0 : mzmqServer::~mzmqServer() noexcept
149 : {
150 0 : return;
151 0 : }
152 :
153 : inline
154 0 : void mzmqServer::setupConfig()
155 : {
156 0 : config.add("server.imagePort", "", "server.imagePort", argType::Required, "server", "imagePort", false, "int", "");
157 :
158 0 : config.add("server.shmimNames", "", "server.shmimNames", argType::Required, "server", "shmimNames", false, "string", "");
159 :
160 0 : config.add("server.usecSleep", "", "server.usecSleep", argType::Required, "server", "usecSleep", false, "int", "");
161 :
162 0 : config.add("server.fpsTgt", "", "server.fpsTgt", argType::Required, "server", "fpsTgt", false, "float", "");
163 :
164 0 : config.add("server.fpsGain", "", "server.fpsGain", argType::Required, "server", "fpsGain", false, "float", "");
165 :
166 0 : config.add("server.compress", "", "server.compress", argType::Required, "server", "compress", false, "bool", "Flag to turn on compression for INT16 and UINT16.");
167 :
168 0 : }
169 :
170 :
171 :
172 : inline
173 0 : void mzmqServer::loadConfig()
174 : {
175 0 : m_argv0 = m_configName;
176 :
177 0 : config(m_imagePort, "server.imagePort");
178 :
179 0 : config(m_shMemImNames, "server.shmimNames");
180 0 : config(m_usecSleep, "server.usecSleep");
181 0 : config(m_fpsTgt, "server.fpsTgt");
182 :
183 0 : config(m_fpsGain, "server.fpsGain");
184 :
185 0 : config(m_compress, "server.compress");
186 :
187 :
188 0 : }
189 :
190 :
191 : #include <sys/syscall.h>
192 :
193 : inline
194 0 : int mzmqServer::appStartup()
195 : {
196 :
197 : //Now set up the framegrabber and writer threads.
198 : // - need SIGSEGV and SIGBUS handling for ImageStreamIO restarts
199 : // - initialize the semaphore
200 : // - start the threads
201 :
202 0 : if(setSigSegvHandler() < 0)
203 : {
204 0 : log<software_error>({__FILE__, __LINE__});
205 0 : return -1;
206 : }
207 :
208 0 : if(m_compress) defaultCompression();
209 :
210 0 : for(size_t n=0; n < m_shMemImNames.size(); ++n)
211 : {
212 0 : shMemImName(m_shMemImNames[n]);
213 : }
214 :
215 0 : if(serverThreadStart() < 0)
216 : {
217 0 : log<software_critical>({__FILE__, __LINE__});
218 0 : return -1;
219 : }
220 :
221 0 : for(size_t n=0; n < m_imageThreads.size(); ++n)
222 : {
223 0 : if( imageThreadStart(n) > 0)
224 : {
225 0 : log<software_critical>({__FILE__, __LINE__, "Starting image thread " + m_imageThreads[n].m_imageName});
226 0 : return -1;
227 : }
228 : }
229 :
230 :
231 0 : std::cerr << "Main Thread: " << syscall(SYS_gettid) << "\n";
232 :
233 0 : return 0;
234 :
235 : }
236 :
237 :
238 :
239 : inline
240 0 : int mzmqServer::appLogic()
241 : {
242 : //first do a join check to see if other threads have exited.
243 :
244 0 : if(pthread_tryjoin_np(m_serverThread.native_handle(),0) == 0)
245 : {
246 0 : log<software_error>({__FILE__, __LINE__, "server thread has exited"});
247 :
248 0 : return -1;
249 : }
250 :
251 0 : for(size_t n=0; n < m_imageThreads.size(); ++n)
252 : {
253 0 : if(pthread_tryjoin_np(m_imageThreads[n].m_thread->native_handle(),0) == 0)
254 : {
255 0 : log<software_error>({__FILE__, __LINE__, "image thread " + m_imageThreads[n].m_imageName + " has exited"});
256 :
257 0 : return -1;
258 : }
259 : }
260 :
261 :
262 0 : return 0;
263 :
264 : }
265 :
266 : inline
267 0 : int mzmqServer::appShutdown()
268 : {
269 0 : m_timeToDie = true;
270 :
271 0 : for(size_t n=0; n < m_imageThreads.size(); ++n)
272 : {
273 0 : imageThreadKill(n);
274 : }
275 :
276 0 : for(size_t n=0; n < m_imageThreads.size(); ++n)
277 : {
278 0 : if( m_imageThreads[n].m_thread->joinable())
279 : {
280 0 : m_imageThreads[n].m_thread->join();
281 : }
282 : }
283 :
284 0 : return 0;
285 : }
286 :
287 : inline
288 0 : int mzmqServer::setSigSegvHandler()
289 : {
290 : struct sigaction act;
291 : sigset_t set;
292 :
293 0 : act.sa_sigaction = &mzmqServer::_handlerSigSegv;
294 0 : act.sa_flags = SA_SIGINFO;
295 0 : sigemptyset(&set);
296 0 : act.sa_mask = set;
297 :
298 0 : errno = 0;
299 0 : if( sigaction(SIGSEGV, &act, 0) < 0 )
300 : {
301 0 : std::string logss = "Setting handler for SIGSEGV failed. Errno says: ";
302 0 : logss += strerror(errno);
303 :
304 0 : log<software_error>({__FILE__, __LINE__, errno, 0, logss});
305 :
306 0 : return -1;
307 0 : }
308 :
309 0 : errno = 0;
310 0 : if( sigaction(SIGBUS, &act, 0) < 0 )
311 : {
312 0 : std::string logss = "Setting handler for SIGBUS failed. Errno says: ";
313 0 : logss += strerror(errno);
314 :
315 0 : log<software_error>({__FILE__, __LINE__, errno, 0,logss});
316 :
317 0 : return -1;
318 0 : }
319 :
320 0 : log<text_log>("Installed SIGSEGV/SIGBUS signal handler.", logPrio::LOG_DEBUG);
321 :
322 0 : return 0;
323 : }
324 :
325 : inline
326 0 : void mzmqServer::_handlerSigSegv( int signum,
327 : siginfo_t *siginf,
328 : void *ucont
329 : )
330 : {
331 0 : m_selfWriter->handlerSigSegv(signum, siginf, ucont);
332 0 : }
333 :
334 : inline
335 0 : void mzmqServer::handlerSigSegv( int signum,
336 : siginfo_t *siginf,
337 : void *ucont
338 : )
339 : {
340 : static_cast<void>(signum);
341 : static_cast<void>(siginf);
342 : static_cast<void>(ucont);
343 :
344 0 : milkzmqServer::m_restart = true;
345 :
346 0 : return;
347 : }
348 :
349 : inline
350 0 : void mzmqServer::reportInfo( const std::string & msg )
351 : {
352 0 : log<text_log>(msg, logPrio::LOG_INFO);
353 0 : }
354 :
355 : inline
356 0 : void mzmqServer::reportNotice( const std::string & msg )
357 : {
358 0 : log<text_log>(msg, logPrio::LOG_NOTICE);
359 0 : }
360 :
361 : inline
362 0 : void mzmqServer::reportWarning( const std::string & msg )
363 : {
364 0 : log<text_log>(msg, logPrio::LOG_WARNING);
365 0 : }
366 :
367 : inline
368 0 : void mzmqServer::reportError( const std::string & msg,
369 : const std::string & file,
370 : int line
371 : )
372 : {
373 0 : log<software_error>({file.c_str(), (uint32_t) line, msg});
374 0 : }
375 :
376 :
377 :
378 : }//namespace app
379 : } //namespace MagAOX
380 : #endif
|