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

            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
        

Generated by: LCOV version 2.0-1