LCOV - code coverage report
Current view: top level - eq/server - config.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 422 635 66.5 %
Date: 2017-12-16 05:07:20 Functions: 52 75 69.3 %

          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 "config.h"
      21             : 
      22             : #include "canvas.h"
      23             : #include "changeLatencyVisitor.h"
      24             : #include "compound.h"
      25             : #include "compoundVisitor.h"
      26             : #include "configUpdateDataVisitor.h"
      27             : #include "equalizers/equalizer.h"
      28             : #include "global.h"
      29             : #include "layout.h"
      30             : #include "log.h"
      31             : #include "node.h"
      32             : #include "observer.h"
      33             : #include "segment.h"
      34             : #include "server.h"
      35             : #include "view.h"
      36             : #include "window.h"
      37             : 
      38             : #include <eq/fabric/commands.h>
      39             : #include <eq/fabric/event.h>
      40             : #include <eq/fabric/iAttribute.h>
      41             : #include <eq/fabric/paths.h>
      42             : 
      43             : #include <co/objectICommand.h>
      44             : 
      45             : #include <boost/foreach.hpp>
      46             : #include <lunchbox/sleep.h>
      47             : 
      48             : #include "channelStopFrameVisitor.h"
      49             : #include "configDeregistrator.h"
      50             : #include "configRegistrator.h"
      51             : #include "configUpdateSyncVisitor.h"
      52             : #include "configUpdateVisitor.h"
      53             : #include "nodeFailedVisitor.h"
      54             : 
      55             : namespace eq
      56             : {
      57             : namespace server
      58             : {
      59             : typedef co::CommandFunc<Config> ConfigFunc;
      60             : using fabric::ON;
      61             : using fabric::OFF;
      62             : 
      63         404 : Config::Config(ServerPtr parent)
      64             :     : Super(parent)
      65             :     , _currentFrame(0)
      66             :     , _incarnation(1)
      67             :     , _finishedFrame(0)
      68             :     , _state(STATE_UNUSED)
      69             :     , _needsFinish(false)
      70             :     , _lastCheck(0)
      71         404 :     , _private(0)
      72             : {
      73         404 :     const Global* global = Global::instance();
      74        3232 :     for (int i = 0; i < FATTR_ALL; ++i)
      75             :     {
      76        2828 :         const FAttribute attr = static_cast<FAttribute>(i);
      77        2828 :         setFAttribute(attr, global->getConfigFAttribute(attr));
      78             :     }
      79        2828 :     for (int i = 0; i < IATTR_ALL; ++i)
      80             :     {
      81        2424 :         const IAttribute attr = static_cast<IAttribute>(i);
      82        2424 :         setIAttribute(attr, global->getConfigIAttribute(attr));
      83             :     }
      84         404 : }
      85             : 
      86        1206 : Config::~Config()
      87             : {
      88        1742 :     while (!_compounds.empty())
      89             :     {
      90         670 :         Compound* compound = _compounds.back();
      91         670 :         removeCompound(compound);
      92         670 :         delete compound;
      93             :     }
      94         804 : }
      95             : 
      96           2 : void Config::attach(const uint128_t& id, const uint32_t instanceID)
      97             : {
      98           2 :     Super::attach(id, instanceID);
      99             : 
     100           2 :     co::CommandQueue* mainQ = getMainThreadQueue();
     101           2 :     co::CommandQueue* cmdQ = getCommandThreadQueue();
     102             : 
     103           2 :     registerCommand(fabric::CMD_CONFIG_INIT,
     104           4 :                     ConfigFunc(this, &Config::_cmdInit), mainQ);
     105           2 :     registerCommand(fabric::CMD_CONFIG_EXIT,
     106           4 :                     ConfigFunc(this, &Config::_cmdExit), mainQ);
     107           2 :     registerCommand(fabric::CMD_CONFIG_UPDATE,
     108           4 :                     ConfigFunc(this, &Config::_cmdUpdate), mainQ);
     109           2 :     registerCommand(fabric::CMD_CONFIG_CREATE_REPLY,
     110           4 :                     ConfigFunc(this, &Config::_cmdCreateReply), cmdQ);
     111           2 :     registerCommand(fabric::CMD_CONFIG_START_FRAME,
     112           4 :                     ConfigFunc(this, &Config::_cmdStartFrame), mainQ);
     113           2 :     registerCommand(fabric::CMD_CONFIG_STOP_FRAMES,
     114           4 :                     ConfigFunc(this, &Config::_cmdStopFrames), mainQ);
     115           2 :     registerCommand(fabric::CMD_CONFIG_FINISH_ALL_FRAMES,
     116           4 :                     ConfigFunc(this, &Config::_cmdFinishAllFrames), mainQ);
     117           2 :     registerCommand(fabric::CMD_CONFIG_CHECK_FRAME,
     118           4 :                     ConfigFunc(this, &Config::_cmdCheckFrame), mainQ);
     119           2 : }
     120             : 
     121             : namespace
     122             : {
     123             : class ChannelViewFinder : public ConfigVisitor
     124             : {
     125             : public:
     126        2264 :     ChannelViewFinder(const Segment* const segment, const View* const view)
     127        2264 :         : _segment(segment)
     128             :         , _view(view)
     129        2264 :         , _result(0)
     130             :     {
     131        2264 :     }
     132             : 
     133        2264 :     virtual ~ChannelViewFinder() {}
     134       21920 :     virtual VisitorResult visit(Channel* channel)
     135             :     {
     136       21920 :         if (channel->getView() != _view)
     137       18248 :             return TRAVERSE_CONTINUE;
     138             : 
     139        3672 :         if (channel->getSegment() != _segment)
     140        2632 :             return TRAVERSE_CONTINUE;
     141             : 
     142        1040 :         _result = channel;
     143        1040 :         return TRAVERSE_TERMINATE;
     144             :     }
     145             : 
     146        2264 :     Channel* getResult() { return _result; }
     147             : private:
     148             :     const Segment* const _segment;
     149             :     const View* const _view;
     150             :     Channel* _result;
     151             : };
     152             : 
     153           2 : class UpdateEqualizersVisitor : public ConfigVisitor
     154             : {
     155             : public:
     156           2 :     UpdateEqualizersVisitor() {}
     157             :     // No need to go down on nodes.
     158           2 :     VisitorResult visitPre(Node*) override { return TRAVERSE_PRUNE; }
     159         132 :     VisitorResult visit(Compound* compound) override
     160             :     {
     161         132 :         Channel* dest = compound->getInheritChannel();
     162         132 :         if (!dest)
     163          14 :             return TRAVERSE_CONTINUE;
     164             : 
     165         118 :         View* view = dest->getView();
     166         118 :         if (!view)
     167           0 :             return TRAVERSE_CONTINUE;
     168             : 
     169         118 :         const Equalizers& equalizers = compound->getEqualizers();
     170         136 :         for (EqualizersCIter i = equalizers.begin(); i != equalizers.end(); ++i)
     171          18 :             view->getEqualizer() = *(*i);
     172             : 
     173         118 :         return TRAVERSE_CONTINUE;
     174             :     }
     175             : };
     176             : }
     177             : 
     178         398 : const Channel* Config::findChannel(const std::string& name) const
     179             : {
     180         398 :     return Super::find<Channel>(name);
     181             : }
     182             : 
     183        2264 : Channel* Config::findChannel(const Segment* segment, const View* view)
     184             : {
     185        4528 :     ChannelViewFinder finder(segment, view);
     186        2264 :     accept(finder);
     187        4528 :     return finder.getResult();
     188             : }
     189             : 
     190         404 : Node* Config::findApplicationNode()
     191             : {
     192         404 :     const Nodes& nodes = getNodes();
     193         404 :     for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
     194             :     {
     195         404 :         Node* node = *i;
     196         404 :         if (node->isApplicationNode())
     197         404 :             return node;
     198             :     }
     199           0 :     return 0;
     200             : }
     201             : 
     202           6 : co::NodePtr Config::findApplicationNetNode()
     203             : {
     204           6 :     Node* node = findApplicationNode();
     205           6 :     LBASSERT(node);
     206           6 :     return node ? node->getNode() : 0;
     207             : }
     208             : 
     209         420 : void Config::activateCanvas(Canvas* canvas)
     210             : {
     211         420 :     LBASSERT(canvas->isStopped());
     212         420 :     LBASSERT(lunchbox::find(getCanvases(), canvas) != getCanvases().end());
     213             : 
     214         420 :     const Layouts& layouts = canvas->getLayouts();
     215         420 :     const Segments& segments = canvas->getSegments();
     216             : 
     217        1076 :     for (Layouts::const_iterator i = layouts.begin(); i != layouts.end(); ++i)
     218             :     {
     219         656 :         const Layout* layout = *i;
     220         656 :         if (!layout)
     221           4 :             continue;
     222             : 
     223         652 :         const Views& views = layout->getViews();
     224        1372 :         for (Views::const_iterator j = views.begin(); j != views.end(); ++j)
     225             :         {
     226         720 :             View* view = *j;
     227             : 
     228        7164 :             for (Segments::const_iterator k = segments.begin();
     229        4776 :                  k != segments.end(); ++k)
     230             :             {
     231        1668 :                 Segment* segment = *k;
     232        1668 :                 Viewport viewport = segment->getViewport();
     233        1668 :                 viewport.intersect(view->getViewport());
     234             : 
     235        1668 :                 if (!viewport.hasArea())
     236             :                 {
     237         444 :                     LBLOG(LOG_VIEW)
     238           0 :                         << "View " << view->getName() << view->getViewport()
     239           0 :                         << " doesn't intersect " << segment->getName()
     240         444 :                         << segment->getViewport() << std::endl;
     241             : 
     242         888 :                     continue;
     243             :                 }
     244             : 
     245        1224 :                 Channel* segmentChannel = segment->getChannel();
     246        1224 :                 if (!segmentChannel)
     247             :                 {
     248           0 :                     LBWARN << "Segment " << segment->getName()
     249           0 :                            << " has no output channel" << std::endl;
     250           0 :                     continue;
     251             :                 }
     252             : 
     253        1224 :                 if (findChannel(segment, view))
     254           0 :                     continue;
     255             : 
     256             :                 // create and add new channel
     257        1224 :                 Channel* channel = new Channel(*segmentChannel);
     258        1224 :                 channel->init(); // not in ctor, virtual method
     259        1224 :                 channel->setOutput(view, segment);
     260             : 
     261             :                 //----- compute channel viewport:
     262             :                 // segment/view intersection in canvas space...
     263        1224 :                 Viewport contribution = viewport;
     264             :                 // ... in segment space...
     265        1224 :                 contribution.transform(segment->getViewport());
     266             : 
     267             :                 // segment output area
     268        1224 :                 if (segmentChannel->hasFixedViewport())
     269             :                 {
     270        1212 :                     Viewport subViewport = segmentChannel->getViewport();
     271        1212 :                     LBASSERT(subViewport.isValid());
     272        1212 :                     if (!subViewport.isValid())
     273           0 :                         subViewport = eq::fabric::Viewport::FULL;
     274             : 
     275             :                     // ...our part of it
     276        1212 :                     subViewport.apply(contribution);
     277        1212 :                     channel->setViewport(subViewport);
     278        1212 :                     LBLOG(LOG_VIEW)
     279           0 :                         << "View @" << (void*)view << ' ' << view->getViewport()
     280           0 :                         << " intersects " << segment->getName()
     281           0 :                         << segment->getViewport() << " at " << subViewport
     282        1212 :                         << " using channel @" << (void*)channel << std::endl;
     283             :                 }
     284             :                 else
     285             :                 {
     286          12 :                     PixelViewport pvp = segmentChannel->getPixelViewport();
     287          12 :                     LBASSERT(pvp.isValid());
     288          12 :                     pvp.apply(contribution);
     289          12 :                     channel->setPixelViewport(pvp);
     290          12 :                     LBLOG(LOG_VIEW)
     291           0 :                         << "View @" << (void*)view << ' ' << view->getViewport()
     292           0 :                         << " intersects " << segment->getName()
     293           0 :                         << segment->getViewport() << " at " << pvp
     294          12 :                         << " using channel @" << (void*)channel << std::endl;
     295             :                 }
     296             : 
     297        1224 :                 if (channel->getWindow()->isAttached())
     298             :                     // parent is already registered - register channel as well
     299           0 :                     getServer()->registerObject(channel);
     300             :             }
     301             :         }
     302             :     }
     303         420 : }
     304             : 
     305           0 : void Config::updateCanvas(Canvas* canvas)
     306             : {
     307           0 :     postNeedsFinish();
     308           0 :     activateCanvas(canvas);
     309             : 
     310             :     // Create one compound group for all new output channels of each layout
     311           0 :     const Layouts& layouts = canvas->getLayouts();
     312           0 :     for (LayoutsCIter i = layouts.begin(); i != layouts.end(); ++i)
     313             :     {
     314           0 :         Compound* group = new Compound(this);
     315             : 
     316           0 :         const Layout* layout = *i;
     317           0 :         const Views& views = layout->getViews();
     318           0 :         for (ViewsCIter j = views.begin(); j != views.end(); ++j)
     319             :         {
     320           0 :             const View* view = *j;
     321           0 :             const Channels& channels = view->getChannels();
     322             : 
     323           0 :             if (channels.empty())
     324           0 :                 LBWARN << "View without destination channels will be ignored"
     325           0 :                        << std::endl;
     326             : 
     327           0 :             for (ChannelsCIter k = channels.begin(); k != channels.end(); ++k)
     328             :             {
     329           0 :                 Channel* channel = *k;
     330           0 :                 LBASSERT(!channel->isActive());
     331             : 
     332           0 :                 Compound* compound = new Compound(group);
     333             :                 compound->setIAttribute(Compound::IATTR_STEREO_MODE,
     334           0 :                                         fabric::AUTO);
     335           0 :                 compound->setChannel(channel);
     336             :             }
     337             :         }
     338           0 :         group->init();
     339             :     }
     340             : 
     341           0 :     canvas->init();
     342           0 :     LBDEBUG << *this << std::endl;
     343           0 : }
     344             : 
     345           0 : Observer* Config::createObserver()
     346             : {
     347           0 :     return new Observer(this);
     348             : }
     349             : 
     350           0 : void Config::releaseObserver(Observer* observer)
     351             : {
     352           0 :     delete observer;
     353           0 : }
     354             : 
     355           0 : Layout* Config::createLayout()
     356             : {
     357           0 :     return new Layout(this);
     358             : }
     359             : 
     360           0 : void Config::releaseLayout(Layout* layout)
     361             : {
     362           0 :     delete layout;
     363           0 : }
     364             : 
     365           0 : Canvas* Config::createCanvas()
     366             : {
     367           0 :     return new Canvas(this);
     368             : }
     369             : 
     370           0 : void Config::releaseCanvas(Canvas* canvas)
     371             : {
     372           0 :     delete canvas;
     373           0 : }
     374             : 
     375             : template <class T>
     376           0 : bool Config::_postDelete(const uint128_t& id)
     377             : {
     378           0 :     T* child = find<T>(id);
     379           0 :     if (!child)
     380           0 :         return false;
     381             : 
     382           0 :     child->postDelete();
     383           0 :     return true;
     384             : }
     385             : 
     386           0 : void Config::removeChild(const uint128_t& id)
     387             : {
     388           0 :     LBASSERT(isRunning());
     389             : 
     390           0 :     if (_postDelete<Observer>(id) || _postDelete<Layout>(id) ||
     391           0 :         _postDelete<Canvas>(id))
     392             :     {
     393           0 :         return;
     394             :     }
     395           0 :     LBUNIMPLEMENTED;
     396             : }
     397             : 
     398         670 : void Config::addCompound(Compound* compound)
     399             : {
     400         670 :     LBASSERT(compound->_config == this);
     401         670 :     _compounds.push_back(compound);
     402         670 : }
     403             : 
     404        1340 : bool Config::removeCompound(Compound* compound)
     405             : {
     406        1340 :     LBASSERT(compound->_config == this);
     407        1340 :     Compounds::iterator i = lunchbox::find(_compounds, compound);
     408        1340 :     if (i == _compounds.end())
     409         670 :         return false;
     410             : 
     411         670 :     _compounds.erase(i);
     412         670 :     return true;
     413             : }
     414             : 
     415           2 : void Config::setApplicationNetNode(co::NodePtr netNode)
     416             : {
     417           2 :     if (netNode.isValid())
     418             :     {
     419           2 :         LBASSERT(_state == STATE_UNUSED);
     420           2 :         _state = STATE_STOPPED;
     421           2 :         setAppNodeID(netNode->getNodeID());
     422             :     }
     423             :     else
     424             :     {
     425           0 :         LBASSERT(_state == STATE_STOPPED);
     426           0 :         _state = STATE_UNUSED;
     427           0 :         setAppNodeID(uint128_t());
     428             :     }
     429             : 
     430           2 :     Node* node = findApplicationNode();
     431           2 :     LBASSERT(node);
     432           2 :     if (node)
     433           2 :         node->setNode(netNode);
     434           2 : }
     435             : 
     436           0 : Channel* Config::getChannel(const ChannelPath& path)
     437             : {
     438           0 :     Nodes nodes = getNodes();
     439           0 :     LBASSERTINFO(nodes.size() > path.nodeIndex, nodes.size() << " <= "
     440             :                                                              << path.nodeIndex);
     441             : 
     442           0 :     if (nodes.size() <= path.nodeIndex)
     443           0 :         return 0;
     444             : 
     445           0 :     return nodes[path.nodeIndex]->getChannel(path);
     446             : }
     447             : 
     448        1442 : Segment* Config::getSegment(const SegmentPath& path)
     449             : {
     450        1442 :     Canvas* canvas = getCanvas(path);
     451        1442 :     LBASSERT(canvas);
     452             : 
     453        1442 :     if (canvas)
     454        1442 :         return canvas->getSegment(path);
     455             : 
     456           0 :     return 0;
     457             : }
     458             : 
     459        1246 : View* Config::getView(const ViewPath& path)
     460             : {
     461        1246 :     Layout* layout = getLayout(path);
     462        1246 :     LBASSERT(layout);
     463             : 
     464        1246 :     if (layout)
     465        1246 :         return layout->getView(path);
     466             : 
     467           0 :     return 0;
     468             : }
     469             : 
     470             : namespace
     471             : {
     472             : template <class C>
     473        2374 : static VisitorResult _accept(C* config, ConfigVisitor& visitor)
     474             : {
     475        2374 :     VisitorResult result = TRAVERSE_CONTINUE;
     476        2374 :     const Compounds& compounds = config->getCompounds();
     477        4984 :     for (Compounds::const_iterator i = compounds.begin(); i != compounds.end();
     478             :          ++i)
     479             :     {
     480        3032 :         switch ((*i)->accept(visitor))
     481             :         {
     482             :         case TRAVERSE_TERMINATE:
     483         422 :             return TRAVERSE_TERMINATE;
     484             : 
     485             :         case TRAVERSE_PRUNE:
     486        1308 :             result = TRAVERSE_PRUNE;
     487        1308 :             break;
     488             : 
     489             :         case TRAVERSE_CONTINUE:
     490             :         default:
     491        1302 :             break;
     492             :         }
     493             :     }
     494        1952 :     return result;
     495             : }
     496             : }
     497             : 
     498        2374 : VisitorResult Config::_acceptCompounds(ConfigVisitor& visitor)
     499             : {
     500        2374 :     return _accept(this, visitor);
     501             : }
     502             : 
     503           0 : VisitorResult Config::_acceptCompounds(ConfigVisitor& visitor) const
     504             : {
     505           0 :     return _accept(this, visitor);
     506             : }
     507             : 
     508             : //===========================================================================
     509             : // operations
     510             : //===========================================================================
     511             : 
     512           2 : void Config::register_()
     513             : {
     514           4 :     ConfigRegistrator registrator;
     515           2 :     accept(registrator);
     516           2 : }
     517             : 
     518           2 : void Config::deregister()
     519             : {
     520           2 :     sync();
     521           4 :     ConfigDeregistrator deregistrator;
     522           2 :     accept(deregistrator);
     523           2 : }
     524             : 
     525          12 : uint128_t Config::commit()
     526             : {
     527          12 :     return Super::commit(_incarnation);
     528             : }
     529             : 
     530           0 : void Config::restore()
     531             : {
     532           0 :     _currentFrame = 0;
     533           0 :     _finishedFrame = 0;
     534           0 :     setApplicationNetNode(0);
     535           0 :     _workDir.clear();
     536           0 :     _renderClient.clear();
     537           0 :     Super::restore();
     538           0 : }
     539             : 
     540           0 : EventOCommand Config::sendError(const uint32_t type, const Error& error)
     541             : {
     542           0 :     return Super::sendError(findApplicationNetNode(), type, error);
     543             : }
     544             : 
     545             : //---------------------------------------------------------------------------
     546             : // update running entities (init/exit/runtime change)
     547             : //---------------------------------------------------------------------------
     548           4 : bool Config::_updateRunning(const bool canFail)
     549             : {
     550           4 :     if (_state == STATE_STOPPED)
     551           0 :         return true;
     552             : 
     553           4 :     LBASSERT(_state == STATE_RUNNING || _state == STATE_INITIALIZING ||
     554             :              _state == STATE_EXITING);
     555             : 
     556           4 :     if (!_connectNodes() && !canFail)
     557           0 :         return false;
     558             : 
     559           4 :     _startNodes();
     560           4 :     _updateCanvases();
     561           4 :     const bool result = _updateNodes(canFail);
     562           4 :     _stopNodes();
     563             : 
     564             :     // Don't use visitor, it would get confused with modified child vectors
     565           4 :     _deleteEntities(getCanvases());
     566           4 :     _deleteEntities(getLayouts());
     567           4 :     _deleteEntities(getObservers());
     568           4 :     const Nodes& nodes = getNodes();
     569           8 :     for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
     570             :     {
     571           4 :         const Pipes& pipes = (*i)->getPipes();
     572          12 :         for (Pipes::const_iterator j = pipes.begin(); j != pipes.end(); ++j)
     573             :         {
     574           8 :             const Windows& windows = (*j)->getWindows();
     575           8 :             _deleteEntities(windows);
     576             :         }
     577             :     }
     578             : 
     579           4 :     return result;
     580             : }
     581             : 
     582           4 : bool Config::_connectNodes()
     583             : {
     584           4 :     bool success = true;
     585           8 :     lunchbox::Clock clock;
     586           4 :     const Nodes& nodes = getNodes();
     587           8 :     for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
     588             :     {
     589           4 :         Node* node = *i;
     590           4 :         if (!node->isActive())
     591           2 :             continue;
     592             : 
     593           2 :         if (!node->connect())
     594           0 :             success = false;
     595             :     }
     596             : 
     597           8 :     for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
     598             :     {
     599           4 :         Node* node = *i;
     600           4 :         if (node->isActive() && !node->syncLaunch(clock))
     601           0 :             success = false;
     602             :     }
     603             : 
     604           8 :     return success;
     605             : }
     606             : 
     607           4 : void Config::_startNodes()
     608             : {
     609             :     // start up newly running nodes
     610           8 :     std::vector<lunchbox::Request<void>> requests;
     611           4 :     const Nodes& nodes = getNodes();
     612           4 :     requests.reserve(nodes.size());
     613             : 
     614           8 :     BOOST_FOREACH (Node* node, nodes)
     615             :     {
     616           4 :         if (node->isActive() && node->isStopped())
     617             :         {
     618           2 :             if (!node->isApplicationNode())
     619           0 :                 requests.push_back(_createConfig(node));
     620             :         }
     621             :         else
     622             :         {
     623           2 :             LBASSERT(!node->isActive() || node->getState() == STATE_FAILED ||
     624             :                      node->getState() == STATE_RUNNING);
     625             :         }
     626             :     }
     627             :     // Request dtor waits for finish
     628           4 : }
     629             : 
     630           4 : void Config::_updateCanvases()
     631             : {
     632           4 :     const Canvases& canvases = getCanvases();
     633           8 :     for (Canvases::const_iterator i = canvases.begin(); i != canvases.end();
     634             :          ++i)
     635             :     {
     636           4 :         Canvas* canvas = *i;
     637           4 :         if (canvas->needsDelete())
     638           0 :             canvas->exit();
     639             :     }
     640           4 : }
     641             : 
     642           4 : void Config::_stopNodes()
     643             : {
     644             :     // wait for the nodes to stop, destroy entities, disconnect
     645           8 :     Nodes stoppingNodes;
     646           4 :     const Nodes& nodes = getNodes();
     647           8 :     for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
     648             :     {
     649           4 :         Node* node = *i;
     650           4 :         const State state = node->getState();
     651           4 :         if (state != STATE_STOPPED && state != STATE_FAILED)
     652           6 :             continue;
     653             : 
     654           2 :         LBASSERT(!node->isActive() || state == STATE_FAILED);
     655           2 :         if (node->isApplicationNode())
     656           2 :             continue;
     657             : 
     658           0 :         co::NodePtr netNode = node->getNode();
     659           0 :         if (!netNode) // already disconnected
     660           0 :             continue;
     661             : 
     662           0 :         LBLOG(LOG_INIT) << "Exiting node" << std::endl;
     663             : 
     664           0 :         if (state == STATE_FAILED)
     665           0 :             node->setState(STATE_STOPPED);
     666             : 
     667           0 :         stoppingNodes.push_back(node);
     668           0 :         LBASSERT(netNode.isValid());
     669             : 
     670           0 :         netNode->send(fabric::CMD_SERVER_DESTROY_CONFIG) << getID()
     671           0 :                                                          << LB_UNDEFINED_UINT32;
     672           0 :         netNode->send(fabric::CMD_CLIENT_EXIT);
     673             :     }
     674             : 
     675             :     // now wait that the render clients disconnect
     676           4 :     uint32_t nSleeps = 50; // max 5 seconds for all clients
     677          12 :     for (Nodes::const_iterator i = stoppingNodes.begin();
     678           8 :          i != stoppingNodes.end(); ++i)
     679             :     {
     680           0 :         Node* node = *i;
     681           0 :         co::NodePtr netNode = node->getNode();
     682           0 :         node->setNode(0);
     683             : 
     684           0 :         if (nSleeps)
     685           0 :             while (netNode->isConnected() && --nSleeps)
     686           0 :                 lunchbox::sleep(100); // ms
     687             : 
     688           0 :         if (netNode->isConnected())
     689             :         {
     690           0 :             co::LocalNodePtr localNode = getLocalNode();
     691           0 :             LBASSERT(localNode.isValid());
     692             : 
     693           0 :             LBWARN << "Forcefully disconnecting exited render client node"
     694           0 :                    << std::endl;
     695           0 :             localNode->disconnect(netNode);
     696             :         }
     697             : 
     698           0 :         LBLOG(LOG_INIT) << "Disconnected node" << std::endl;
     699             :     }
     700           4 : }
     701             : 
     702           4 : bool Config::_updateNodes(const bool canFail)
     703             : {
     704           8 :     ConfigUpdateVisitor update(_initID, _currentFrame);
     705           4 :     accept(update);
     706             : 
     707           8 :     ConfigUpdateSyncVisitor syncUpdate;
     708           4 :     accept(syncUpdate);
     709             : 
     710           4 :     const bool failure = syncUpdate.hadFailure();
     711             : 
     712           4 :     if (syncUpdate.needsSync()) // init failure, call again (exit pending)
     713             :     {
     714           0 :         LBASSERT(failure);
     715           0 :         accept(syncUpdate);
     716           0 :         LBASSERT(!syncUpdate.needsSync());
     717             :     }
     718             : 
     719           4 :     if (syncUpdate.getNumRunningChannels() == 0 && !canFail)
     720             :     {
     721           0 :         LBWARN << "Config has no running channels, will exit" << std::endl;
     722           0 :         return false;
     723             :     }
     724             : 
     725           4 :     return !failure;
     726             : }
     727             : 
     728             : template <class T>
     729          20 : void Config::_deleteEntities(const std::vector<T*>& entities)
     730             : {
     731          64 :     for (size_t i = 0; i < entities.size();) // don't use iterator! (delete)
     732             :     {
     733          44 :         T* entity = entities[i];
     734          44 :         if (entity->needsDelete())
     735             :         {
     736           0 :             LBASSERT(entity->isAttached());
     737           0 :             getServer()->deregisterObject(entity);
     738           0 :             delete entity;
     739             :         }
     740             :         else
     741          44 :             ++i;
     742             :     }
     743          20 : }
     744             : 
     745           0 : lunchbox::Request<void> Config::_createConfig(Node* node)
     746             : {
     747           0 :     LBASSERT(!node->isApplicationNode());
     748           0 :     LBASSERT(node->isActive());
     749             : 
     750             :     // create config on each non-app node
     751             :     //   app-node already has config from chooseConfig
     752           0 :     lunchbox::Request<void> request = getLocalNode()->registerRequest<void>();
     753             : 
     754           0 :     node->getNode()->send(fabric::CMD_SERVER_CREATE_CONFIG)
     755           0 :         << co::ObjectVersion(this) << request;
     756           0 :     return request;
     757             : }
     758             : 
     759           2 : void Config::_syncClock()
     760             : {
     761           2 :     const Nodes& nodes = getNodes();
     762           4 :     for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
     763             :     {
     764           2 :         Node* node = *i;
     765           2 :         if (node->isRunning() || node->isApplicationNode())
     766             :         {
     767           2 :             LBASSERT(node->isApplicationNode() || node->isActive());
     768           4 :             co::NodePtr netNode = node->getNode();
     769           2 :             LBASSERT(netNode->isConnected());
     770             : 
     771           4 :             send(netNode, fabric::CMD_CONFIG_SYNC_CLOCK)
     772           6 :                 << getServer()->getTime();
     773             :         }
     774             :     }
     775           2 : }
     776             : 
     777             : //---------------------------------------------------------------------------
     778             : // init
     779             : //---------------------------------------------------------------------------
     780           2 : bool Config::_init(const uint128_t& initID)
     781             : {
     782           2 :     LBASSERT(_state == STATE_STOPPED);
     783           2 :     _state = STATE_INITIALIZING;
     784           2 :     _currentFrame = 0;
     785           2 :     _finishedFrame = 0;
     786           2 :     _initID = initID;
     787             : 
     788          16 :     for (auto compound : _compounds)
     789          14 :         compound->init();
     790             : 
     791           4 :     for (auto observer : getObservers())
     792           2 :         observer->init();
     793             : 
     794           4 :     for (auto canvas : getCanvases())
     795           2 :         canvas->init();
     796             : 
     797           2 :     const auto& layouts = getLayouts();
     798          16 :     for (auto layout : layouts)
     799          28 :         for (auto view : layout->getViews())
     800          14 :             view->init();
     801             : 
     802             :     // any of the above entities might have been updated
     803           2 :     commit();
     804             : 
     805           2 :     if (!_updateRunning(false))
     806           0 :         return false;
     807             : 
     808             :     // Needed to set up active state for first LB update
     809          16 :     for (CompoundsCIter i = _compounds.begin(); i != _compounds.end(); ++i)
     810          14 :         (*i)->update(0);
     811             : 
     812             :     // Update equalizer properties in views
     813           4 :     UpdateEqualizersVisitor updater;
     814           2 :     accept(updater);
     815             : 
     816           2 :     _needsFinish = false;
     817           2 :     _state = STATE_RUNNING;
     818           2 :     return true;
     819             : }
     820             : 
     821             : //---------------------------------------------------------------------------
     822             : // exit
     823             : //---------------------------------------------------------------------------
     824           2 : bool Config::exit()
     825             : {
     826           2 :     if (_state != STATE_RUNNING)
     827           0 :         LBWARN << "Exiting non-initialized config" << std::endl;
     828             : 
     829           2 :     LBASSERT(_state == STATE_RUNNING || _state == STATE_INITIALIZING);
     830           2 :     _state = STATE_EXITING;
     831             : 
     832           2 :     const Canvases& canvases = getCanvases();
     833           4 :     for (Canvases::const_iterator i = canvases.begin(); i != canvases.end();
     834             :          ++i)
     835             :     {
     836           2 :         Canvas* canvas = *i;
     837           2 :         canvas->exit();
     838             :     }
     839             : 
     840          48 :     for (Compounds::const_iterator i = _compounds.begin();
     841          32 :          i != _compounds.end(); ++i)
     842             :     {
     843          14 :         Compound* compound = *i;
     844          14 :         compound->exit();
     845             :     }
     846             : 
     847           2 :     const bool success = _updateRunning(true);
     848             : 
     849             :     // send exit event to app, needed if this is called from init()
     850           4 :     EventOCommand cmd(send(findApplicationNetNode(), fabric::CMD_CONFIG_EVENT));
     851           2 :     Event event;
     852           2 :     event.serial = getSerial();
     853           2 :     event.time = getServer()->getTime();
     854           2 :     event.originator = getID();
     855           2 :     cmd << EVENT_EXIT << event;
     856             : 
     857           2 :     _needsFinish = false;
     858           2 :     _state = STATE_STOPPED;
     859           4 :     return success;
     860             : }
     861             : 
     862             : //---------------------------------------------------------------------------
     863             : // frame
     864             : //---------------------------------------------------------------------------
     865           2 : void Config::_startFrame(const uint128_t& frameID)
     866             : {
     867           2 :     LBASSERT(_state == STATE_RUNNING);
     868           2 :     _verifyFrameFinished(_currentFrame);
     869           2 :     _syncClock();
     870             : 
     871           2 :     ++_currentFrame;
     872           2 :     ++_incarnation;
     873           2 :     LBLOG(LOG_TASKS) << "----- Start Frame ----- " << _currentFrame
     874           2 :                      << std::endl;
     875             : 
     876          48 :     for (Compounds::const_iterator i = _compounds.begin();
     877          32 :          i != _compounds.end(); ++i)
     878             :     {
     879          14 :         Compound* compound = *i;
     880          14 :         compound->update(_currentFrame);
     881             :     }
     882             : 
     883           4 :     ConfigUpdateDataVisitor configDataVisitor;
     884           2 :     accept(configDataVisitor);
     885             : 
     886           2 :     const Nodes& nodes = getNodes();
     887           4 :     co::NodePtr appNode = findApplicationNetNode();
     888           4 :     for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
     889             :     {
     890           2 :         Node* node = *i;
     891           2 :         node->update(frameID, _currentFrame);
     892           2 :         if (node->isRunning() && node->isApplicationNode())
     893           2 :             appNode = 0; // release sent (see below)
     894             :     }
     895             : 
     896           2 :     if (appNode) // release appNode local sync
     897           0 :         send(appNode, fabric::CMD_CONFIG_RELEASE_FRAME_LOCAL) << _currentFrame;
     898             : 
     899             :     // Fix 2976899: Config::finishFrame deadlocks when no nodes are active
     900           2 :     notifyNodeFrameFinished(_currentFrame);
     901           2 : }
     902             : 
     903           2 : void Config::_verifyFrameFinished(const uint32_t frameNumber)
     904             : {
     905           2 :     const Nodes& nodes = getNodes();
     906           4 :     for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
     907             :     {
     908           2 :         Node* node = *i;
     909           4 :         if (node->isRunning() &&
     910           2 :             node->getFinishedFrame() + getLatency() < frameNumber)
     911             :         {
     912           0 :             NodeFailedVisitor nodeFailedVisitor;
     913           0 :             node->accept(nodeFailedVisitor);
     914             :         }
     915             :     }
     916           2 : }
     917             : 
     918           4 : void Config::notifyNodeFrameFinished(const uint32_t frameNumber)
     919             : {
     920           4 :     if (_finishedFrame >= frameNumber) // node finish already done
     921           0 :         return;
     922             : 
     923           4 :     const Nodes& nodes = getNodes();
     924           6 :     for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
     925             :     {
     926           4 :         const Node* node = *i;
     927           4 :         if (node->isRunning() && node->getFinishedFrame() < frameNumber)
     928             :         {
     929           2 :             LBASSERT(_needsFinish || node->isActive());
     930           4 :             return;
     931             :         }
     932             :     }
     933             : 
     934           2 :     _finishedFrame = frameNumber;
     935             : 
     936             :     // All nodes have finished the frame. Notify the application's config that
     937             :     // the frame is finished
     938             : 
     939             :     // do not use send/_bufferedTasks, not thread-safe!
     940           4 :     send(findApplicationNetNode(), fabric::CMD_CONFIG_FRAME_FINISH)
     941           2 :         << frameNumber;
     942           2 :     LBLOG(LOG_TASKS) << "TASK config frame finished  "
     943           2 :                      << " frame " << frameNumber << std::endl;
     944             : }
     945             : 
     946           2 : void Config::_flushAllFrames()
     947             : {
     948           2 :     if (_currentFrame == 0)
     949           0 :         return;
     950             : 
     951           2 :     const Nodes& nodes = getNodes();
     952           4 :     for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
     953             :     {
     954           2 :         Node* node = *i;
     955           2 :         if (node->isRunning())
     956           2 :             node->flushFrames(_currentFrame);
     957             :     }
     958             : 
     959           2 :     LBLOG(LOG_TASKS) << "--- Flush All Frames -- " << std::endl;
     960             : }
     961             : 
     962           0 : void Config::changeLatency(const uint32_t latency)
     963             : {
     964           0 :     if (getLatency() == latency)
     965           0 :         return;
     966             : 
     967           0 :     setLatency(latency);
     968             : 
     969             :     // update latency on all frames and barriers
     970           0 :     ChangeLatencyVisitor visitor(latency);
     971           0 :     accept(visitor);
     972             : }
     973             : 
     974             : //---------------------------------------------------------------------------
     975             : // command handlers
     976             : //---------------------------------------------------------------------------
     977           2 : bool Config::_cmdInit(co::ICommand& cmd)
     978             : {
     979           4 :     co::ObjectICommand command(cmd);
     980             : 
     981           2 :     LB_TS_THREAD(_mainThread);
     982           2 :     LBVERB << "handle config start init " << command << std::endl;
     983             : 
     984           2 :     sync();
     985           2 :     commit();
     986             : 
     987           2 :     const uint128_t& initID = command.read<uint128_t>();
     988           2 :     const uint32_t requestID = command.read<uint32_t>();
     989           2 :     const bool result = _init(initID);
     990             : 
     991           2 :     if (!result)
     992           0 :         exit();
     993             : 
     994           2 :     sync();
     995           6 :     LBDEBUG << "Config init " << (result ? "successful" : "failed")
     996           6 :             << std::endl;
     997             : 
     998           2 :     const uint128_t version = commit();
     999           4 :     send(command.getRemoteNode(), fabric::CMD_CONFIG_INIT_REPLY)
    1000           2 :         << version << requestID << result;
    1001           4 :     return true;
    1002             : }
    1003             : 
    1004           2 : bool Config::_cmdExit(co::ICommand& cmd)
    1005             : {
    1006           4 :     co::ObjectICommand command(cmd);
    1007           2 :     LBVERB << "handle config exit " << command << std::endl;
    1008             : 
    1009             :     bool result;
    1010           2 :     if (_state == STATE_RUNNING)
    1011           2 :         result = exit();
    1012             :     else
    1013             :     {
    1014           0 :         LBINFO << "Exit of non-running config?" << std::endl;
    1015           0 :         result = false;
    1016             :     }
    1017             : 
    1018           6 :     LBDEBUG << "Config exit " << (result ? "successful" : "failed")
    1019           6 :             << std::endl;
    1020           4 :     send(command.getRemoteNode(), fabric::CMD_CONFIG_EXIT_REPLY)
    1021           6 :         << command.read<uint32_t>() << result;
    1022           4 :     return true;
    1023             : }
    1024             : 
    1025           4 : bool Config::_cmdUpdate(co::ICommand& cmd)
    1026             : {
    1027           8 :     co::ObjectICommand command(cmd);
    1028             : 
    1029           4 :     LBVERB << "handle config update " << command << std::endl;
    1030             : 
    1031           4 :     const uint32_t versionID = command.read<uint32_t>();
    1032           4 :     const uint32_t finishID = command.read<uint32_t>();
    1033             : 
    1034           4 :     sync();
    1035           4 :     commit();
    1036             : 
    1037           8 :     co::NodePtr node = command.getRemoteNode();
    1038           4 :     if (!_needsFinish)
    1039             :     {
    1040           8 :         send(node, fabric::CMD_CONFIG_UPDATE_VERSION)
    1041          12 :             << getVersion() << versionID << finishID << LB_UNDEFINED_UINT32;
    1042           4 :         return true;
    1043             :     }
    1044             : 
    1045           0 :     co::LocalNodePtr localNode = getLocalNode();
    1046           0 :     lunchbox::Request<void> request = localNode->registerRequest<void>();
    1047             : 
    1048           0 :     send(node, fabric::CMD_CONFIG_UPDATE_VERSION) << getVersion() << versionID
    1049           0 :                                                   << finishID << request;
    1050             : 
    1051           0 :     _flushAllFrames();
    1052           0 :     _finishedFrame.waitEQ(_currentFrame); // wait for render clients idle
    1053           0 :     request.wait();                       // wait for app sync
    1054           0 :     _needsFinish = false;
    1055             : 
    1056           0 :     const bool canFail = (getIAttribute(IATTR_ROBUSTNESS) != OFF);
    1057           0 :     const bool result = _updateRunning(canFail);
    1058           0 :     if (!result && !canFail)
    1059             :     {
    1060           0 :         LBWARN << "Config update failed, exiting config" << std::endl;
    1061           0 :         exit();
    1062             :     }
    1063             : 
    1064           0 :     const uint128_t version = commit();
    1065           0 :     send(command.getRemoteNode(), fabric::CMD_CONFIG_UPDATE_REPLY)
    1066           0 :         << version << command.read<uint32_t>() << result;
    1067           0 :     return true;
    1068             : }
    1069             : 
    1070           2 : bool Config::_cmdStartFrame(co::ICommand& cmd)
    1071             : {
    1072           4 :     co::ObjectICommand command(cmd);
    1073             : 
    1074           2 :     LBVERB << "handle config frame start " << command << std::endl;
    1075             : 
    1076           2 :     _startFrame(command.read<uint128_t>());
    1077             : 
    1078           2 :     if (_state == STATE_STOPPED)
    1079             :     {
    1080             :         // unlock app
    1081           0 :         send(command.getRemoteNode(), fabric::CMD_CONFIG_FRAME_FINISH)
    1082           0 :             << _currentFrame;
    1083             :     }
    1084           4 :     return true;
    1085             : }
    1086             : 
    1087           2 : bool Config::_cmdFinishAllFrames(co::ICommand& cmd)
    1088             : {
    1089           4 :     co::ObjectICommand command(cmd);
    1090             : 
    1091           2 :     LBVERB << "handle config all frames finish " << command << std::endl;
    1092             : 
    1093           2 :     _flushAllFrames();
    1094           4 :     return true;
    1095             : }
    1096             : 
    1097           0 : bool Config::_cmdStopFrames(co::ICommand& cmd)
    1098             : {
    1099           0 :     co::ObjectICommand command(cmd);
    1100             : 
    1101           0 :     LBVERB << "handle config stop frames " << command << std::endl;
    1102             : 
    1103           0 :     ChannelStopFrameVisitor visitor(_currentFrame);
    1104           0 :     accept(visitor);
    1105             : 
    1106           0 :     return true;
    1107             : }
    1108             : 
    1109           0 : bool Config::_cmdCreateReply(co::ICommand& cmd)
    1110             : {
    1111           0 :     co::ObjectICommand command(cmd);
    1112             : 
    1113           0 :     LB_TS_THREAD(_cmdThread);
    1114           0 :     LB_TS_NOT_THREAD(_mainThread);
    1115             : 
    1116           0 :     getLocalNode()->serveRequest(command.read<uint32_t>());
    1117           0 :     return true;
    1118             : }
    1119             : 
    1120           0 : bool Config::_cmdCheckFrame(co::ICommand& cmd)
    1121             : {
    1122           0 :     const int64_t lastInterval = getServer()->getTime() - _lastCheck;
    1123           0 :     _lastCheck = getServer()->getTime();
    1124             : 
    1125           0 :     co::ObjectICommand command(cmd);
    1126           0 :     LBVERB << "Check nodes for frame finish " << command << std::endl;
    1127             : 
    1128           0 :     const uint32_t frameNumber = command.read<uint32_t>();
    1129           0 :     const uint32_t timeout = getTimeout();
    1130             : 
    1131           0 :     bool retry = false;
    1132           0 :     const Nodes& nodes = getNodes();
    1133           0 :     for (Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i)
    1134             :     {
    1135           0 :         Node* node = *i;
    1136           0 :         if (node->isRunning() && node->isActive())
    1137             :         {
    1138           0 :             co::NodePtr netNode = node->getNode();
    1139           0 :             if (netNode->isClosed())
    1140           0 :                 continue;
    1141             : 
    1142           0 :             if (node->getFinishedFrame() >= frameNumber)
    1143           0 :                 continue;
    1144             : 
    1145             :             const int64_t interval =
    1146           0 :                 getServer()->getTime() - netNode->getLastReceiveTime();
    1147           0 :             getLocalNode()->ping(netNode);
    1148             : 
    1149             :             // TODO?: handle timed out nodes.
    1150             :             // currently we get a false positive due to lack of communication
    1151             :             // from client to server. we do not get ping responses in time.
    1152             :             // running clients should inform the server about their status with
    1153             :             // a timeout/2 period.
    1154             : 
    1155           0 :             if (interval > timeout && lastInterval <= timeout)
    1156           0 :                 continue;
    1157             : 
    1158             :             // retry
    1159           0 :             LBINFO << "Retry waiting for node " << node->getName()
    1160           0 :                    << " to finish frame " << frameNumber << " last seen "
    1161           0 :                    << interval << " ms ago"
    1162           0 :                    << " last run " << lastInterval << std::endl;
    1163           0 :             retry = true;
    1164             :             // else node timeout
    1165             :         }
    1166             :     }
    1167             : 
    1168           0 :     if (retry)
    1169           0 :         return true;
    1170             : 
    1171           0 :     send(command.getRemoteNode(), fabric::CMD_CONFIG_FRAME_FINISH)
    1172           0 :         << _currentFrame;
    1173           0 :     return true;
    1174             : }
    1175             : 
    1176         204 : void Config::output(std::ostream& os) const
    1177             : {
    1178         204 :     os << std::endl << lunchbox::disableFlush << lunchbox::disableHeader;
    1179             : 
    1180        1680 :     for (Compounds::const_iterator i = _compounds.begin();
    1181        1120 :          i != _compounds.end(); ++i)
    1182             :     {
    1183         356 :         os << **i;
    1184             :     }
    1185             : 
    1186         204 :     os << lunchbox::enableHeader << lunchbox::enableFlush;
    1187         204 : }
    1188             : }
    1189             : }
    1190             : 
    1191             : #include "../fabric/config.ipp"
    1192             : #include "nodeFactory.h"
    1193             : template class eq::fabric::Config<eq::server::Server, eq::server::Config,
    1194             :                                   eq::server::Observer, eq::server::Layout,
    1195             :                                   eq::server::Canvas, eq::server::Node,
    1196             :                                   eq::server::ConfigVisitor>;
    1197             : 
    1198             : /** @cond IGNORE */
    1199             : template std::ostream& eq::fabric::operator<<(std::ostream&,
    1200             :                                               const eq::server::Config::Super&);
    1201             : /** @endcond */
    1202             : 
    1203             : #define FIND_ID_TEMPLATE1(type)                                           \
    1204             :     template void eq::server::Config::Super::find<type>(const uint128_t&, \
    1205             :                                                         type**);
    1206             : 
    1207             : FIND_ID_TEMPLATE1(eq::server::Canvas);
    1208             : FIND_ID_TEMPLATE1(eq::server::Channel);
    1209             : FIND_ID_TEMPLATE1(eq::server::Layout);
    1210             : FIND_ID_TEMPLATE1(eq::server::Node);
    1211             : FIND_ID_TEMPLATE1(eq::server::Observer);
    1212             : FIND_ID_TEMPLATE1(eq::server::Pipe);
    1213             : FIND_ID_TEMPLATE1(eq::server::Segment);
    1214             : FIND_ID_TEMPLATE1(eq::server::View);
    1215             : FIND_ID_TEMPLATE1(eq::server::Window);
    1216             : 
    1217             : #define FIND_ID_TEMPLATE2(type) \
    1218             :     template type* eq::server::Config::Super::find<type>(const uint128_t&);
    1219             : 
    1220             : FIND_ID_TEMPLATE2(eq::server::Canvas);
    1221             : FIND_ID_TEMPLATE2(eq::server::Channel);
    1222             : FIND_ID_TEMPLATE2(eq::server::Layout);
    1223             : FIND_ID_TEMPLATE2(eq::server::Node);
    1224             : FIND_ID_TEMPLATE2(eq::server::Observer);
    1225             : FIND_ID_TEMPLATE2(eq::server::Pipe);
    1226             : FIND_ID_TEMPLATE2(eq::server::Segment);
    1227             : FIND_ID_TEMPLATE2(eq::server::View);
    1228             : FIND_ID_TEMPLATE2(eq::server::Window);
    1229             : 
    1230             : #define FIND_NAME_TEMPLATE1(type)                                           \
    1231             :     template void eq::server::Config::Super::find<type>(const std::string&, \
    1232             :                                                         const type**) const;
    1233             : FIND_NAME_TEMPLATE1(eq::server::Canvas);
    1234             : FIND_NAME_TEMPLATE1(eq::server::Channel);
    1235             : FIND_NAME_TEMPLATE1(eq::server::Layout);
    1236             : FIND_NAME_TEMPLATE1(eq::server::Node);
    1237             : FIND_NAME_TEMPLATE1(eq::server::Observer);
    1238             : FIND_NAME_TEMPLATE1(eq::server::Pipe);
    1239             : FIND_NAME_TEMPLATE1(eq::server::Segment);
    1240             : FIND_NAME_TEMPLATE1(eq::server::View);
    1241             : FIND_NAME_TEMPLATE1(eq::server::Window);
    1242             : 
    1243             : #define FIND_NAME_TEMPLATE2(type) \
    1244             :     template type* eq::server::Config::Super::find<type>(const std::string&);
    1245             : 
    1246             : FIND_NAME_TEMPLATE2(eq::server::Canvas);
    1247             : FIND_NAME_TEMPLATE2(eq::server::Channel);
    1248             : FIND_NAME_TEMPLATE2(eq::server::Layout);
    1249             : FIND_NAME_TEMPLATE2(eq::server::Node);
    1250             : FIND_NAME_TEMPLATE2(eq::server::Observer);
    1251             : FIND_NAME_TEMPLATE2(eq::server::Pipe);
    1252             : FIND_NAME_TEMPLATE2(eq::server::Segment);
    1253             : FIND_NAME_TEMPLATE2(eq::server::View);
    1254             : FIND_NAME_TEMPLATE2(eq::server::Window);
    1255             : 
    1256             : #define CONST_FIND_NAME_TEMPLATE2(type)                         \
    1257             :     template const type* eq::server::Config::Super::find<type>( \
    1258             :         const std::string&) const;
    1259             : 
    1260             : CONST_FIND_NAME_TEMPLATE2(eq::server::Canvas);
    1261             : CONST_FIND_NAME_TEMPLATE2(eq::server::Channel);
    1262             : CONST_FIND_NAME_TEMPLATE2(eq::server::Layout);
    1263             : CONST_FIND_NAME_TEMPLATE2(eq::server::Node);
    1264             : CONST_FIND_NAME_TEMPLATE2(eq::server::Observer);
    1265             : CONST_FIND_NAME_TEMPLATE2(eq::server::Pipe);
    1266             : CONST_FIND_NAME_TEMPLATE2(eq::server::Segment);
    1267             : CONST_FIND_NAME_TEMPLATE2(eq::server::View);
    1268          60 : CONST_FIND_NAME_TEMPLATE2(eq::server::Window);

Generated by: LCOV version 1.11