LCOV - code coverage report
Current view: top level - eq/server - server.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 134 193 69.4 %
Date: 2016-09-29 05:02:09 Functions: 14 16 87.5 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2016, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                          Cedric Stalder <cedric.stalder@gmail.com>
       4             :  *                          Daniel Nachbaur <danielnachbaur@gmail.com>
       5             :  *
       6             :  * This library is free software; you can redistribute it and/or modify it under
       7             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       8             :  * by the Free Software Foundation.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      11             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      12             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      13             :  * details.
      14             :  *
      15             :  * You should have received a copy of the GNU Lesser General Public License
      16             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      17             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             :  */
      19             : 
      20             : #include "server.h"
      21             : 
      22             : #include "channel.h"
      23             : #include "compound.h"
      24             : #include "config.h"
      25             : #include "global.h"
      26             : #include "loader.h"
      27             : #include "node.h"
      28             : #include "nodeFactory.h"
      29             : #include "pipe.h"
      30             : #include "window.h"
      31             : #ifdef EQUALIZER_USE_HWSD
      32             : #  include "config/server.h"
      33             : #endif
      34             : 
      35             : #include <eq/fabric/commands.h>
      36             : #include <eq/fabric/configParams.h>
      37             : 
      38             : #include <co/iCommand.h>
      39             : #include <co/connectionDescription.h>
      40             : #include <co/global.h>
      41             : #include <co/init.h>
      42             : #include <co/localNode.h>
      43             : #include <lunchbox/refPtr.h>
      44             : #include <lunchbox/sleep.h>
      45             : 
      46             : #include <sstream>
      47             : 
      48             : #include "configBackupVisitor.h"
      49             : #include "configRestoreVisitor.h"
      50             : 
      51             : namespace eq
      52             : {
      53             : namespace server
      54             : {
      55             : namespace
      56             : {
      57          28 : static NodeFactory _nf;
      58             : }
      59             : 
      60             : typedef co::CommandFunc<Server> ServerFunc;
      61             : typedef fabric::Server< co::Node, Server, Config, NodeFactory, co::LocalNode,
      62             :                         ServerVisitor > Super;
      63             : 
      64         446 : Server::Server()
      65             :         : Super( &_nf )
      66             :         , _mainThreadQueue( co::Global::getCommandQueueLimit( ))
      67         446 :         , _running( false )
      68             : {
      69         446 :     lunchbox::Log::setClock( &_clock );
      70         446 :     disableInstanceCache();
      71             : 
      72             :     registerCommand( fabric::CMD_SERVER_CHOOSE_CONFIG,
      73             :                      ServerFunc( this, &Server::_cmdChooseConfig ),
      74         446 :                      &_mainThreadQueue );
      75             :     registerCommand( fabric::CMD_SERVER_RELEASE_CONFIG,
      76             :                      ServerFunc( this, &Server::_cmdReleaseConfig ),
      77         446 :                      &_mainThreadQueue );
      78             :     registerCommand( fabric::CMD_SERVER_DESTROY_CONFIG_REPLY,
      79         446 :                      ServerFunc( this, &Server::_cmdDestroyConfigReply ), 0 );
      80             :     registerCommand( fabric::CMD_SERVER_SHUTDOWN,
      81             :                      ServerFunc( this, &Server::_cmdShutdown ),
      82         446 :                      &_mainThreadQueue );
      83             :     registerCommand( fabric::CMD_SERVER_MAP,
      84         446 :                      ServerFunc( this, &Server::_cmdMap ), &_mainThreadQueue );
      85             :     registerCommand( fabric::CMD_SERVER_UNMAP,
      86             :                      ServerFunc( this, &Server::_cmdUnmap ),
      87         446 :                      &_mainThreadQueue );
      88         446 : }
      89             : 
      90        1332 : Server::~Server()
      91             : {
      92         444 :     LBASSERT( getConfigs().empty( )); // not possible - config RefPtr's myself
      93         444 :     deleteConfigs();
      94         444 :     lunchbox::Log::setClock( 0 );
      95         888 : }
      96             : 
      97          24 : void Server::init()
      98             : {
      99          24 :     lunchbox::Thread::setName( "Server" );
     100          24 :     LBASSERT( isListening( ));
     101             : 
     102          24 :     const Configs& configs = getConfigs();
     103             : #ifndef EQUALIZER_USE_HWSD
     104             :     if( configs.empty( ))
     105             :         LBWARN << "No configurations loaded" << std::endl;
     106             : #endif
     107             : 
     108          72 :     LBDEBUG << lunchbox::disableFlush << lunchbox::disableHeader
     109          24 :            << "Running server: " << std::endl
     110          48 :            << lunchbox::indent << Global::instance() << *this
     111          24 :            << lunchbox::exdent << lunchbox::enableHeader
     112          72 :            << lunchbox::enableFlush << std::endl;
     113             : 
     114          28 :     for( Configs::const_iterator i = configs.begin(); i != configs.end(); ++i )
     115           4 :         (*i)->register_();
     116          24 : }
     117             : 
     118          24 : void Server::exit()
     119             : {
     120          24 :     const Configs& configs = getConfigs();
     121          28 :     for( Configs::const_iterator i = configs.begin(); i != configs.end(); ++i )
     122           4 :         (*i)->deregister();
     123          24 : }
     124             : 
     125          24 : void Server::run()
     126             : {
     127          24 :     init();
     128          24 :     handleCommands();
     129          24 :     exit();
     130          24 : }
     131             : 
     132         888 : void Server::deleteConfigs()
     133             : {
     134         888 :     const Configs& configs = getConfigs();
     135        2200 :     while( !configs.empty( ))
     136             :     {
     137         424 :         Config* config = configs.back();
     138         424 :         _removeConfig( config );
     139         424 :         delete config;
     140             :     }
     141         888 : }
     142             : 
     143             : //===========================================================================
     144             : // ICommand handling methods
     145             : //===========================================================================
     146          24 : void Server::handleCommands()
     147             : {
     148          24 :     _running = true;
     149         102 :     while( _running ) // set to false in _cmdShutdown()
     150             :     {
     151          54 :         const co::ICommands& commands = _mainThreadQueue.popAll();
     152          54 :         LBASSERT( !commands.empty( ));
     153             : 
     154          84 :         for( co::ICommandsCIter i = commands.begin(); i != commands.end(); ++i )
     155             :         {
     156             :             // We want to avoid a non-const copy of commands, hence the cast...
     157          54 :             co::ICommand& command = const_cast< co::ICommand& >( *i );
     158             : 
     159          54 :             if( !command( ))
     160             :             {
     161           0 :                 LBABORT( "Error handling " << command );
     162             :             }
     163          54 :             if( !_running )
     164          24 :                 break;
     165             :         }
     166          54 :     }
     167          24 :     _mainThreadQueue.flush();
     168          24 : }
     169             : 
     170           4 : bool Server::_cmdChooseConfig( co::ICommand& command )
     171             : {
     172           4 :     const uint32_t requestID = command.read< uint32_t >();
     173           4 :     const fabric::ConfigParams& params = command.read< fabric::ConfigParams >();
     174             : 
     175           4 :     LBVERB << "Handle choose config " << command << " req " << requestID
     176           0 :            << " renderer " << params.getWorkDir() << '/'
     177           4 :            << params.getRenderClient() << std::endl;
     178             : 
     179           4 :     Config* config = 0;
     180           4 :     const Configs& configs = getConfigs();
     181           8 :     for( ConfigsCIter i = configs.begin(); i != configs.end() && !config; ++i )
     182             :     {
     183           4 :         Config* candidate = *i;
     184           4 :         const float version = candidate->getFAttribute( Config::FATTR_VERSION );
     185           4 :         LBASSERT( version == 1.2f );
     186           4 :         if( !candidate->isUsed() && version == 1.2f )
     187           4 :             config = candidate;
     188             :     }
     189             : 
     190             : #ifdef EQUALIZER_USE_HWSD
     191           4 :     if( !config )
     192             :     {
     193           0 :         const std::string& configFile = command.read< std::string >();
     194           0 :         config = config::Server::configure( this, configFile, params );
     195           0 :         if( config )
     196             :         {
     197           0 :             config->register_();
     198           0 :             LBDEBUG << lunchbox::disableFlush << lunchbox::disableHeader
     199           0 :                    << "Configured:" << std::endl
     200           0 :                    << lunchbox::indent << Global::instance() << *this
     201           0 :                    << lunchbox::exdent << lunchbox::enableHeader
     202           0 :                    << lunchbox::enableFlush << std::endl;
     203           0 :         }
     204             :     }
     205             : #endif
     206             : 
     207           8 :     co::NodePtr node = command.getRemoteNode();
     208             : 
     209           4 :     if( !config )
     210             :     {
     211             :         node->send( fabric::CMD_SERVER_CHOOSE_CONFIG_REPLY )
     212           0 :             << uint128_t() << requestID;
     213           0 :         return true;
     214             :     }
     215             : 
     216           8 :     ConfigBackupVisitor backup;
     217           4 :     config->accept( backup );
     218           4 :     config->setApplicationNetNode( node );
     219           4 :     config->setWorkDir( params.getWorkDir( ));
     220           4 :     config->setRenderClient( params.getRenderClient( ));
     221           4 :     config->setRenderClientArgs( params.getRenderClientArgs( ));
     222           4 :     config->setRenderClientEnvPrefixes( params.getRenderClientEnvPrefixes( ));
     223           4 :     config->commit();
     224             : 
     225             :     node->send( fabric::CMD_SERVER_CREATE_CONFIG )
     226           4 :             << co::ObjectVersion( config ) << LB_UNDEFINED_UINT32;
     227             : 
     228           4 :     server::Node* appNode = config->findApplicationNode();
     229             :     const co::ConnectionDescriptions& descs =
     230           4 :         appNode->getConnectionDescriptions();
     231             : 
     232           4 :     if( config->getNodes().size() > 1 )
     233             :     {
     234           0 :         if( descs.empty() && node->getConnectionDescriptions().empty( ))
     235             :         {
     236           0 :             LBWARN << "Likely misconfiguration: Neither the application nor the"
     237           0 :                    << " config file has a connection for this multi-node "
     238           0 :                    << "config. Render clients will be unable to communicate "
     239           0 :                    << "with the application process." << std::endl;
     240             :         }
     241           0 :         if( getConnectionDescriptions().empty( ))
     242             :         {
     243           0 :             LBWARN << "Likely misconfiguration: The server has no listening "
     244           0 :                    << "connection for this multi-node config. Render clients "
     245           0 :                    << "will be unable to communicate with the server."
     246           0 :                    << std::endl;
     247             :         }
     248             :     }
     249             : 
     250             :     node->send( fabric::CMD_SERVER_CHOOSE_CONFIG_REPLY )
     251           4 :             << config->getID() << requestID << co::serialize( descs );
     252           8 :     return true;
     253             : }
     254             : 
     255          24 : bool Server::_cmdReleaseConfig( co::ICommand& command )
     256             : {
     257          24 :     const uint128_t& configID = command.read< uint128_t >();
     258          24 :     const uint32_t requestID = command.read< uint32_t >();
     259             : 
     260          24 :     LBVERB << "Handle release config " << command << " config " << configID
     261          24 :            << std::endl;
     262             : 
     263          24 :     co::NodePtr node = command.getRemoteNode();
     264             : 
     265          24 :     Config* config = 0;
     266          24 :     const Configs& configs = getConfigs();
     267          84 :     for( Configs::const_iterator i = configs.begin();
     268          84 :          i != configs.end() && !config; ++i )
     269             :     {
     270           4 :         Config* candidate = *i;
     271           4 :         if( candidate->getID() == configID )
     272           4 :             config = candidate;
     273             :     }
     274             : 
     275          24 :     if( !config )
     276             :     {
     277          20 :         LBWARN << "Release request for unknown config" << std::endl;
     278          20 :         node->send( fabric::CMD_SERVER_RELEASE_CONFIG_REPLY ) << requestID;
     279          20 :         return true;
     280             :     }
     281             : 
     282           4 :     if( config->isRunning( ))
     283             :     {
     284           0 :         LBWARN << "Release of running configuration" << std::endl;
     285           0 :         config->exit(); // Make sure config is exited
     286             :     }
     287             : 
     288           8 :     lunchbox::Request< void > request = registerRequest< void >();
     289             :     node->send( fabric::CMD_SERVER_DESTROY_CONFIG )
     290           4 :         << config->getID() << request;
     291           4 :     request.wait();
     292             : 
     293             : #ifdef EQUALIZER_USE_HWSD
     294           4 :     if( config->isAutoConfig( ))
     295             :     {
     296           0 :         LBASSERT( _admins.empty( ));
     297           0 :         config->deregister();
     298           0 :         config::Server::release( config );
     299             :     }
     300             :     else
     301             : #endif
     302             :     {
     303           4 :         ConfigRestoreVisitor restore;
     304           4 :         config->accept( restore );
     305           4 :         config->commit();
     306             :     }
     307             : 
     308           4 :     node->send( fabric::CMD_SERVER_RELEASE_CONFIG_REPLY ) << requestID;
     309           4 :     LBVERB << "Released config " << configID << std::endl;
     310          28 :     return true;
     311             : }
     312             : 
     313           4 : bool Server::_cmdDestroyConfigReply( co::ICommand& command )
     314             : {
     315           4 :     serveRequest( command.read< uint32_t >( ));
     316           4 :     return true;
     317             : }
     318             : 
     319          24 : bool Server::_cmdShutdown( co::ICommand& command )
     320             : {
     321          24 :     const uint32_t requestID = command.read< uint32_t >();
     322             : 
     323          24 :     co::NodePtr node = command.getRemoteNode();
     324             : 
     325          24 :     if( !_admins.empty( ))
     326             :     {
     327           0 :         LBWARN << "Ignoring shutdown request, " << _admins.size()
     328           0 :                << " admin clients connected" << std::endl;
     329             : 
     330           0 :         node->send( fabric::CMD_SERVER_SHUTDOWN_REPLY ) << requestID << false;
     331           0 :         return true;
     332             :     }
     333             : 
     334          24 :     const Configs& configs = getConfigs();
     335          28 :     for( Configs::const_iterator i = configs.begin(); i != configs.end(); ++i )
     336             :     {
     337           4 :         Config* candidate = *i;
     338           4 :         if( candidate->isUsed( ))
     339             :         {
     340           0 :             LBWARN << "Ignoring shutdown request due to used config"
     341           0 :                    << std::endl;
     342             : 
     343             :             node->send( fabric::CMD_SERVER_SHUTDOWN_REPLY )
     344           0 :                     << requestID << false;
     345           0 :             return true;
     346             :         }
     347             :     }
     348             : 
     349          24 :     LBDEBUG << "Shutting down server" << std::endl;
     350             : 
     351          24 :     _running = false;
     352          24 :     node->send( fabric::CMD_SERVER_SHUTDOWN_REPLY ) << requestID << true;
     353             : 
     354             : #ifndef WIN32
     355             :     // WAR for 2874188: Lockup at shutdown
     356          24 :     lunchbox::sleep( 100 );
     357             : #endif
     358             : 
     359          24 :     return true;
     360             : }
     361             : 
     362           0 : bool Server::_cmdMap( co::ICommand& command )
     363             : {
     364           0 :     co::NodePtr node = command.getRemoteNode();
     365           0 :     _admins.push_back( node );
     366             : 
     367           0 :     const Configs& configs = getConfigs();
     368           0 :     for( Configs::const_iterator i = configs.begin(); i != configs.end(); ++i )
     369             :     {
     370           0 :         Config* config = *i;
     371             :         node->send( fabric::CMD_SERVER_CREATE_CONFIG )
     372           0 :                 << co::ObjectVersion( config ) << LB_UNDEFINED_UINT32;
     373             :     }
     374             : 
     375           0 :     node->send( fabric::CMD_SERVER_MAP_REPLY ) << command.read< uint32_t >();
     376           0 :     return true;
     377             : }
     378             : 
     379           0 : bool Server::_cmdUnmap( co::ICommand& command )
     380             : {
     381           0 :     co::NodePtr node = command.getRemoteNode();
     382           0 :     co::Nodes::iterator i = lunchbox::find( _admins, node );
     383             : 
     384           0 :     LBASSERT( i != _admins.end( ));
     385           0 :     if( i != _admins.end( ))
     386             :     {
     387           0 :         _admins.erase( i );
     388           0 :         const Configs& configs = getConfigs();
     389           0 :         for( Configs::const_iterator j = configs.begin();
     390           0 :              j != configs.end(); ++j )
     391             :         {
     392           0 :             Config* config = *j;
     393             :             node->send( fabric::CMD_SERVER_DESTROY_CONFIG )
     394           0 :                     << config->getID() << LB_UNDEFINED_UINT32;
     395             :         }
     396             :     }
     397             : 
     398           0 :     node->send( fabric::CMD_SERVER_UNMAP_REPLY ) << command.read< uint32_t >();
     399           0 :     return true;
     400             : }
     401             : 
     402             : }
     403             : }
     404             : #include "../fabric/server.ipp"
     405             : template class eq::fabric::Server< co::Node, eq::server::Server,
     406             :                                    eq::server::Config,
     407             :                                    eq::server::NodeFactory,
     408             :                                    co::LocalNode, eq::server::ServerVisitor >;
     409             : 
     410             : /** @cond IGNORE */
     411             : template std::ostream&
     412          84 : eq::fabric::operator << ( std::ostream&, const eq::server::Super& );
     413             : /** @endcond */

Generated by: LCOV version 1.11