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

Generated by: LCOV version 1.10