Esempio n. 1
0
void QueueMaster::push( const QueueItemPacket& packet )
{
    LBASSERT( packet.size >= sizeof( QueueItemPacket ));
    LBASSERT( packet.command == CMD_QUEUE_ITEM );

    Command& command = _impl->cache.alloc( getLocalNode(), getLocalNode(),
                                           packet.size );
    QueueItemPacket* queuePacket = command.getModifiable< QueueItemPacket >();

    memcpy( queuePacket, &packet, packet.size );
    queuePacket->objectID = getID();
    command.retain();
    _impl->queue.push( &command );
}
Esempio n. 2
0
bool Config::init( const uint128_t& initID )
{
    EQASSERT( !_running );
    _currentFrame = 0;
    _unlockedFrame = 0;
    _finishedFrame = 0;
    _frameTimes.clear();

    co::LocalNodePtr localNode = getLocalNode();
    ConfigInitPacket packet;
    packet.requestID  = localNode->registerRequest();
    packet.initID     = initID;

    send( getServer(), packet );
    
    ClientPtr client = getClient();
    while( !localNode->isRequestServed( packet.requestID ))
        client->processCommand();
    localNode->waitRequest( packet.requestID, _running );
    localNode->enableSendOnRegister();

    if( _running )
        handleEvents();
    else
        EQWARN << "Config initialization failed: " << getError() << std::endl
               << "    Consult client log for further information" << std::endl;
    return _running;
}
Esempio n. 3
0
void TileQueue::cycleData( const uint32_t frameNumber, const Compound* compound)
{
    for( unsigned i = 0; i < NUM_EYES; ++i )
    {
        if( !compound->isInheritActive( Eye( 1<<i )))// eye pass not used
        {
            _queueMaster[i] = 0;
            continue;
        }

        // reuse unused queues
        LatencyQueue* queue    = _queues.empty() ? 0 : _queues.back();
        const uint32_t latency = getAutoObsolete();
        const uint32_t dataAge = queue ? queue->_frameNumber : 0;

        if( queue && dataAge < frameNumber-latency && frameNumber > latency )
            // not used anymore
            _queues.pop_back();
        else // still used - allocate new data
        {
            queue = new LatencyQueue;

            getLocalNode()->registerObject( &queue->_queue );
            queue->_queue.setAutoObsolete( 1 ); // current + in use by render nodes
        }

        queue->_queue.clear();
        queue->_frameNumber = frameNumber;

        _queues.push_front( queue );
        _queueMaster[i] = queue;
    }
}
Esempio n. 4
0
void Config::deregisterObject( co::Object* object )
{
    EQASSERT( object )
    EQASSERT( object->isMaster( ));

    if( !object->isAttached( )) // not registered
        return;

    const uint32_t latency = getLatency();
    ClientPtr client = getClient();
    if( latency == 0 || !_running || !object->isBuffered( )) // OPT
    {
        client->deregisterObject( object );
        return;
    }

    // Keep a distributed object latency frames.
    // Replaces the object with a dummy proxy object using the
    // existing master change manager.
    ConfigSwapObjectPacket packet;
    packet.requestID = getLocalNode()->registerRequest();
    packet.object = object;

    send( client, packet );
    client->waitRequest( packet.requestID );
}
Esempio n. 5
0
bool Config::exit()
{
    update();
    finishAllFrames();

    co::LocalNodePtr localNode = getLocalNode();
    localNode->disableSendOnRegister();

    ConfigExitPacket packet;
    packet.requestID = localNode->registerRequest();
    send( getServer(), packet );

    ClientPtr client = getClient();
    while( !localNode->isRequestServed( packet.requestID ))
        client->processCommand();

    bool ret = false;
    localNode->waitRequest( packet.requestID, ret );

    while( tryNextEvent( )) /* flush all pending events */ ;
    if( _lastEvent )
        _lastEvent->release();
    _eventQueue.flush();
    _lastEvent = 0;
    _running = false;
    return ret;
}
Esempio n. 6
0
void Config::_stopNodes()
{
    // wait for the nodes to stop, destroy entities, disconnect
    Nodes stoppingNodes;
    const Nodes& nodes = getNodes();
    for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
    {
        Node* node = *i;
        const State state = node->getState();
        if( state != STATE_STOPPED && state != STATE_FAILED )
            continue;

        LBASSERT( !node->isActive() || state == STATE_FAILED );
        if( node->isApplicationNode( ))
            continue;

        co::NodePtr netNode = node->getNode();
        if( !netNode ) // already disconnected
            continue;

        LBLOG( LOG_INIT ) << "Exiting node" << std::endl;

        if( state == STATE_FAILED )
            node->setState( STATE_STOPPED );

        stoppingNodes.push_back( node );
        LBASSERT( netNode.isValid( ));

        netNode->send( fabric::CMD_SERVER_DESTROY_CONFIG )
                << getID() << LB_UNDEFINED_UINT32;
        netNode->send( fabric::CMD_CLIENT_EXIT );
    }

    // now wait that the render clients disconnect
    uint32_t nSleeps = 50; // max 5 seconds for all clients
    for( Nodes::const_iterator i = stoppingNodes.begin();
         i != stoppingNodes.end(); ++i )
    {
        Node*        node    = *i;
        co::NodePtr netNode = node->getNode();
        node->setNode( 0 );

        if( nSleeps )
            while( netNode->isConnected() && --nSleeps )
                lunchbox::sleep( 100 ); // ms

        if( netNode->isConnected( ))
        {
            co::LocalNodePtr localNode = getLocalNode();
            LBASSERT( localNode.isValid( ));

            LBWARN << "Forcefully disconnecting exited render client node"
                   << std::endl;
            localNode->disconnect( netNode );
        }

        LBLOG( LOG_INIT ) << "Disconnected node" << std::endl;
    }
}
Esempio n. 7
0
void Pipe::_stopTransferThread()
{
    if( _impl->transferThread.isStopped( ))
        return;

    send( getLocalNode(), fabric::CMD_PIPE_EXIT_TRANSFER_THREAD );
    _impl->transferThread.join();
}
Esempio n. 8
0
void QueueMaster::attach( const UUID& id, const uint32_t instanceID )
{
    Object::attach( id, instanceID );

    CommandQueue* queue = getLocalNode()->getCommandThreadQueue();
    registerCommand( CMD_QUEUE_GET_ITEM, 
                     CommandFunc< detail::QueueMaster >(
                         _impl, &detail::QueueMaster::cmdGetItem ), queue );
}
Esempio n. 9
0
void Config::notifyAttached()
{
    fabric::Object::notifyAttached();
    EQASSERT( !_appNode )
    EQASSERT( getAppNodeID().isGenerated() )
    co::LocalNodePtr localNode = getLocalNode();
    _appNode = localNode->connect( getAppNodeID( ));
    EQASSERTINFO( _appNode, "Connection to application node failed -- " <<
                            "misconfigured connections on appNode?" );
}
Esempio n. 10
0
void QueueSlave::applyInstanceData( co::DataIStream& is )
{
    NodeID masterNodeID;
    is >> _impl->masterInstanceID >> masterNodeID;

    LBASSERT( masterNodeID != 0 );
    LBASSERT( !_impl->master );
    LocalNodePtr localNode = getLocalNode();
    _impl->master = localNode->connect( masterNodeID );
}
Esempio n. 11
0
void QueueSlave::applyInstanceData( co::DataIStream& is )
{
    uint128_t masterNodeID;
    is >> _impl->masterInstanceID >> masterNodeID;

    EQASSERT( masterNodeID != NodeID::ZERO );
    EQASSERT( !_impl->master );
    LocalNodePtr localNode = getLocalNode();
    _impl->master = localNode->connect( masterNodeID );
}
Esempio n. 12
0
bool Config::_cmdCreateReply( co::ICommand& cmd )
{
    co::ObjectICommand command( cmd );

    LB_TS_THREAD( _cmdThread );
    LB_TS_NOT_THREAD( _mainThread );

    getLocalNode()->serveRequest( command.read< uint32_t >( ));
    return true;
}
Esempio n. 13
0
bool Config::_cmdExitReply( co::Command& command )
{
    const ConfigExitReplyPacket* packet = 
        command.get<ConfigExitReplyPacket>();
    EQVERB << "handle exit reply " << packet << std::endl;

    _exitMessagePump();
    getLocalNode()->serveRequest( packet->requestID, (void*)(packet->result) );
    return true;
}
Esempio n. 14
0
bool Config::_cmdSwapObject( co::Command& command )
{
    const ConfigSwapObjectPacket* packet = 
        command.get<ConfigSwapObjectPacket>();
    EQVERB << "Cmd swap object " << packet << std::endl;

    co::Object* object = packet->object;
    LatencyObject* latencyObject = new LatencyObject( object->getChangeType(),
                                                     object->chooseCompressor(),
                                             _currentFrame + getLatency() + 1 );
    getLocalNode()->swapObject( object, latencyObject  );
    {
        co::base::ScopedFastWrite mutex( _latencyObjects );
        _latencyObjects->push_back( latencyObject );
    }
    EQASSERT( packet->requestID != EQ_UNDEFINED_UINT32 );
    getLocalNode()->serveRequest( packet->requestID );
    return true;
}
Esempio n. 15
0
bool Config::_cmdInitReply( co::Command& command )
{
    const ConfigInitReplyPacket* packet = 
        command.get<ConfigInitReplyPacket>();
    EQVERB << "handle init reply " << packet << std::endl;

    sync( packet->version );
    getLocalNode()->serveRequest( packet->requestID, (void*)(packet->result) );
    return true;
}
Esempio n. 16
0
bool Config::_cmdCheckFrame( co::ICommand& cmd )
{
    const int64_t lastInterval = getServer()->getTime() - _lastCheck;
    _lastCheck = getServer()->getTime();

    co::ObjectICommand command( cmd );
    LBVERB << "Check nodes for frame finish " << command << std::endl;

    const uint32_t frameNumber = command.read< uint32_t >();
    const uint32_t timeout = getTimeout();

    bool retry = false;
    const Nodes& nodes = getNodes();
    for( Nodes::const_iterator i = nodes.begin(); i != nodes.end(); ++i )
    {
        Node* node = *i;
        if( node->isRunning() && node->isActive() )
        {
            co::NodePtr netNode = node->getNode();
            if ( netNode->isClosed() )
                continue;

            if ( node->getFinishedFrame() >= frameNumber )
                continue;

            const int64_t interval = getServer()->getTime() -
                                     netNode->getLastReceiveTime();
            getLocalNode()->ping( netNode );

            // TODO?: handle timed out nodes.
            // currently we get a false positive due to lack of communication
            // from client to server. we do not get ping responses in time.
            // running clients should inform the server about their status with
            // a timeout/2 period.

            if ( interval > timeout && lastInterval <= timeout )
                continue;

            // retry
            LBINFO << "Retry waiting for node " << node->getName()
                   << " to finish frame " << frameNumber << " last seen "
                   << interval << " ms ago" << " last run " << lastInterval
                   << std::endl;
            retry = true;
            // else node timeout
        }
    }

    if( retry )
        return true;

    send( command.getRemoteNode(), fabric::CMD_CONFIG_FRAME_FINISH )
        << _currentFrame;
    return true;
}
Esempio n. 17
0
void Pipe::cancelThread()
{
    _stopTransferThread();

    if( !_impl->thread )
        return;

    // local command dispatching
    co::ObjectOCommand( this, getLocalNode(), fabric::CMD_PIPE_EXIT_THREAD,
                        co::COMMANDTYPE_OBJECT, getID(), EQ_INSTANCE_ALL );
}
Esempio n. 18
0
void TileQueue::flush()
{
    unsetData();

    while (!_queues.empty())
    {
        LatencyQueue* queue = _queues.front();
        _queues.pop_front();
        getLocalNode()->deregisterObject(&queue->_queue);
        delete queue;
    }
}
Esempio n. 19
0
void Frame::flush()
{
    unsetData();

    while( !_datas.empty( ))
    {
        FrameData* data = _datas.front();
        _datas.pop_front();
        getLocalNode()->deregisterObject( data );
        delete data;
    }
}
Esempio n. 20
0
uint32_t Config::finishFrame()
{
    ClientPtr client = getClient();
    const uint32_t latency = getLatency();
    const uint32_t frameToFinish = (_currentFrame >= latency) ? 
                                       _currentFrame - latency : 0;

    ConfigStatistics stat( Statistic::CONFIG_FINISH_FRAME, this );
    stat.event.data.statistic.frameNumber = frameToFinish;
    {
        ConfigStatistics waitStat( Statistic::CONFIG_WAIT_FINISH_FRAME, this );
        waitStat.event.data.statistic.frameNumber = frameToFinish;
        
        // local draw sync
        if( _needsLocalSync( ))
            while( _unlockedFrame < _currentFrame )
                client->processCommand();

        // local node finish (frame-latency) sync
        const Nodes& nodes = getNodes();
        if( !nodes.empty( ))
        {
            EQASSERT( nodes.size() == 1 );
            const Node* node = nodes.front();

            while( node->getFinishedFrame() < frameToFinish )
                client->processCommand();
        }

        // global sync
        const uint32_t timeout = getTimeout();
        co::base::Clock time;
        const int64_t pingTimeout = co::Global::getKeepaliveTimeout();

        while( !_finishedFrame.timedWaitGE( frameToFinish, pingTimeout ))
        {
            if( time.getTime64() >= timeout || !getLocalNode()->pingIdleNodes())
            {
                EQWARN << "Timeout waiting for nodes to finish frame " 
                       << frameToFinish << std::endl;
                break;
            }
        }
    }

    handleEvents();
    _updateStatistics( frameToFinish );
    _releaseObjects();

    EQLOG( co::base::LOG_ANY ) << "---- Finished Frame --- " << frameToFinish
                               << " (" << _currentFrame << ')' << std::endl;
    return frameToFinish;
}
Esempio n. 21
0
void Pipe::exitThread()
{
    _stopTransferThread();

    if( !_impl->thread )
        return;

    send( getLocalNode(), fabric::CMD_PIPE_EXIT_THREAD );

    _impl->thread->join();
    delete _impl->thread;
    _impl->thread = 0;
}
Esempio n. 22
0
void View::detach()
{
    // if pipe is not running, detach comes from _flushViews in state stopping
    //  Don't send command to stopping pipe (see issue #11)
    if( _pipe && _pipe->isRunning( ))
    {
        // local command dispatching
        co::ObjectOCommand( _pipe, getLocalNode(), fabric::CMD_PIPE_DETACH_VIEW,
                            co::COMMANDTYPE_OBJECT, _pipe->getID(),
                            CO_INSTANCE_ALL ) << getID();
    }
    Super::detach();
}
Esempio n. 23
0
lunchbox::Request< void > Config::_createConfig( Node* node )
{
    LBASSERT( !node->isApplicationNode( ));
    LBASSERT( node->isActive( ));

    // create config on each non-app node
    //   app-node already has config from chooseConfig
    lunchbox::Request< void > request = getLocalNode()->registerRequest<void>();

    node->getNode()->send( fabric::CMD_SERVER_CREATE_CONFIG )
            << co::ObjectVersion( this ) << request;
    return request;
}
Esempio n. 24
0
void View::detach()
{
    if( _pipe )
    {
        co::LocalNodePtr localNode = getLocalNode();
        co::Command& command =
            localNode->allocCommand( sizeof( PipeDetachViewPacket ));

        PipeDetachViewPacket* packet = command.get< PipeDetachViewPacket >();
        *packet = PipeDetachViewPacket( getID( ));

        _pipe->dispatchCommand( command );
    }
    Super::detach();
}
Esempio n. 25
0
bool Config::_cmdUpdate( co::ICommand& cmd )
{
    co::ObjectICommand command( cmd );

    LBVERB << "handle config update " << command << std::endl;

    const uint32_t versionID = command.read< uint32_t >();
    const uint32_t finishID = command.read< uint32_t >();

    sync();
    commit();

    co::NodePtr node = command.getRemoteNode();
    if( !_needsFinish )
    {
        send( node, fabric::CMD_CONFIG_UPDATE_VERSION )
                << getVersion() << versionID << finishID << LB_UNDEFINED_UINT32;
        return true;
    }

    co::LocalNodePtr localNode = getLocalNode();
    lunchbox::Request< void > request = localNode->registerRequest< void >();

    send( node, fabric::CMD_CONFIG_UPDATE_VERSION )
        << getVersion() << versionID << finishID << request;

    _flushAllFrames();
    _finishedFrame.waitEQ( _currentFrame ); // wait for render clients idle
    request.wait(); // wait for app sync
    _needsFinish = false;

    const bool canFail = (getIAttribute( IATTR_ROBUSTNESS ) != OFF);
    const bool result = _updateRunning( canFail );
    if( !result && !canFail )
    {
        LBWARN << "Config update failed, exiting config" << std::endl;
        exit();
    }

    const uint128_t version = commit();
    send( command.getRemoteNode(), fabric::CMD_CONFIG_UPDATE_REPLY )
            << version << command.read< uint32_t >() << result;
    return true;
}
Esempio n. 26
0
bool Pipe::_cmdConfigExit( co::ICommand& cmd )
{
    co::ObjectICommand command( cmd );

    LB_TS_THREAD( _pipeThread );
    LBLOG( LOG_INIT ) << "TASK pipe config exit " << command << std::endl;

    _impl->state = STATE_STOPPING; // needed in View::detach (from _flushViews)

    // send before node gets a chance to send its destroy command
    getNode()->send( getLocalNode(), fabric::CMD_NODE_DESTROY_PIPE ) << getID();

    // Flush views before exit since they are created after init
    // - application may need initialized pipe to exit
    // - configExit can't access views since all channels are gone already
    _flushViews();
    _flushQueues();
    _impl->state = configExit() ? STATE_STOPPED : STATE_FAILED;
    return true;
}
Esempio n. 27
0
void Frame::cycleData(const uint32_t frameNumber, const Compound* compound)
{
    _masterFrameData = 0;
    for (unsigned i = 0; i < NUM_EYES; ++i)
    {
        _inputFrames[i].clear();

        const Eye eye = Eye(1 << i);
        if (!compound->isInheritActive(eye)) // eye pass not used
        {
            _frameData[i] = 0;
            continue;
        }

        // reuse unused frame data
        FrameData* data = _datas.empty() ? 0 : _datas.back();
        const uint32_t latency = getAutoObsolete();
        const uint32_t dataAge = data ? data->getFrameNumber() : 0;

        if (data && dataAge < frameNumber - latency && frameNumber > latency)
            // not used anymore
            _datas.pop_back();
        else // still used - allocate new data
        {
            data = new FrameData;

            getLocalNode()->registerObject(data);
            data->setAutoObsolete(1); // current + in use by render nodes
        }

        data->setFrameNumber(frameNumber);

        _datas.push_front(data);
        _frameData[i] = data;
        _getInputNodes(i).clear();
        _getInputNetNodes(i).clear();
        if (!_masterFrameData)
            _masterFrameData = data;
    }
}
Esempio n. 28
0
bool Window::_cmdConfigExit( co::ICommand& cmd )
{
    co::ObjectICommand command( cmd );

    LBLOG( LOG_INIT ) << "TASK window config exit " << command << std::endl;

    if( _state != STATE_STOPPED )
    {
        if( getPipe()->isRunning( ) && _systemWindow )
        {
            makeCurrent();
            getPipe()->flushFrames( _objectManager );
        }
        // else emergency exit, no context available.

        _state = configExit() ? STATE_STOPPED : STATE_FAILED;
    }

    getPipe()->send( getLocalNode(),
                     fabric::CMD_PIPE_DESTROY_WINDOW ) << getID();
    return true;
}
Esempio n. 29
0
bool Node::_cmdConfigExit( co::Command& command )
{
    LB_TS_THREAD( _nodeThread );
    LBLOG( LOG_INIT ) << "Node exit " 
                      << command.get<NodeConfigExitPacket>() << std::endl;

    const Pipes& pipes = getPipes();
    for( Pipes::const_iterator i = pipes.begin(); i != pipes.end(); ++i )
    {
        Pipe* pipe = *i;
        pipe->waitExited();
    }
    
    _state = configExit() ? STATE_STOPPED : STATE_FAILED;
    transmitter.getQueue().wakeup();
    transmitter.join();
    _flushObjects();

    ConfigDestroyNodePacket destroyPacket( getID( ));
    getConfig()->send( getLocalNode(), destroyPacket );
    return true;
}
Esempio n. 30
0
void Node::_setAffinity()
{
    const int32_t affinity = getIAttribute( IATTR_HINT_AFFINITY );
    switch( affinity )
    {
        case OFF:
            break;

        case AUTO:
            // TODO
            LBVERB << "No automatic thread placement for node threads "
                   << std::endl;
            break;

        default:
            co::LocalNodePtr node = getLocalNode();
            send( node, fabric::CMD_NODE_SET_AFFINITY ) << affinity;

            node->setAffinity( affinity );
            break;
    }
}