LCOV - code coverage report
Current view: top level - eq - client.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 84 178 47.2 %
Date: 2016-07-30 05:04:55 Functions: 22 34 64.7 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2016, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                          Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or modify it under
       6             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       7             :  * by the Free Software Foundation.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      10             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      11             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      12             :  * details.
      13             :  *
      14             :  * You should have received a copy of the GNU Lesser General Public License
      15             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      16             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      17             :  */
      18             : 
      19             : #include "client.h"
      20             : 
      21             : #include "commandQueue.h"
      22             : #include "config.h"
      23             : #include "node.h"
      24             : #include "global.h"
      25             : #include "init.h"
      26             : #include "nodeFactory.h"
      27             : #include "server.h"
      28             : 
      29             : #include <eq/fabric/commands.h>
      30             : #include <eq/fabric/configVisitor.h>
      31             : #include <eq/fabric/leafVisitor.h>
      32             : #include <eq/fabric/elementVisitor.h>
      33             : #include <eq/fabric/nodeType.h>
      34             : #include <eq/fabric/view.h>
      35             : 
      36             : #include <eq/server/localServer.h>
      37             : 
      38             : #include <co/iCommand.h>
      39             : #include <co/connection.h>
      40             : #include <co/connectionDescription.h>
      41             : #include <co/global.h>
      42             : #include <lunchbox/dso.h>
      43             : #include <lunchbox/file.h>
      44             : #include <boost/filesystem/path.hpp>
      45             : 
      46             : #ifdef EQ_QT_USED
      47             : #  include <QApplication> // must be included before any header defining Bool
      48             : 
      49             : #  include "os.h"
      50             : #else
      51             : class QApplication;
      52             : #endif
      53             : 
      54             : namespace eq
      55             : {
      56             : namespace
      57             : {
      58             : typedef stde::hash_set< Server* > ServerSet;
      59             : }
      60             : 
      61             : /** @cond IGNORE */
      62             : namespace detail
      63             : {
      64          12 : class Client
      65             : {
      66             : public:
      67          12 :     Client()
      68             :         : queue( co::Global::getCommandQueueLimit( ))
      69             :         , modelUnit( EQ_UNDEFINED_UNIT )
      70             :         , qtApp( 0 )
      71          12 :         , running( false )
      72          12 :     {}
      73             : 
      74             :     CommandQueue queue; //!< The command->node command queue.
      75             :     std::string name;
      76             :     Strings activeLayouts;
      77             :     ServerSet localServers;
      78             :     std::string gpuFilter;
      79             :     float modelUnit;
      80             :     QApplication* qtApp;
      81             :     bool running;
      82             : 
      83          12 :     void initQt( int argc LB_UNUSED, char** argv LB_UNUSED )
      84             :     {
      85             : #if EQ_GLX_USED || EQ_WGL_USED || EQ_AGL_USED
      86          12 :         return;
      87             : #endif
      88             : #ifdef EQ_QT_USED
      89             :         if( !QApplication::instance( ))
      90             :         {
      91             : #  ifdef __linux__
      92             :             ::XInitThreads();
      93             : #  endif
      94             :             qtApp = new QApplication( argc, argv );
      95             :         }
      96             : #endif
      97             :     }
      98             : };
      99             : }
     100             : 
     101             : typedef co::CommandFunc<Client> ClientFunc;
     102             : 
     103             : typedef fabric::Client Super;
     104             : /** @endcond */
     105             : 
     106          12 : Client::Client()
     107             :         : Super()
     108          12 :         , _impl( new detail::Client )
     109             : {
     110             :     registerCommand( fabric::CMD_CLIENT_EXIT,
     111          12 :                      ClientFunc( this, &Client::_cmdExit ), &_impl->queue );
     112             :     registerCommand( fabric::CMD_CLIENT_INTERRUPT,
     113          12 :                      ClientFunc( this, &Client::_cmdInterrupt ), &_impl->queue);
     114             : 
     115          12 :     LBVERB << "New client at " << (void*)this << std::endl;
     116          12 : }
     117             : 
     118          36 : Client::~Client()
     119             : {
     120          12 :     LBVERB << "Delete client at " << (void*)this << std::endl;
     121          12 :     LBASSERT( isClosed( ));
     122          12 :     close();
     123          12 :     delete _impl;
     124          24 : }
     125             : 
     126          12 : bool Client::connectServer( ServerPtr server )
     127             : {
     128          12 :     if( Super::connectServer( server ))
     129             :     {
     130           0 :         server->setClient( this );
     131           0 :         return true;
     132             :     }
     133             : 
     134          48 :     if( !server->getConnectionDescriptions().empty() ||
     135          48 :         !Global::getServer().empty() || getenv( "EQ_SERVER" ))
     136             :     {
     137           0 :         return false;
     138             :     }
     139             : 
     140             :     // Use app-local server if no explicit server was set
     141          12 :     if( !server::startLocalServer( Global::getConfigFile( )))
     142           0 :         return false;
     143             : 
     144          12 :     co::ConnectionPtr connection = server::connectLocalServer();
     145          12 :     if( !connection || !connect( server, connection ))
     146           0 :         return false;
     147             : 
     148          12 :     server->setClient( this );
     149          12 :     _impl->localServers.insert( server.get( ));
     150          12 :     return true;
     151             : }
     152             : 
     153          12 : bool Client::disconnectServer( ServerPtr server )
     154             : {
     155          12 :     ServerSet::iterator i = _impl->localServers.find( server.get( ));
     156          12 :     if( i == _impl->localServers.end( ))
     157             :     {
     158           0 :         server->setClient( 0 );
     159           0 :         const bool success = Super::disconnectServer( server );
     160           0 :         _impl->queue.flush();
     161           0 :         return success;
     162             :     }
     163             : 
     164             :     // shut down process-local server (see _startLocalServer)
     165          12 :     LBASSERT( server->isConnected( ));
     166          12 :     const bool success = server->shutdown();
     167          12 :     server::joinLocalServer();
     168          12 :     server->setClient( 0 );
     169             : 
     170          12 :     LBASSERT( !server->isConnected( ));
     171          12 :     _impl->localServers.erase( i );
     172          12 :     _impl->queue.flush();
     173          12 :     return success;
     174             : }
     175             : 
     176             : namespace
     177             : {
     178           0 : bool _isParameterOption( const std::string& name, const int argc, char** argv,
     179             :                          const int index )
     180             : {
     181           0 :     return ( index < argc-1 &&          // has enough total arguments
     182           0 :              name == argv[index] &&     // name matches
     183           0 :              argv[index+1][0] != '-' ); // next arg not an option
     184             : }
     185             : }
     186             : 
     187          12 : bool Client::initLocal( const int argc, char** argv )
     188             : {
     189          12 :     bool isClient = false;
     190          12 :     std::string clientOpts;
     191             : 
     192          12 :     if( _impl->name.empty() && argc > 0 && argv )
     193             :     {
     194          12 :         const boost::filesystem::path prog = argv[0];
     195          12 :         setName( prog.stem().string( ));
     196             :     }
     197             : 
     198          12 :     for( int i=1; i<argc; ++i )
     199             :     {
     200           0 :         if( std::string( "--eq-client" ) == argv[i] )
     201           0 :             isClient = true;
     202           0 :         else if( _isParameterOption( "--eq-layout", argc, argv, i ))
     203           0 :             _impl->activeLayouts.push_back( argv[++i] );
     204           0 :         else if( _isParameterOption( "--eq-gpufilter" , argc, argv, i ))
     205           0 :             _impl->gpuFilter = argv[ ++i ];
     206           0 :         else if( _isParameterOption( "--eq-modelunit", argc, argv, i ))
     207             :         {
     208           0 :             std::istringstream unitString( argv[++i] );
     209           0 :             unitString >> _impl->modelUnit;
     210             :         }
     211             :     }
     212          12 :     LBVERB << "Launching " << getNodeID() << std::endl;
     213             : 
     214          12 :     if( !Super::initLocal( argc, argv ))
     215           0 :         return false;
     216             : 
     217          12 :     if( isClient )
     218             :     {
     219           0 :         LBVERB << "Client node started from command line with option "
     220           0 :                << clientOpts << std::endl;
     221             : 
     222           0 :         if( !_setupClient( clientOpts ))
     223             :         {
     224           0 :             exitLocal();
     225           0 :             return false;
     226             :         }
     227             : 
     228           0 :         _impl->running = true;
     229           0 :         clientLoop();
     230           0 :         exitClient();
     231             :     }
     232             : 
     233          12 :     _impl->initQt( argc, argv );
     234          12 :     return true;
     235             : }
     236             : 
     237           0 : bool Client::_setupClient( const std::string& clientArgs )
     238             : {
     239           0 :     LBASSERT( isListening( ));
     240           0 :     if( clientArgs.empty( ))
     241           0 :         return true;
     242             : 
     243           0 :     size_t nextPos = clientArgs.find( CO_SEPARATOR );
     244           0 :     if( nextPos == std::string::npos )
     245             :     {
     246           0 :         LBERROR << "Could not parse working directory: " << clientArgs
     247           0 :                 << std::endl;
     248           0 :         return false;
     249             :     }
     250             : 
     251           0 :     const std::string workDir = clientArgs.substr( 0, nextPos );
     252           0 :     std::string description = clientArgs.substr( nextPos + 1 );
     253             : 
     254           0 :     Global::setWorkDir( workDir );
     255           0 :     if( !workDir.empty() && chdir( workDir.c_str( )) == -1 )
     256           0 :         LBWARN << "Can't change working directory to " << workDir << ": "
     257           0 :                << lunchbox::sysError << std::endl;
     258             : 
     259           0 :     nextPos = description.find( CO_SEPARATOR );
     260           0 :     if( nextPos == std::string::npos )
     261             :     {
     262           0 :         LBERROR << "Could not parse server node type: " << description
     263           0 :                 << " is left from " << clientArgs << std::endl;
     264           0 :         return false;
     265             :     }
     266             : 
     267           0 :     co::NodePtr server = createNode( fabric::NODETYPE_SERVER );
     268           0 :     if( !server->deserialize( description ))
     269           0 :         LBWARN << "Can't parse server data" << std::endl;
     270             : 
     271           0 :     LBASSERTINFO( description.empty(), description );
     272           0 :     if( !connect( server ))
     273             :     {
     274           0 :         LBERROR << "Can't connect server node using " << *server << std::endl;
     275           0 :         return false;
     276             :     }
     277             : 
     278           0 :     return true;
     279             : }
     280             : 
     281           0 : void Client::clientLoop()
     282             : {
     283           0 :     LBINFO << "Entered client loop" << std::endl;
     284           0 :     while( isRunning( ))
     285           0 :         processCommand();
     286           0 : }
     287             : 
     288          12 : bool Client::exitLocal()
     289             : {
     290             : #ifdef EQ_QT_USED
     291          12 :     delete _impl->qtApp;
     292          12 :     _impl->qtApp = 0;
     293             : #endif
     294          12 :     _impl->activeLayouts.clear();
     295          12 :     _impl->modelUnit = EQ_UNDEFINED_UNIT;
     296          12 :     return fabric::Client::exitLocal();
     297             : }
     298             : 
     299           0 : void Client::exitClient()
     300             : {
     301           0 :     _impl->queue.flush();
     302           0 :     bool ret = exitLocal();
     303           0 :     LBINFO << "Exit " << lunchbox::className( this ) << " process used "
     304           0 :            << getRefCount() << std::endl;
     305             : 
     306           0 :     if( !eq::exit( ))
     307           0 :         ret = false;
     308           0 :     ::exit( ret ? EXIT_SUCCESS : EXIT_FAILURE );
     309             : }
     310             : 
     311           0 : bool Client::hasCommands()
     312             : {
     313           0 :     return !_impl->queue.isEmpty();
     314             : }
     315             : 
     316           0 : bool Client::isRunning() const
     317             : {
     318           0 :     return _impl->running;
     319             : }
     320             : 
     321          78 : co::CommandQueue* Client::getMainThreadQueue()
     322             : {
     323          78 :     return &_impl->queue;
     324             : }
     325             : 
     326           0 : void Client::addActiveLayout( const std::string& activeLayout )
     327             : {
     328           0 :     _impl->activeLayouts.push_back( activeLayout );
     329           0 : }
     330             : 
     331          12 : void Client::setName( const std::string& name )
     332             : {
     333          12 :     _impl->name = name;
     334          12 : }
     335             : 
     336           2 : const std::string& Client::getName() const
     337             : {
     338           2 :     return _impl->name;
     339             : }
     340             : 
     341           1 : const Strings& Client::getActiveLayouts() const
     342             : {
     343           1 :     return _impl->activeLayouts;
     344             : }
     345             : 
     346           2 : const std::string& Client::getGPUFilter() const
     347             : {
     348           2 :     return _impl->gpuFilter;
     349             : }
     350             : 
     351           1 : float Client::getModelUnit() const
     352             : {
     353           1 :     return _impl->modelUnit;
     354             : }
     355             : 
     356           0 : void Client::interruptMainThread()
     357             : {
     358           0 :     send( fabric::CMD_CLIENT_INTERRUPT );
     359           0 : }
     360             : 
     361           0 : co::NodePtr Client::createNode( const uint32_t type )
     362             : {
     363           0 :     switch( type )
     364             :     {
     365             :         case fabric::NODETYPE_SERVER:
     366             :         {
     367           0 :             Server* server = new Server;
     368           0 :             server->setClient( this );
     369           0 :             return server;
     370             :         }
     371             : 
     372             :         default:
     373           0 :             return Super::createNode( type );
     374             :     }
     375             : }
     376             : 
     377           0 : bool Client::_cmdExit( co::ICommand& command )
     378             : {
     379           0 :     _impl->running = false;
     380             :     // Close connection here, this is the last command we'll get on it
     381           0 :     command.getLocalNode()->disconnect( command.getRemoteNode( ));
     382           0 :     return true;
     383             : }
     384             : 
     385           0 : bool Client::_cmdInterrupt( co::ICommand& )
     386             : {
     387           0 :     return true;
     388             : }
     389             : 
     390             : namespace
     391             : {
     392          12 : class StopNodesVisitor : public ServerVisitor
     393             : {
     394             : public:
     395          12 :     virtual ~StopNodesVisitor() {}
     396          30 :     virtual VisitorResult visitPre( Node* node )
     397             :     {
     398          30 :         node->dirtyClientExit();
     399          30 :         return TRAVERSE_CONTINUE;
     400             :     }
     401             : };
     402             : }
     403             : 
     404          12 : void Client::notifyDisconnect( co::NodePtr node )
     405             : {
     406          12 :     if( node->getType() == fabric::NODETYPE_SERVER )
     407             :     {
     408             :         // local command dispatching
     409             :         co::OCommand( this, this, fabric::CMD_CLIENT_EXIT,
     410          12 :                       co::COMMANDTYPE_NODE );
     411             : 
     412          12 :         ServerPtr server = static_cast< Server* >( node.get( ));
     413          24 :         StopNodesVisitor stopNodes;
     414          24 :         server->accept( stopNodes );
     415             :     }
     416          12 :     fabric::Client::notifyDisconnect( node );
     417          12 : }
     418             : 
     419          42 : }

Generated by: LCOV version 1.11