diff -ru certi.orig/include/RTIambServices.hh certi.new/include/RTIambServices.hh --- certi.orig/include/RTIambServices.hh 2007-06-14 15:00:21.000000000 +0200 +++ certi.new/include/RTIambServices.hh 2008-04-01 16:03:29.000000000 +0200 @@ -475,7 +475,7 @@ Boolean tick2() throw (SpecifiedSaveLabelDoesNotExist, ConcurrentAccessAttempted, RTIinternalError); -Boolean tick_kernel(bool) +Boolean __evoke_callback(TickTime) throw (SpecifiedSaveLabelDoesNotExist, ConcurrentAccessAttempted, RTIinternalError); Boolean tick(TickTime, TickTime) diff -ru certi.orig/libCERTI/Message.cc certi.new/libCERTI/Message.cc --- certi.orig/libCERTI/Message.cc 2008-02-27 17:38:27.000000000 +0100 +++ certi.new/libCERTI/Message.cc 2008-04-01 15:54:40.000000000 +0200 @@ -194,6 +194,13 @@ // ---------------------------------------------------------------------------- void +Message::setTickTime(RTI::TickTime time) +{ + tickTime = time; +} + +// ---------------------------------------------------------------------------- +void Message::setDimension(DimensionHandle handle) { dimension = handle ; @@ -603,6 +610,7 @@ dimension = msg.dimension ; // transportation = msg.transportation ; // ordering = msg.ordering ; + tickTime = msg.tickTime ; strcpy(tag, msg.tag); strcpy(name, msg.name); diff -ru certi.orig/libCERTI/Message.hh certi.new/libCERTI/Message.hh --- certi.orig/libCERTI/Message.hh 2007-12-17 17:01:25.000000000 +0100 +++ certi.new/libCERTI/Message.hh 2008-04-01 15:33:34.000000000 +0200 @@ -310,6 +310,9 @@ long getRegion() const { return region ; }; void setRegion(long); + RTI::TickTime getTickTime() const { return tickTime ; }; + void setTickTime(RTI::TickTime); + void setFederationTimeDelta(FederationTimeDelta); FederationTimeDelta getFederationTimeDelta() const { return lookahead ; }; @@ -415,6 +418,7 @@ // OrderingHandle ordering ; unsigned long number ; long region ; + RTI::TickTime tickTime; public: // used for both Attributes and Parameters arrays. diff -ru certi.orig/libCERTI/Message_R.cc certi.new/libCERTI/Message_R.cc --- certi.orig/libCERTI/Message_R.cc 2008-03-13 15:39:19.000000000 +0100 +++ certi.new/libCERTI/Message_R.cc 2008-04-01 15:34:22.000000000 +0200 @@ -441,7 +441,12 @@ case DISABLE_TIME_REGULATION: case ENABLE_TIME_CONSTRAINED: case DISABLE_TIME_CONSTRAINED: + boolean = body.readLongInt(); + break ; + + // Body contains TickTime, boolean case TICK_REQUEST: + body.readBlock((char *)&tickTime, sizeof(tickTime)); boolean = body.readLongInt(); break ; diff -ru certi.orig/libCERTI/Message_W.cc certi.new/libCERTI/Message_W.cc --- certi.orig/libCERTI/Message_W.cc 2008-03-13 15:39:19.000000000 +0100 +++ certi.new/libCERTI/Message_W.cc 2008-04-01 15:34:45.000000000 +0200 @@ -454,7 +454,12 @@ case DISABLE_TIME_REGULATION: case ENABLE_TIME_CONSTRAINED: case DISABLE_TIME_CONSTRAINED: + body.writeLongInt(boolean); + break ; + + // Body contains TickTime, boolean case TICK_REQUEST: + body.writeBlock((char *)&tickTime, sizeof(tickTime)); body.writeLongInt(boolean); break ; diff -ru certi.orig/libRTI/RTIambassador.cc certi.new/libRTI/RTIambassador.cc --- certi.orig/libRTI/RTIambassador.cc 2008-03-13 15:39:19.000000000 +0100 +++ certi.new/libRTI/RTIambassador.cc 2008-04-01 17:56:05.000000000 +0200 @@ -195,7 +195,10 @@ } // ---------------------------------------------------------------------------- -// Tick +//! Evoke callback (HLA1.3). +/*! Evokes a single callback, but doesn't wait for it. + * @return true if additional callbacks pending, false otherwise + */ RTI::Boolean RTI::RTIambassador::tick() throw (SpecifiedSaveLabelDoesNotExist, @@ -203,11 +206,15 @@ RTIinternalError) { // non-blocking tick, returns immediately with or without 1 callback - return tick_kernel (false); + return __evoke_callback(0.0); } // ---------------------------------------------------------------------------- -// Tick +//! Evoke callback (CERTI extension). +/*! Blocks until a callback delivery and then evokes a single callback. + * @return true if additional callbacks pending, false otherwise + * @warning This is a non-standard extension of the HLA 1.3 API. + */ RTI::Boolean RTI::RTIambassador::tick2() throw (SpecifiedSaveLabelDoesNotExist, @@ -215,13 +222,19 @@ RTIinternalError) { // blocking tick, waits until a callback delivery, be careful - return tick_kernel (true); + // use maximal timeout for select() + return __evoke_callback(LONG_MAX); } // ---------------------------------------------------------------------------- -// Tick_kernel +//! Evoke callback (CERTI extension). +/*! Blocks up to "minimum" seconds until a callback delivery and then evokes a + * single callback. + * @return true if additional callbacks pending, false otherwise + * @warning This is a non-standard extension of the HLA 1.3 API. + */ RTI::Boolean -RTI::RTIambassador::tick_kernel(bool locked) +RTI::RTIambassador::__evoke_callback(TickTime minimum) throw (SpecifiedSaveLabelDoesNotExist, ConcurrentAccessAttempted, RTIinternalError) @@ -230,10 +243,7 @@ // Prevenir le RTI vers_RTI.type = Message::TICK_REQUEST ; - if (locked) - vers_RTI.setBoolean(true); - else - vers_RTI.setBoolean(false); + vers_RTI.setTickTime(std::max(0.0, minimum)); try { vers_RTI.write(privateRefs->socketUn); @@ -515,14 +525,48 @@ } // ---------------------------------------------------------------------------- + +static RTI::TickTime currentTickTime() +{ + RTI::TickTime result; +#ifdef _WIN32 + _timeb timev; + _ftime(&timev); + result = timev.time + timev.millitm/1000; +#else + struct timeval timev; + gettimeofday(&timev, NULL); + result = timev.tv_sec + timev.tv_usec/1000000; +#endif + return result; +} + +// ---------------------------------------------------------------------------- +//! Evoke multiple callbacks (HLA1.3). +/*! Blocks up to "minimum" seconds until a callback delivery, then envokes + * multiple callbacks until no callback is pending, or until "maximum" + * duration is reached. + * @return true if additional callbacks pending, false otherwise + */ RTI::Boolean -RTI::RTIambassador::tick(TickTime, TickTime) +RTI::RTIambassador::tick(TickTime minimum, TickTime maximum) throw (SpecifiedSaveLabelDoesNotExist, ConcurrentAccessAttempted, RTIinternalError) { - return tick(); -} + RTI::TickTime start_tick = currentTickTime(); + RTI::Boolean pending = __evoke_callback(minimum); + while(pending) + { + RTI::TickTime current_tick = currentTickTime(); + if(current_tick > maximum+start_tick) + break; + + pending = __evoke_callback(minimum+start_tick - current_tick); + } + + return pending; +} // ---------------------------------------------------------------------------- // Create Federation Execution. diff -ru certi.orig/RTIA/Communications.cc certi.new/RTIA/Communications.cc --- certi.orig/RTIA/Communications.cc 2008-02-22 12:34:30.000000000 +0100 +++ certi.new/RTIA/Communications.cc 2008-04-01 17:22:45.000000000 +0200 @@ -180,7 +180,8 @@ Returns the actual source in the 1st parameter (RTIG=>1 federate=>2) */ void -Communications::readMessage(int &n, NetworkMessage *msg_reseau, Message *msg) +Communications::readMessage(int &n, NetworkMessage *msg_reseau, Message *msg, + struct timeval *timeout) { const int tcp_fd(SecureTCPSocket::returnSocket()); const int udp_fd(SocketUDP::returnSocket()); @@ -241,7 +242,7 @@ else { // waitingList is empty and no data in TCP buffer. // Wait a message (coming from federate or network). - if (select(max_fd, &fdset, NULL, NULL, NULL) < 0) { + if (select(max_fd, &fdset, NULL, NULL, timeout) < 0) { #ifdef _WIN32 if(WSAGetLastError() == WSAEINTR) #else @@ -275,12 +276,16 @@ msg_reseau->read((SocketUDP *) this); n = 1 ; } - else { + else if (FD_ISSET(_socket_un, &fdset)) { // Read a message coming from the federate. - assert(FD_ISSET(_socket_un, &fdset)); receiveUN(msg); n = 2 ; } + else + { + // select() timeout occured + n = 3; + } } } diff -ru certi.orig/RTIA/Communications.hh certi.new/RTIA/Communications.hh --- certi.orig/RTIA/Communications.hh 2008-02-22 12:34:30.000000000 +0100 +++ certi.new/RTIA/Communications.hh 2008-04-01 15:39:54.000000000 +0200 @@ -54,7 +54,7 @@ void sendMessage(NetworkMessage *Msg); void sendUN(Message *Msg); void receiveUN(Message *Msg); - void readMessage(int&, NetworkMessage *, Message *); + void readMessage(int&, NetworkMessage *, Message *, struct timeval *); void requestFederateService(Message *req); unsigned long getAddress(); unsigned int getPort(); diff -ru certi.orig/RTIA/RTIA.cc certi.new/RTIA/RTIA.cc --- certi.orig/RTIA/RTIA.cc 2008-03-14 15:52:23.000000000 +0100 +++ certi.new/RTIA/RTIA.cc 2008-04-01 17:53:12.000000000 +0200 @@ -109,7 +109,7 @@ msg_un = new Message ; try { - comm->readMessage(n, msg_tcp_udp, msg_un); + comm->readMessage(n, msg_tcp_udp, msg_un, NULL); } catch (NetworkSignal) { fm->_fin_execution = true ; @@ -129,6 +129,8 @@ processFederateRequest(msg_un); delete msg_tcp_udp ; break ; + case 3: // timeout + break ; default: assert(false); } @@ -137,12 +139,16 @@ while (!fm->_fin_execution && tm->_ongoing_tick) { // read a message from the rtig // same code is reused, but only the case 1 should match - msg_tcp_udp = new NetworkMessage ; msg_un = new Message ; + struct timeval timev; + timev.tv_sec = int(tm->_tick_timeout); + timev.tv_usec = int((tm->_tick_timeout-timev.tv_sec)*1000000.0); + try { - comm->readMessage(n, msg_tcp_udp, msg_un); + comm->readMessage(n, msg_tcp_udp, msg_un, &timev); + /* timev is undefined after select() */ } catch (NetworkSignal) { fm->_fin_execution = true ; @@ -156,11 +162,21 @@ break ; case 1: processNetworkMessage(msg_tcp_udp) ; // could authorize a callbak + // FIXME: !!!!! _ongoing_tick is reset in processNetworkMessage + // what are the following 3 lines good for? could be removed? msg_un->type = Message::TICK_REQUEST ; msg_un->setBoolean(true) ; processFederateRequest(msg_un); //could reset _ongoing_tick break ; case 2: + assert(false); + case 3: // timeout + tm->_ongoing_tick = false; + // terminate tick() in federate + msg_un->type = Message::TICK_REQUEST; + msg_un->setBoolean(false); + comm->requestFederateService(msg_un); + break ; default: assert(false); } diff -ru certi.orig/RTIA/RTIA_federate.cc certi.new/RTIA/RTIA_federate.cc --- certi.orig/RTIA/RTIA_federate.cc 2008-03-14 15:52:23.000000000 +0100 +++ certi.new/RTIA/RTIA_federate.cc 2008-04-01 15:53:04.000000000 +0200 @@ -939,7 +939,8 @@ case Message::TICK_REQUEST: tm->_tick_request_ack = true ; - if (req->getBoolean()) { + tm->_tick_timeout = req->getTickTime(); + if (tm->_tick_timeout > 0.0) { tm->_ongoing_tick = true ; D.Out(pdDebug, "Receiving Message from Federate, type TickRequest2."); diff -ru certi.orig/RTIA/TimeManagement.hh certi.new/RTIA/TimeManagement.hh --- certi.orig/RTIA/TimeManagement.hh 2008-03-13 15:39:19.000000000 +0100 +++ certi.new/RTIA/TimeManagement.hh 2008-04-01 15:50:25.000000000 +0200 @@ -106,6 +106,7 @@ // Attribute bool _ongoing_tick; // tick2 processing + RTI::TickTime _tick_timeout; bool _tick_request_ack; // do we have to acknowledge the tick request bool _asynchronous_delivery ;