LCOV - code coverage report
Current view: top level - apps/mzmqServer - mzmqServer.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 6.9 % 102 7
Test Date: 2026-04-15 19:34:29 Functions: 14.3 % 14 2

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

Generated by: LCOV version 2.0-1