LCOV - code coverage report
Current view: top level - eq/server - server.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 132 191 69.1 %
Date: 2016-07-30 05:04:55 Functions: 14 16 87.5 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2013, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                    2010, Cedric Stalder <cedric.stalder@gmail.com>
       4             :  *               2010-2012, 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->commit();
     222             : 
     223             :     node->send( fabric::CMD_SERVER_CREATE_CONFIG )
     224           4 :             << co::ObjectVersion( config ) << LB_UNDEFINED_UINT32;
     225             : 
     226           4 :     server::Node* appNode = config->findApplicationNode();
     227             :     const co::ConnectionDescriptions& descs =
     228           4 :         appNode->getConnectionDescriptions();
     229             : 
     230           4 :     if( config->getNodes().size() > 1 )
     231             :     {
     232           0 :         if( descs.empty() && node->getConnectionDescriptions().empty( ))
     233             :         {
     234           0 :             LBWARN << "Likely misconfiguration: Neither the application nor the"
     235           0 :                    << " config file has a connection for this multi-node "
     236           0 :                    << "config. Render clients will be unable to communicate "
     237           0 :                    << "with the application process." << std::endl;
     238             :         }
     239           0 :         if( getConnectionDescriptions().empty( ))
     240             :         {
     241           0 :             LBWARN << "Likely misconfiguration: The server has no listening "
     242           0 :                    << "connection for this multi-node config. Render clients "
     243           0 :                    << "will be unable to communicate with the server."
     244           0 :                    << std::endl;
     245             :         }
     246             :     }
     247             : 
     248             :     node->send( fabric::CMD_SERVER_CHOOSE_CONFIG_REPLY )
     249           4 :             << config->getID() << requestID << co::serialize( descs );
     250           8 :     return true;
     251             : }
     252             : 
     253          24 : bool Server::_cmdReleaseConfig( co::ICommand& command )
     254             : {
     255          24 :     const uint128_t& configID = command.read< uint128_t >();
     256          24 :     const uint32_t requestID = command.read< uint32_t >();
     257             : 
     258          24 :     LBVERB << "Handle release config " << command << " config " << configID
     259          24 :            << std::endl;
     260             : 
     261          24 :     co::NodePtr node = command.getRemoteNode();
     262             : 
     263          24 :     Config* config = 0;
     264          24 :     const Configs& configs = getConfigs();
     265          84 :     for( Configs::const_iterator i = configs.begin();
     266          84 :          i != configs.end() && !config; ++i )
     267             :     {
     268           4 :         Config* candidate = *i;
     269           4 :         if( candidate->getID() == configID )
     270           4 :             config = candidate;
     271             :     }
     272             : 
     273          24 :     if( !config )
     274             :     {
     275          20 :         LBWARN << "Release request for unknown config" << std::endl;
     276          20 :         node->send( fabric::CMD_SERVER_RELEASE_CONFIG_REPLY ) << requestID;
     277          20 :         return true;
     278             :     }
     279             : 
     280           4 :     if( config->isRunning( ))
     281             :     {
     282           0 :         LBWARN << "Release of running configuration" << std::endl;
     283           0 :         config->exit(); // Make sure config is exited
     284             :     }
     285             : 
     286           8 :     lunchbox::Request< void > request = registerRequest< void >();
     287             :     node->send( fabric::CMD_SERVER_DESTROY_CONFIG )
     288           4 :         << config->getID() << request;
     289           4 :     request.wait();
     290             : 
     291             : #ifdef EQUALIZER_USE_HWSD
     292           4 :     if( config->isAutoConfig( ))
     293             :     {
     294           0 :         LBASSERT( _admins.empty( ));
     295           0 :         config->deregister();
     296           0 :         config::Server::release( config );
     297             :     }
     298             :     else
     299             : #endif
     300             :     {
     301           4 :         ConfigRestoreVisitor restore;
     302           4 :         config->accept( restore );
     303           4 :         config->commit();
     304             :     }
     305             : 
     306           4 :     node->send( fabric::CMD_SERVER_RELEASE_CONFIG_REPLY ) << requestID;
     307           4 :     LBVERB << "Released config " << configID << std::endl;
     308          28 :     return true;
     309             : }
     310             : 
     311           4 : bool Server::_cmdDestroyConfigReply( co::ICommand& command )
     312             : {
     313           4 :     serveRequest( command.read< uint32_t >( ));
     314           4 :     return true;
     315             : }
     316             : 
     317          24 : bool Server::_cmdShutdown( co::ICommand& command )
     318             : {
     319          24 :     const uint32_t requestID = command.read< uint32_t >();
     320             : 
     321          24 :     co::NodePtr node = command.getRemoteNode();
     322             : 
     323          24 :     if( !_admins.empty( ))
     324             :     {
     325           0 :         LBWARN << "Ignoring shutdown request, " << _admins.size()
     326           0 :                << " admin clients connected" << std::endl;
     327             : 
     328           0 :         node->send( fabric::CMD_SERVER_SHUTDOWN_REPLY ) << requestID << false;
     329           0 :         return true;
     330             :     }
     331             : 
     332          24 :     const Configs& configs = getConfigs();
     333          28 :     for( Configs::const_iterator i = configs.begin(); i != configs.end(); ++i )
     334             :     {
     335           4 :         Config* candidate = *i;
     336           4 :         if( candidate->isUsed( ))
     337             :         {
     338           0 :             LBWARN << "Ignoring shutdown request due to used config"
     339           0 :                    << std::endl;
     340             : 
     341             :             node->send( fabric::CMD_SERVER_SHUTDOWN_REPLY )
     342           0 :                     << requestID << false;
     343           0 :             return true;
     344             :         }
     345             :     }
     346             : 
     347          24 :     LBDEBUG << "Shutting down server" << std::endl;
     348             : 
     349          24 :     _running = false;
     350          24 :     node->send( fabric::CMD_SERVER_SHUTDOWN_REPLY ) << requestID << true;
     351             : 
     352             : #ifndef WIN32
     353             :     // WAR for 2874188: Lockup at shutdown
     354          24 :     lunchbox::sleep( 100 );
     355             : #endif
     356             : 
     357          24 :     return true;
     358             : }
     359             : 
     360           0 : bool Server::_cmdMap( co::ICommand& command )
     361             : {
     362           0 :     co::NodePtr node = command.getRemoteNode();
     363           0 :     _admins.push_back( node );
     364             : 
     365           0 :     const Configs& configs = getConfigs();
     366           0 :     for( Configs::const_iterator i = configs.begin(); i != configs.end(); ++i )
     367             :     {
     368           0 :         Config* config = *i;
     369             :         node->send( fabric::CMD_SERVER_CREATE_CONFIG )
     370           0 :                 << co::ObjectVersion( config ) << LB_UNDEFINED_UINT32;
     371             :     }
     372             : 
     373           0 :     node->send( fabric::CMD_SERVER_MAP_REPLY ) << command.read< uint32_t >();
     374           0 :     return true;
     375             : }
     376             : 
     377           0 : bool Server::_cmdUnmap( co::ICommand& command )
     378             : {
     379           0 :     co::NodePtr node = command.getRemoteNode();
     380           0 :     co::Nodes::iterator i = lunchbox::find( _admins, node );
     381             : 
     382           0 :     LBASSERT( i != _admins.end( ));
     383           0 :     if( i != _admins.end( ))
     384             :     {
     385           0 :         _admins.erase( i );
     386           0 :         const Configs& configs = getConfigs();
     387           0 :         for( Configs::const_iterator j = configs.begin();
     388           0 :              j != configs.end(); ++j )
     389             :         {
     390           0 :             Config* config = *j;
     391             :             node->send( fabric::CMD_SERVER_DESTROY_CONFIG )
     392           0 :                     << config->getID() << LB_UNDEFINED_UINT32;
     393             :         }
     394             :     }
     395             : 
     396           0 :     node->send( fabric::CMD_SERVER_UNMAP_REPLY ) << command.read< uint32_t >();
     397           0 :     return true;
     398             : }
     399             : 
     400             : }
     401             : }
     402             : #include "../fabric/server.ipp"
     403             : template class eq::fabric::Server< co::Node, eq::server::Server,
     404             :                                    eq::server::Config,
     405             :                                    eq::server::NodeFactory,
     406             :                                    co::LocalNode, eq::server::ServerVisitor >;
     407             : 
     408             : /** @cond IGNORE */
     409             : template std::ostream&
     410          84 : eq::fabric::operator << ( std::ostream&, const eq::server::Super& );
     411             : /** @endcond */

Generated by: LCOV version 1.11