#include <realtimescheduler.h>
Inheritance diagram for RealtimeScheduler:
1 simsec == 1 sec) It must be subclassed; its subclasses must handle network traffic from/to the simulation
Public Types | |
typedef std::list< PacketBufferEntry > | PacketBuffer |
Public Member Functions | |
RealtimeScheduler () | |
Constructor. | |
virtual | ~RealtimeScheduler () |
Destructor. | |
virtual void | startRun () |
Called at the beginning of a simulation run. | |
virtual void | endRun () |
Called at the end of a simulation run. | |
virtual void | executionResumed () |
Recalculates "base time" from current wall clock time. | |
virtual void | setInterfaceModule (cModule *module, cMessage *notificationMsg, PacketBuffer *buffer, int mtu, bool isApp=false) |
To be called from the module which wishes to receive data from the tun device. | |
virtual cMessage * | getNextEvent () |
Scheduler function -- it comes from cScheduler interface. | |
virtual void | sendBytes (const char *buf, size_t numBytes, bool isApp=false) |
Send data to network. | |
Protected Member Functions | |
virtual int | initializeNetwork ()=0 |
Initialize the network. | |
virtual bool | receiveWithTimeout (long usec) |
Waits for incoming data on the tun device. | |
virtual int | receiveUntil (const timeval &targetTime) |
Tries to read data until the given time is up. | |
Protected Attributes | |
int | netw_fd |
cModule * | module |
cMessage * | notificationMsg |
PacketBuffer * | packetBuffer |
size_t | buffersize |
int | app_fd |
cModule * | appModule |
cMessage * | appNotificationMsg |
PacketBuffer * | appPacketBuffer |
size_t | appBuffersize |
timeval | baseTime |
Classes | |
class | PacketBufferEntry |
typedef std::list<PacketBufferEntry> RealtimeScheduler::PacketBuffer |
RealtimeScheduler::RealtimeScheduler | ( | ) |
void RealtimeScheduler::executionResumed | ( | ) | [virtual] |
cMessage * RealtimeScheduler::getNextEvent | ( | ) | [virtual] |
Scheduler function -- it comes from cScheduler interface.
00158 { 00159 // assert that we've been configured 00160 if (!module) 00161 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() not called: it must be called from a module's initialize() function"); 00162 if (app_fd >= 0 && !appModule) 00163 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() not called from application: it must be called from a module's initialize() function"); 00164 00165 // calculate target time 00166 timeval targetTime; 00167 cMessage *msg = sim->msgQueue.peekFirst(); 00168 if (!msg) { 00169 // if there are no events, wait until something comes from outside 00170 // TBD: obey simtimelimit, cpu-time-limit 00171 targetTime.tv_sec = LONG_MAX; 00172 targetTime.tv_usec = 0; 00173 } else { 00174 // use time of next event 00175 simtime_t eventSimtime = msg->arrivalTime(); 00176 targetTime = timeval_add(baseTime, eventSimtime); 00177 } 00178 00179 // if needed, wait until that time arrives 00180 timeval curTime; 00181 gettimeofday(&curTime, NULL); 00182 if (timeval_greater(targetTime, curTime)) { 00183 int status = receiveUntil(targetTime); 00184 if (status == -1) { 00185 printf("WARNING: receiveUntil returned -1 (user interrupt)\n"); 00186 return NULL; // interrupted by user 00187 } else if (status == 1) { 00188 msg = sim->msgQueue.peekFirst(); // received something 00189 } 00190 } else { 00191 // printf("WARNING: Lagging behind realtime!\n"); 00192 // we're behind -- customized versions of this class may 00193 // alert if we're too much behind, whatever that means 00194 } 00195 // ok, return the message 00196 return msg; 00197 }
virtual int RealtimeScheduler::initializeNetwork | ( | ) | [protected, pure virtual] |
int RealtimeScheduler::receiveUntil | ( | const timeval & | targetTime | ) | [protected, virtual] |
Tries to read data until the given time is up.
targetTime | stop waiting after this time is up |
00131 { 00132 // if there's more than 200ms to wait, wait in 100ms chunks 00133 // in order to keep UI responsiveness by invoking ev.idle() 00134 timeval curTime; 00135 gettimeofday(&curTime, NULL); 00136 while (targetTime.tv_sec-curTime.tv_sec >=2 || 00137 timeval_diff_usec(targetTime, curTime) >= 200000) { 00138 if (receiveWithTimeout(100000)) { // 100ms 00139 if (ev.idle()) return -1; 00140 return 1; 00141 } 00142 if (ev.idle()) return -1; 00143 gettimeofday(&curTime, NULL); 00144 } 00145 00146 // difference is now at most 100ms, do it at once 00147 long usec = timeval_diff_usec(targetTime, curTime); 00148 if (usec>0) 00149 if (receiveWithTimeout(usec)) { 00150 if (ev.idle()) return -1; 00151 return 1; 00152 } 00153 if (ev.idle()) return -1; 00154 return 0; 00155 }
bool RealtimeScheduler::receiveWithTimeout | ( | long | usec | ) | [protected, virtual] |
Waits for incoming data on the tun device.
usec | Timeout after which to quit waiting (in µsec) |
00066 { 00067 bool newData = false; 00068 // prepare sets for select() 00069 fd_set readFD; 00070 FD_ZERO(&readFD); 00071 00072 FD_SET(netw_fd, &readFD); 00073 if ( app_fd >= 0 ) FD_SET(app_fd, &readFD); 00074 00075 timeval timeout; 00076 timeout.tv_sec = 0; 00077 timeout.tv_usec = usec; 00078 00079 if (select(FD_SETSIZE, &readFD, NULL, NULL, &timeout) > 0) { 00080 // Incoming data 00081 if (FD_ISSET(netw_fd, &readFD)) { 00082 char* buf = new char[buffersize]; 00083 int nBytes = read(netw_fd, buf, buffersize); 00084 if (nBytes < 0) { 00085 opp_error("Read from network device returned an error"); 00086 } else if (nBytes == 0) { 00087 opp_error("network device closed..."); 00088 } else { 00089 // write data to buffer 00090 ev << "RealtimeScheduler: received " << nBytes << " bytes\n"; 00091 packetBuffer->push_back(PacketBufferEntry(buf, nBytes)); 00092 00093 // schedule notificationMsg for the interface module 00094 timeval curTime; 00095 gettimeofday(&curTime, NULL); 00096 curTime = timeval_substract(curTime, baseTime); 00097 simtime_t t = curTime.tv_sec + curTime.tv_usec*1e-6; 00098 // TBD assert that it's somehow not smaller than previous event's time 00099 notificationMsg->setArrival(module,-1,t); 00100 simulation.msgQueue.insert(notificationMsg); 00101 newData = true; 00102 } 00103 } else if ( (app_fd >= 0) && (FD_ISSET(app_fd, &readFD)) ) { 00104 char* buf = new char[appBuffersize]; 00105 int nBytes = read(app_fd, buf, appBuffersize); 00106 if (nBytes < 0) { 00107 opp_error("Read from network device returned an error"); 00108 } else if (nBytes == 0) { 00109 opp_error("network device closed..."); 00110 } else { 00111 // write data to buffer 00112 ev << "RealtimeScheduler: received " << nBytes << " bytes\n"; 00113 appPacketBuffer->push_back(PacketBufferEntry(buf, nBytes)); 00114 00115 // schedule notificationMsg for the interface module 00116 timeval curTime; 00117 gettimeofday(&curTime, NULL); 00118 curTime = timeval_substract(curTime, baseTime); 00119 simtime_t t = curTime.tv_sec + curTime.tv_usec*1e-6; 00120 // TBD assert that it's somehow not smaller than previous event's time 00121 appNotificationMsg->setArrival(appModule,-1,t); 00122 simulation.msgQueue.insert(appNotificationMsg); 00123 newData = true; 00124 } 00125 } 00126 } 00127 return newData; 00128 }
void RealtimeScheduler::sendBytes | ( | const char * | buf, | |
size_t | numBytes, | |||
bool | isApp = false | |||
) | [virtual] |
Send data to network.
buf | A pointer to the data to be send | |
numBytes | the length of the data | |
isApp | set to "true" if called from a realworldApp |
00200 { 00201 if (!buf) { 00202 ev << "Error sending packet: buf = NULL!\n"; 00203 return; 00204 } 00205 if (!isApp) { 00206 if( numBytes > buffersize ) { 00207 ev << "trying to send oversizd packet: size " << numBytes << " mtu " << buffersize << "\n"; 00208 opp_error("Can't send packet: too large"); //FIXME: Throw exception instead 00209 } 00210 write(netw_fd, buf, numBytes); 00211 } else { 00212 if( numBytes > appBuffersize ) { 00213 ev << "trying to send oversizd packet: size " << numBytes << " mtu " << appBuffersize << "\n"; 00214 opp_error("Can't send packet: too large"); //FIXME: Throw exception instead 00215 } 00216 if ( app_fd < 0 ) opp_error ("Can't send packet to Application: no socket"); 00217 write(app_fd, buf, numBytes); 00218 } 00219 // TBD check for errors 00220 }
void RealtimeScheduler::setInterfaceModule | ( | cModule * | module, | |
cMessage * | notificationMsg, | |||
PacketBuffer * | buffer, | |||
int | mtu, | |||
bool | isApp = false | |||
) | [virtual] |
To be called from the module which wishes to receive data from the tun device.
The method must be called from the module's initialize() function.
module | Pointer to the module that whishes to receive the data | |
notificationMsg | A pointer to a message that will be sheduled if there is data to read | |
buffer | A pointer to the buffer the data will be written into | |
mtu | Max allowed packet size | |
isApp | set to "true" if called from a realworldApp |
00044 { 00045 if (!mod || !notifMsg || !buffer) 00046 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule(): arguments must be non-NULL"); 00047 00048 if (!isApp) { 00049 if (module) 00050 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() already called"); 00051 module = mod; 00052 notificationMsg = notifMsg; 00053 packetBuffer = buffer; 00054 buffersize = mtu; 00055 } else { 00056 if (appModule) 00057 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() already called"); 00058 appModule = mod; 00059 appNotificationMsg = notifMsg; 00060 appPacketBuffer = buffer; 00061 appBuffersize = mtu; 00062 } 00063 }
void RealtimeScheduler::startRun | ( | ) | [virtual] |
Called at the beginning of a simulation run.
00019 { 00020 if (initsocketlibonce()!=0) 00021 throw new cRuntimeError("RealtimeScheduler: Cannot initialize socket library"); 00022 00023 gettimeofday(&baseTime, NULL); 00024 00025 appModule = NULL; 00026 appNotificationMsg = NULL; 00027 module = NULL; 00028 notificationMsg = NULL; 00029 00030 if (initializeNetwork()) { 00031 opp_error("realtimeScheduler error: initializeNetwork failed\n"); 00032 } 00033 }
int RealtimeScheduler::app_fd [protected] |
size_t RealtimeScheduler::appBuffersize [protected] |
cModule* RealtimeScheduler::appModule [protected] |
cMessage* RealtimeScheduler::appNotificationMsg [protected] |
PacketBuffer* RealtimeScheduler::appPacketBuffer [protected] |
timeval RealtimeScheduler::baseTime [protected] |
size_t RealtimeScheduler::buffersize [protected] |
cModule* RealtimeScheduler::module [protected] |
int RealtimeScheduler::netw_fd [protected] |
cMessage* RealtimeScheduler::notificationMsg [protected] |
PacketBuffer* RealtimeScheduler::packetBuffer [protected] |