RealtimeScheduler Class Reference

#include <realtimescheduler.h>

Inheritance diagram for RealtimeScheduler:

TunOutScheduler List of all members.

Detailed Description

This class implements a event scheduler for omnet It makes the simulation run in realtime (i.e.

1 simsec == 1 sec) It must be subclassed; its subclasses must handle network traffic from/to the simulation


Public Types

typedef std::list< PacketBufferEntryPacketBuffer

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
PacketBufferpacketBuffer
size_t buffersize
int app_fd
cModule * appModule
cMessage * appNotificationMsg
PacketBufferappPacketBuffer
size_t appBuffersize
int additional_fd
timeval baseTime

Classes

class  PacketBufferEntry


Member Typedef Documentation

typedef std::list<PacketBufferEntry> RealtimeScheduler::PacketBuffer


Constructor & Destructor Documentation

RealtimeScheduler::RealtimeScheduler (  ) 

Constructor.

00010                                      : cScheduler()
00011 {
00012     netw_fd = -1;
00013     app_fd = -1;
00014     additional_fd = -1;
00015 }

RealtimeScheduler::~RealtimeScheduler (  )  [virtual]

Destructor.

00017 { }


Member Function Documentation

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.

00054 {};

void RealtimeScheduler::closeAppSocket (  ) 

Close the application TCP socket.

00208 {
00209     close(app_fd);
00210     app_fd = -1;
00211 }

void RealtimeScheduler::endRun (  )  [virtual]

Called at the end of a simulation run.

00036 {}

void RealtimeScheduler::executionResumed (  )  [virtual]

Recalculates "base time" from current wall clock time.

00039 {
00040     gettimeofday(&baseTime, NULL);
00041     baseTime = timeval_substract(baseTime, sim->simTime());
00042 }

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]

Initialize the network.

Implemented in TunOutScheduler.

int RealtimeScheduler::receiveUntil ( const timeval &  targetTime  )  [protected, virtual]

Tries to read data until the given time is up.

Parameters:
targetTime stop waiting after this time is up
Returns:
1 if data is read, -1 if there is an error, 0 if no data is read
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.

Parameters:
usec Timeout after which to quit waiting (in µsec)
Returns:
true if data was read, false otherwise
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.

Parameters:
buf A pointer to the data to be send
numBytes the length of the data
isApp set to "true" if called from a realworldApp
Returns:
The number of bytes written, -1 on error
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.

Parameters:
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 }


Member Data Documentation

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]


The documentation for this class was generated from the following files:
Generated on Fri May 11 14:52:40 2007 for ITM OverSim by  doxygen 1.4.7