#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 ssize_t | sendBytes (const char *buf, size_t numBytes, bool isApp=false) |
Send data to network. | |
void | closeAppSocket () |
Close the application TCP socket. | |
Protected Member Functions | |
virtual int | initializeNetwork ()=0 |
Initialize the network. | |
virtual void | additionalFD () |
This function is called from main loop if data is accessable from "additional_fd". | |
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 |
int | additional_fd |
timeval | baseTime |
Classes | |
class | PacketBufferEntry |
typedef std::list<PacketBufferEntry> RealtimeScheduler::PacketBuffer |
RealtimeScheduler::RealtimeScheduler | ( | ) |
Constructor.
00010 : cScheduler() 00011 { 00012 netw_fd = -1; 00013 app_fd = -1; 00014 additional_fd = -1; 00015 }
virtual void RealtimeScheduler::additionalFD | ( | ) | [inline, protected, virtual] |
This function is called from main loop if data is accessable from "additional_fd".
This FD can be set in initializeNetwork by concrete implementations.
Reimplemented in TunOutScheduler.
void RealtimeScheduler::closeAppSocket | ( | ) |
void RealtimeScheduler::executionResumed | ( | ) | [virtual] |
cMessage * RealtimeScheduler::getNextEvent | ( | ) | [virtual] |
Scheduler function -- it comes from cScheduler interface.
00166 { 00167 // assert that we've been configured 00168 if (!module) 00169 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() not called: it must be called from a module's initialize() function"); 00170 if (app_fd >= 0 && !appModule) 00171 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() not called from application: it must be called from a module's initialize() function"); 00172 00173 // calculate target time 00174 timeval targetTime; 00175 cMessage *msg = sim->msgQueue.peekFirst(); 00176 if (!msg) { 00177 // if there are no events, wait until something comes from outside 00178 // TBD: obey simtimelimit, cpu-time-limit 00179 targetTime.tv_sec = LONG_MAX; 00180 targetTime.tv_usec = 0; 00181 } else { 00182 // use time of next event 00183 simtime_t eventSimtime = msg->arrivalTime(); 00184 targetTime = timeval_add(baseTime, eventSimtime); 00185 } 00186 00187 // if needed, wait until that time arrives 00188 timeval curTime; 00189 gettimeofday(&curTime, NULL); 00190 if (timeval_greater(targetTime, curTime)) { 00191 int status = receiveUntil(targetTime); 00192 if (status == -1) { 00193 printf("WARNING: receiveUntil returned -1 (user interrupt)\n"); 00194 return NULL; // interrupted by user 00195 } else if (status == 1) { 00196 msg = sim->msgQueue.peekFirst(); // received something 00197 } 00198 } else { 00199 // printf("WARNING: Lagging behind realtime!\n"); 00200 // we're behind -- customized versions of this class may 00201 // alert if we're too much behind, whatever that means 00202 } 00203 // ok, return the message 00204 return msg; 00205 }
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 |
00139 { 00140 // if there's more than 200ms to wait, wait in 100ms chunks 00141 // in order to keep UI responsiveness by invoking ev.idle() 00142 timeval curTime; 00143 gettimeofday(&curTime, NULL); 00144 while (targetTime.tv_sec-curTime.tv_sec >=2 || 00145 timeval_diff_usec(targetTime, curTime) >= 200000) { 00146 if (receiveWithTimeout(100000)) { // 100ms 00147 if (ev.idle()) return -1; 00148 return 1; 00149 } 00150 if (ev.idle()) return -1; 00151 gettimeofday(&curTime, NULL); 00152 } 00153 00154 // difference is now at most 100ms, do it at once 00155 long usec = timeval_diff_usec(targetTime, curTime); 00156 if (usec>0) 00157 if (receiveWithTimeout(usec)) { 00158 if (ev.idle()) return -1; 00159 return 1; 00160 } 00161 if (ev.idle()) return -1; 00162 return 0; 00163 }
bool RealtimeScheduler::receiveWithTimeout | ( | long | usec | ) | [protected, virtual] |
Waits for incoming data on the tun device.
usec | Timeout after which to quit waiting (in µsec) |
00067 { 00068 bool newData = false; 00069 // prepare sets for select() 00070 fd_set readFD; 00071 FD_ZERO(&readFD); 00072 00073 if ( netw_fd >= 0 ) FD_SET(netw_fd, &readFD); 00074 if ( app_fd >= 0 ) FD_SET(app_fd, &readFD); 00075 if ( additional_fd >= 0 ) FD_SET(additional_fd, &readFD); 00076 00077 timeval timeout; 00078 timeout.tv_sec = 0; 00079 timeout.tv_usec = usec; 00080 00081 if (select(FD_SETSIZE, &readFD, NULL, NULL, &timeout) > 0) { 00082 // Incoming data 00083 if ( (netw_fd >= 0 ) && (FD_ISSET(netw_fd, &readFD)) ) { 00084 char* buf = new char[buffersize]; 00085 int nBytes = read(netw_fd, buf, buffersize); 00086 if (nBytes < 0) { 00087 opp_error("Read from network device returned an error"); 00088 } else if (nBytes == 0) { 00089 opp_error("network device closed..."); 00090 } else { 00091 // write data to buffer 00092 ev << "RealtimeScheduler: received " << nBytes << " bytes\n"; 00093 packetBuffer->push_back(PacketBufferEntry(buf, nBytes)); 00094 00095 // schedule notificationMsg for the interface module 00096 timeval curTime; 00097 gettimeofday(&curTime, NULL); 00098 curTime = timeval_substract(curTime, baseTime); 00099 simtime_t t = curTime.tv_sec + curTime.tv_usec*1e-6; 00100 // TBD assert that it's somehow not smaller than previous event's time 00101 notificationMsg->setArrival(module,-1,t); 00102 simulation.msgQueue.insert(notificationMsg); 00103 newData = true; 00104 } 00105 } 00106 if ( (app_fd >= 0) && (FD_ISSET(app_fd, &readFD)) ) { 00107 char* buf = new char[appBuffersize]; 00108 int nBytes = read(app_fd, buf, appBuffersize); 00109 if (nBytes < 0) { 00110 opp_error("Read from network device returned an error (App)"); 00111 } else if (nBytes == 0) { 00112 // Application closed Socket 00113 ev << "Application closed socket\n"; 00114 app_fd = -1; 00115 } else { 00116 // write data to buffer 00117 ev << "RealtimeScheduler: received " << nBytes << " bytes\n"; 00118 appPacketBuffer->push_back(PacketBufferEntry(buf, nBytes)); 00119 00120 // schedule notificationMsg for the interface module 00121 timeval curTime; 00122 gettimeofday(&curTime, NULL); 00123 curTime = timeval_substract(curTime, baseTime); 00124 simtime_t t = curTime.tv_sec + curTime.tv_usec*1e-6; 00125 // TBD assert that it's somehow not smaller than previous event's time 00126 appNotificationMsg->setArrival(appModule,-1,t); 00127 simulation.msgQueue.insert(appNotificationMsg); 00128 newData = true; 00129 } 00130 } 00131 if ( (additional_fd >= 0) && (FD_ISSET(additional_fd, &readFD)) ) { 00132 additionalFD(); 00133 } 00134 } 00135 return newData; 00136 }
ssize_t 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 |
00215 { 00216 if (!buf) { 00217 ev << "Error sending packet: buf = NULL!\n"; 00218 return -1; 00219 } 00220 if (!isApp) { 00221 if( numBytes > buffersize ) { 00222 ev << "trying to send oversizd packet: size " << numBytes << " mtu " << buffersize << "\n"; 00223 opp_error("Can't send packet: too large"); //FIXME: Throw exception instead 00224 } 00225 00226 if ( netw_fd < 0 ) { 00227 ev << "Can't send packet to network: no tun socket!" << endl; 00228 return 0; 00229 } 00230 return write(netw_fd, buf, numBytes); 00231 } else { 00232 if( numBytes > appBuffersize ) { 00233 ev << "trying to send oversizd packet: size " << numBytes << " mtu " << appBuffersize << "\n"; 00234 opp_error("Can't send packet: too large"); //FIXME: Throw exception instead 00235 } 00236 if ( app_fd < 0 ) opp_error ("Can't send packet to Application: no socket"); 00237 return write(app_fd, buf, numBytes); 00238 } 00239 // TBD check for errors 00240 }
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 |
00045 { 00046 if (!mod || !notifMsg || !buffer) 00047 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule(): arguments must be non-NULL"); 00048 00049 if (!isApp) { 00050 if (module) 00051 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() already called"); 00052 module = mod; 00053 notificationMsg = notifMsg; 00054 packetBuffer = buffer; 00055 buffersize = mtu; 00056 } else { 00057 if (appModule) 00058 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() already called"); 00059 appModule = mod; 00060 appNotificationMsg = notifMsg; 00061 appPacketBuffer = buffer; 00062 appBuffersize = mtu; 00063 } 00064 }
void RealtimeScheduler::startRun | ( | ) | [virtual] |
Called at the beginning of a simulation run.
00020 { 00021 if (initsocketlibonce()!=0) 00022 throw new cRuntimeError("RealtimeScheduler: Cannot initialize socket library"); 00023 00024 gettimeofday(&baseTime, NULL); 00025 00026 appModule = NULL; 00027 appNotificationMsg = NULL; 00028 module = NULL; 00029 notificationMsg = NULL; 00030 00031 if (initializeNetwork()) { 00032 opp_error("realtimeScheduler error: initializeNetwork failed\n"); 00033 } 00034 }
int RealtimeScheduler::additional_fd [protected] |
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] |