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

Generated by: LCOV version 1.11