LCOV - code coverage report
Current view: top level - apps/mzmqServer - mzmqServer.hpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 0.0 % 92 0
Test Date: 2026-01-03 21:03:39 Functions: 0.0 % 13 0

            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
        

Generated by: LCOV version 2.0-1