void Command::clone_( Command& from ) { EQ_TS_THREAD( _writeThread ); EQASSERT( _refCount == 0 ); EQASSERT( !_func.isValid( )); _node = from._node; _localNode = from._localNode; _packet = from._packet; _refCountMaster = &from._refCount; }
Command* CommandQueue::pop( const uint32_t timeout ) { EQ_TS_THREAD( _thread ); if( timeout == EQ_TIMEOUT_INDEFINITE ) return _commands.pop(); Command* command; if( !_commands.timedPop( timeout, command )) throw Exception( Exception::TIMEOUT_COMMANDQUEUE ); return command; }
Command& CommandCache::alloc( NodePtr node, LocalNodePtr localNode, const uint64_t size ) { EQ_TS_THREAD( _thread ); const Cache which = (size > Packet::minSize) ? CACHE_BIG : CACHE_SMALL; _compact( which ); Command& command = _newCommand( which ); command._alloc( node, localNode, size ); return command; }
bool LocalNode::_cmdStopRcv( Command& command ) { EQ_TS_THREAD( _rcvThread ); EQASSERT( _state == STATE_LISTENING ); EQINFO << "Cmd stop receiver " << this << std::endl; _state = STATE_CLOSING; // causes rcv thread exit command->command = CMD_NODE_STOP_CMD; // causes cmd thread exit _dispatchCommand( command ); return true; }
Command& CommandCache::alloc( NodePtr node, LocalNodePtr localNode, const uint64_t size ) { EQ_TS_THREAD( _thread ); EQASSERTINFO( size < EQ_BIT48, "Out-of-sync network stream: packet size " << size << "?" ); const Cache which = (size > Packet::minSize) ? CACHE_BIG : CACHE_SMALL; _compact( which ); Command& command = _newCommand( which ); command.alloc_( node, localNode, size ); return command; }
void MasterCM::removeSlaves( NodePtr node ) { EQ_TS_THREAD( _cmdThread ); const NodeID& nodeID = node->getNodeID(); SlavesCount::iterator i = _slavesCount.find( nodeID ); if( i == _slavesCount.end( )) return; Nodes::iterator j = stde::find( _slaves, node ); EQASSERT( j != _slaves.end( )); _slaves.erase( j ); _slavesCount.erase( i ); }
void FrameBufferObject::exit() { EQ_TS_THREAD( _thread ); if( _fboID ) { glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); glDeleteFramebuffersEXT( 1, &_fboID ); _fboID = 0; } for( size_t i = 0; i < _colors.size(); ++i ) _colors[i]->flush(); _depth.flush(); _valid = false; }
void UnbufferedMasterCM::removeSlave( NodePtr node ) { EQ_TS_THREAD( _cmdThread ); // remove from subscribers const NodeID& nodeID = node->getNodeID(); EQASSERTINFO( _slavesCount[ nodeID ] != 0, base::className( _object )); --_slavesCount[ nodeID ]; if( _slavesCount[ nodeID ] == 0 ) { Nodes::iterator i = find( _slaves.begin(), _slaves.end(), node ); EQASSERT( i != _slaves.end( )); _slaves.erase( i ); _slavesCount.erase( nodeID ); } }
void Command::_free() { EQ_TS_THREAD( _writeThread ); EQASSERT( _refCount == 0 ); EQASSERT( !_func.isValid( )); if( _data ) free( _data ); _data = 0; _dataSize = 0; _packet = 0; _node = 0; _localNode = 0; _refCountMaster = 0; }
ConnectionPtr PGMConnection::acceptSync() { EQ_TS_THREAD( _recvThread ); if( _state != STATE_LISTENING ) return 0; EQASSERT( _overlappedAcceptData ); EQASSERT( _overlappedSocket != INVALID_SOCKET ); if( _overlappedSocket == INVALID_SOCKET ) return 0; // complete accept DWORD got = 0; DWORD flags = 0; if( !WSAGetOverlappedResult( _readFD, &_overlapped, &got, TRUE, &flags )) { EQWARN << "Accept completion failed: " << base::sysError << ", closing connection" << std::endl; close(); return 0; } sockaddr_in* local = 0; sockaddr_in* remote = 0; int localLen = 0; int remoteLen = 0; GetAcceptExSockaddrs( _overlappedAcceptData, 0, sizeof( sockaddr_in ) + 16, sizeof( sockaddr_in ) + 16, (sockaddr**)&local, &localLen, (sockaddr**)&remote, &remoteLen ); PGMConnection* newConnection = new PGMConnection; ConnectionPtr connection( newConnection ); // to keep ref-counting correct newConnection->_readFD = _overlappedSocket; _overlappedSocket = INVALID_SOCKET; newConnection->_setupReadSocket(); newConnection->_writeFD = _writeFD; newConnection->_initAIORead(); newConnection->_state = STATE_CONNECTED; newConnection->_description = _description; EQINFO << "accepted connection " << (void*)newConnection << " from " << inet_ntoa( remote->sin_addr ) << ":" << ntohs( remote->sin_port ) << std::endl; return connection; }
bool FrameBufferObject::resize( const int32_t width, const int32_t height ) { EQ_TS_THREAD( _thread ); EQASSERT( width > 0 && height > 0 ); EQASSERT( !_colors.empty( )); Texture* color = _colors.front(); if( color->getWidth() == width && color->getHeight() == height && _valid ) return true; for( size_t i = 0; i < _colors.size(); ++i ) _colors[i]->resize( width, height ); if ( _depth.isValid( )) _depth.resize( width, height ); return _checkStatus(); }
bool FrameBufferObject::init( const int32_t width, const int32_t height, const GLuint colorFormat, const int32_t depthSize, const int32_t stencilSize ) { EQ_TS_THREAD( _thread ); if( _fboID ) { _setError( ERROR_FRAMEBUFFER_INITIALIZED ); EQWARN << _error << std::endl; return false; } // generate and bind the framebuffer glGenFramebuffersEXT( 1, &_fboID ); glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, _fboID ); // create and bind textures for( unsigned i = 0; i < _colors.size(); ++i ) { _colors[i]->init( colorFormat, width, height ); _colors[i]->bindToFBO( GL_COLOR_ATTACHMENT0 + i, width, height ); } if( stencilSize > 0 && GLEW_EXT_packed_depth_stencil ) { _depth.init( GL_DEPTH24_STENCIL8, width, height ); _depth.bindToFBO( GL_DEPTH_STENCIL_ATTACHMENT, width, height ); } else if( depthSize > 0 ) { _depth.init( GL_DEPTH_COMPONENT, width, height ); _depth.bindToFBO( GL_DEPTH_ATTACHMENT, width, height ); } if( _checkStatus( )) return true; // else exit(); return false; }
Command& CommandCache::_newCommand( const Cache which ) { EQ_TS_THREAD( _thread ); Data& cache = _cache[ which ]; const uint32_t cacheSize = uint32_t( cache.size( )); base::a_int32_t& freeCounter = _free[ which ]; EQASSERTINFO( size_t( freeCounter ) <= cacheSize, freeCounter << " > " << cacheSize ); if( freeCounter > 0 ) { EQASSERT( cacheSize > 0 ); const DataCIter end = _position[ which ]; DataCIter& i = _position[ which ]; for( ++i; i != end; ++i ) { if( i == cache.end( )) i = cache.begin(); #ifdef PROFILE ++_lookups; #endif Command* command = *i; if( command->isFree( )) { #ifdef PROFILE const long hits = ++_hits; if( (hits%1000) == 0 ) { for( size_t j = 0; j < CACHE_ALL; ++j ) { size_t size = 0; const Data& cmds = _cache[ j ]; for( DataCIter k=cmds.begin(); k != cmds.end(); ++k) size += (*k)->getAllocationSize(); EQINFO << _hits << "/" << _hits + _misses << " hits, " << _lookups << " lookups, " << _free[j] << " of " << cmds.size() << " packets free, " << _allocs << " allocs, " << _frees << " frees, " << size / 1024 << "KB" << std::endl; } } #endif return *command; } } } #ifdef PROFILE ++_misses; #endif const uint32_t add = (cacheSize >> 3) + 1; for( size_t j = 0; j < add; ++j ) cache.push_back( new Command( freeCounter )); freeCounter += add; const int32_t num = int32_t( cache.size() >> _freeShift ); _maxFree[ which ] = EQ_MAX( _minFree[ which ], num ); _position[ which ] = cache.begin(); #ifdef PROFILE _allocs += add; #endif return *( cache.back( )); }
//--------------------------------------------------------------------------- // command handlers //--------------------------------------------------------------------------- bool MasterCM::_cmdSlaveDelta( Command& command ) { EQ_TS_THREAD( _cmdThread ); const ObjectSlaveDeltaPacket* packet = command.get< ObjectSlaveDeltaPacket >(); EQASSERTINFO( _pendingDeltas.size() < 100, "More than 100 unfinished slave commits!?" ); ObjectDataIStream* istream = 0; PendingStreams::iterator i = _pendingDeltas.begin(); for( ; i != _pendingDeltas.end(); ++i ) { PendingStream& pending = *i; if( pending.first == packet->commit ) { istream = pending.second; break; } } if( !istream ) { EQASSERT( i == _pendingDeltas.end( )); istream = _iStreamCache.alloc(); } istream->addDataPacket( command ); if( istream->isReady( )) { if( i != _pendingDeltas.end( )) _pendingDeltas.erase( i ); _queuedDeltas.push( istream ); _object->notifyNewVersion(); EQASSERTINFO( _queuedDeltas.getSize() < 100, "More than 100 queued slave commits!?" ); #if 0 EQLOG( LOG_OBJECTS ) << "Queued slave commit " << packet->commit << " object " << _object->getID() << " " << base::className( _object ) << std::endl; #endif } else if( i == _pendingDeltas.end( )) { _pendingDeltas.push_back( PendingStream( packet->commit, istream )); #if 0 EQLOG( LOG_OBJECTS ) << "New incomplete slave commit " << packet->commit << " object " << _object->getID() << " " << base::className( _object ) << std::endl; #endif } #if 0 else EQLOG( LOG_OBJECTS ) << "Got data for incomplete slave commit " << packet->commit << " object " << _object->getID() << " " << base::className( _object ) << std::endl; #endif return true; }
void FrameBufferObject::bind() { EQ_TS_THREAD( _thread ); EQASSERT( _fboID ); EQ_GL_CALL( glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, _fboID )); }
void FullMasterCM::addSlave( Command& command, NodeMapObjectReplyPacket& reply ) { EQ_TS_THREAD( _cmdThread ); EQASSERT( command->type == PACKETTYPE_CO_NODE ); EQASSERT( command->command == CMD_NODE_MAP_OBJECT ); NodePtr node = command.getNode(); const NodeMapObjectPacket* packet = command.get< NodeMapObjectPacket >(); const uint128_t requested = packet->requestedVersion; const uint32_t instanceID = packet->instanceID; Mutex mutex( _slaves ); EQASSERT( _version != VERSION_NONE ); _checkConsistency(); // add to subscribers ++_slavesCount[ node->getNodeID() ]; _slaves->push_back( node ); stde::usort( *_slaves ); if( requested == VERSION_NONE ) // no data to send { _sendEmptyVersion( node, instanceID, _version ); reply.version = _version; return; } const uint128_t oldest = _instanceDatas.front()->os.getVersion(); uint128_t start = (requested == VERSION_OLDEST || requested < oldest ) ? oldest : requested; uint128_t end = _version; const bool useCache = packet->masterInstanceID == _object->getInstanceID(); #ifndef NDEBUG if( requested != VERSION_OLDEST && requested < start ) EQINFO << "Mapping version " << start << " instead of requested version " << requested << std::endl; #endif reply.version = start; reply.useCache = packet->useCache && useCache; if( reply.useCache ) { if( packet->minCachedVersion <= start && packet->maxCachedVersion >= start ) { #ifdef EQ_INSTRUMENT_MULTICAST _hit += packet->maxCachedVersion + 1 - start; #endif start = packet->maxCachedVersion + 1; } else if( packet->maxCachedVersion == end ) { end = EQ_MAX( start, packet->minCachedVersion - 1 ); #ifdef EQ_INSTRUMENT_MULTICAST _hit += _version - end; #endif } // TODO else cached block in the middle, send head and tail elements } #if 0 EQLOG( LOG_OBJECTS ) << *_object << ", instantiate on " << node->getNodeID() << " with v" << ((requested == VERSION_OLDEST) ? oldest : requested) << " (" << requested << ") sending " << start << ".." << end << " have " << _version - _nVersions << ".." << _version << " " << _instanceDatas.size() << std::endl; #endif EQASSERT( start >= oldest ); // send all instance datas from start..end InstanceDataDeque::iterator i = _instanceDatas.begin(); while( i != _instanceDatas.end() && (*i)->os.getVersion() < start ) ++i; for( ; i != _instanceDatas.end() && (*i)->os.getVersion() <= end; ++i ) { InstanceData* data = *i; EQASSERT( data ); data->os.sendMapData( node, instanceID ); #ifdef EQ_INSTRUMENT_MULTICAST ++_miss; #endif } #ifdef EQ_INSTRUMENT_MULTICAST if( _miss % 100 == 0 ) EQINFO << "Cached " << _hit << "/" << _hit + _miss << " instance data transmissions" << std::endl; #endif }
//---------------------------------------------------------------------- // receiver thread functions //---------------------------------------------------------------------- void LocalNode::_runReceiverThread() { EQ_TS_THREAD( _rcvThread ); int nErrors = 0; while( _state == STATE_LISTENING ) { const ConnectionSet::Event result = _incoming.select(); switch( result ) { case ConnectionSet::EVENT_CONNECT: _handleConnect(); break; case ConnectionSet::EVENT_DATA: _handleData(); break; case ConnectionSet::EVENT_DISCONNECT: case ConnectionSet::EVENT_INVALID_HANDLE: _handleDisconnect(); break; case ConnectionSet::EVENT_TIMEOUT: EQINFO << "select timeout" << std::endl; break; case ConnectionSet::EVENT_ERROR: ++nErrors; EQWARN << "Connection error during select" << std::endl; if( nErrors > 100 ) { EQWARN << "Too many errors in a row, capping connection" << std::endl; _handleDisconnect(); } break; case ConnectionSet::EVENT_SELECT_ERROR: EQWARN << "Error during select" << std::endl; ++nErrors; if( nErrors > 10 ) { EQWARN << "Too many errors in a row" << std::endl; EQUNIMPLEMENTED; } break; case ConnectionSet::EVENT_INTERRUPT: _redispatchCommands(); break; default: EQUNIMPLEMENTED; } if( result != ConnectionSet::EVENT_ERROR && result != ConnectionSet::EVENT_SELECT_ERROR ) nErrors = 0; } if( !_pendingCommands.empty( )) EQWARN << _pendingCommands.size() << " commands pending while leaving command thread" << std::endl; for( CommandList::const_iterator i = _pendingCommands.begin(); i != _pendingCommands.end(); ++i ) { Command* command = *i; command->release(); } EQCHECK( _commandThread->join( )); _objectStore->clear(); _pendingCommands.clear(); _commandCache.flush(); EQINFO << "Leaving receiver thread of " << base::className( this ) << std::endl; }
void GLXEventHandler::_processEvent( GLXWindowEvent& event ) { EQ_TS_THREAD( _thread ); XEvent& xEvent = event.xEvent; XID drawable = xEvent.xany.window; if( _window->getXDrawable() != drawable ) return; Window* window = _window->getWindow(); switch( xEvent.type ) { case Expose: if( xEvent.xexpose.count ) // Only report last expose event return; event.type = Event::WINDOW_EXPOSE; break; case ConfigureNotify: event.type = Event::WINDOW_RESIZE; _getWindowSize( xEvent.xany.display, drawable, event.resize ); break; case UnmapNotify: event.type = Event::WINDOW_HIDE; _getWindowSize( xEvent.xany.display, drawable, event.resize ); break; case MapNotify: event.type = Event::WINDOW_SHOW; _getWindowSize( xEvent.xany.display, drawable, event.resize ); break; case ClientMessage: { Atom deleteAtom = XInternAtom( xEvent.xany.display, "WM_DELETE_WINDOW", False ); if( static_cast<Atom>( xEvent.xclient.data.l[0] ) != deleteAtom ) return; // not a delete message, ignore. } // else: delete message, fall through case DestroyNotify: event.type = Event::WINDOW_CLOSE; break; case MotionNotify: event.type = Event::WINDOW_POINTER_MOTION; event.pointerMotion.x = xEvent.xmotion.x; event.pointerMotion.y = xEvent.xmotion.y; event.pointerMotion.buttons = _getButtonState( xEvent ); event.pointerMotion.button = PTR_BUTTON_NONE; _computePointerDelta( window, event ); _getRenderContext( window, event ); break; case ButtonPress: event.type = Event::WINDOW_POINTER_BUTTON_PRESS; event.pointerButtonPress.x = xEvent.xbutton.x; event.pointerButtonPress.y = xEvent.xbutton.y; event.pointerButtonPress.buttons = _getButtonState( xEvent ); event.pointerButtonPress.button = _getButtonAction( xEvent ); // Translate wheel events switch( event.pointerButtonPress.button ) { case PTR_BUTTON4: event.pointerWheel.xAxis = 1; break; case PTR_BUTTON5: event.pointerWheel.xAxis = -1; break; case PTR_BUTTON6: event.pointerWheel.yAxis = 1; break; case PTR_BUTTON7: event.pointerWheel.yAxis = -1; break; } switch( event.pointerButtonPress.button ) { case PTR_BUTTON4: case PTR_BUTTON5: case PTR_BUTTON6: case PTR_BUTTON7: event.type = Event::WINDOW_POINTER_WHEEL; event.pointerWheel.button = PTR_BUTTON_NONE; } _computePointerDelta( window, event ); _getRenderContext( window, event ); break; case ButtonRelease: event.type = Event::WINDOW_POINTER_BUTTON_RELEASE; event.pointerButtonRelease.x = xEvent.xbutton.x; event.pointerButtonRelease.y = xEvent.xbutton.y; event.pointerButtonRelease.buttons = _getButtonState( xEvent ); event.pointerButtonRelease.button = _getButtonAction( xEvent); _computePointerDelta( window, event ); _getRenderContext( window, event ); break; case KeyPress: event.type = Event::KEY_PRESS; event.keyPress.key = _getKey( xEvent ); break; case KeyRelease: event.type = Event::KEY_RELEASE; event.keyPress.key = _getKey( xEvent ); break; case ReparentNotify: case VisibilityNotify: event.type = Event::UNKNOWN; EQINFO << "Ignored X event, type " << xEvent.type << std::endl; break; default: event.type = Event::UNKNOWN; EQWARN << "Unhandled X event, type " << xEvent.type << std::endl; break; } event.originator = window->getID(); event.serial = window->getSerial(); _window->processEvent( event ); }
void UnbufferedMasterCM::addSlave( Command& command, NodeMapObjectReplyPacket& reply ) { EQ_TS_THREAD( _cmdThread ); EQASSERT( command->type == PACKETTYPE_CO_NODE ); EQASSERT( command->command == CMD_NODE_MAP_OBJECT ); NodePtr node = command.getNode(); NodeMapObjectPacket* packet = command.get<NodeMapObjectPacket>(); const uint128_t version = packet->requestedVersion; const uint32_t instanceID = packet->instanceID; // add to subscribers ++_slavesCount[ node->getNodeID() ]; _slaves.push_back( node ); stde::usort( _slaves ); #if 0 EQLOG( LOG_OBJECTS ) << "Object id " << _object->_id << " v" << _version << ", instantiate on " << node->getNodeID() << std::endl; #endif reply.version = _version; if( version == VERSION_NONE ) { // no data, send empty packet to set version _sendEmptyVersion( node, instanceID ); return; } #ifndef NDEBUG if( version != VERSION_OLDEST && version < _version ) EQINFO << "Mapping version " << _version << " instead of requested version" << version << std::endl; #endif const bool useCache = packet->masterInstanceID == _object->getInstanceID(); if( useCache && packet->minCachedVersion <= _version && packet->maxCachedVersion >= _version ) { #ifdef EQ_INSTRUMENT_MULTICAST ++_hit; #endif reply.useCache = true; return; } #ifdef EQ_INSTRUMENT_MULTICAST ++_miss; #endif // send instance data ObjectInstanceDataOStream os( this ); os.enableMap( _version, node, instanceID ); _object->getInstanceData( os ); os.disable(); if( os.hasSentData( )) return; // no data, send empty packet to set version _sendEmptyVersion( node, instanceID ); }