| 1 | // [License]
 | 
|---|
| 2 | // The Ariba-Underlay Copyright
 | 
|---|
| 3 | //
 | 
|---|
| 4 | // Copyright (c) 2008-2009, Institute of Telematics, UniversitÀt Karlsruhe (TH)
 | 
|---|
| 5 | //
 | 
|---|
| 6 | // Institute of Telematics
 | 
|---|
| 7 | // UniversitÀt Karlsruhe (TH)
 | 
|---|
| 8 | // Zirkel 2, 76128 Karlsruhe
 | 
|---|
| 9 | // Germany
 | 
|---|
| 10 | //
 | 
|---|
| 11 | // Redistribution and use in source and binary forms, with or without
 | 
|---|
| 12 | // modification, are permitted provided that the following conditions are
 | 
|---|
| 13 | // met:
 | 
|---|
| 14 | //
 | 
|---|
| 15 | // 1. Redistributions of source code must retain the above copyright
 | 
|---|
| 16 | // notice, this list of conditions and the following disclaimer.
 | 
|---|
| 17 | // 2. Redistributions in binary form must reproduce the above copyright
 | 
|---|
| 18 | // notice, this list of conditions and the following disclaimer in the
 | 
|---|
| 19 | // documentation and/or other materials provided with the distribution.
 | 
|---|
| 20 | //
 | 
|---|
| 21 | // THIS SOFTWARE IS PROVIDED BY THE INSTITUTE OF TELEMATICS ``AS IS'' AND
 | 
|---|
| 22 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
|---|
| 23 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
|---|
| 24 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ARIBA PROJECT OR
 | 
|---|
| 25 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
|---|
| 26 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
|---|
| 27 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
|---|
| 28 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | 
|---|
| 29 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
|---|
| 30 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
|---|
| 31 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
|---|
| 32 | //
 | 
|---|
| 33 | // The views and conclusions contained in the software and documentation
 | 
|---|
| 34 | // are those of the authors and should not be interpreted as representing
 | 
|---|
| 35 | // official policies, either expressed or implied, of the Institute of
 | 
|---|
| 36 | // Telematics.
 | 
|---|
| 37 | // [License]
 | 
|---|
| 38 | 
 | 
|---|
| 39 | #ifndef SYSTEMQUEUE_H_
 | 
|---|
| 40 | #define SYSTEMQUEUE_H_
 | 
|---|
| 41 | 
 | 
|---|
| 42 | #include <vector>
 | 
|---|
| 43 | #include <cassert>
 | 
|---|
| 44 | #include "SystemEvent.h"
 | 
|---|
| 45 | #include "SystemEventListener.h"
 | 
|---|
| 46 | #include "ariba/utility/logging/Logging.h"
 | 
|---|
| 47 | #include <boost/date_time.hpp>
 | 
|---|
| 48 | #include <boost/cstdint.hpp>
 | 
|---|
| 49 | 
 | 
|---|
| 50 | #ifdef UNDERLAY_OMNET
 | 
|---|
| 51 |   #include <csimplemodule.h>
 | 
|---|
| 52 |   #include <cmessage.h>
 | 
|---|
| 53 |   #include <macros.h>
 | 
|---|
| 54 | #else
 | 
|---|
| 55 |   #include <boost/thread/mutex.hpp>
 | 
|---|
| 56 |   #include <boost/thread/thread.hpp>
 | 
|---|
| 57 |   #include <boost/thread/condition_variable.hpp>
 | 
|---|
| 58 |   #include <boost/utility.hpp>
 | 
|---|
| 59 |   #include <boost/bind.hpp>
 | 
|---|
| 60 | #endif
 | 
|---|
| 61 | 
 | 
|---|
| 62 | using std::vector;
 | 
|---|
| 63 | using boost::posix_time::ptime;
 | 
|---|
| 64 | 
 | 
|---|
| 65 | namespace ariba {
 | 
|---|
| 66 | namespace utility {
 | 
|---|
| 67 | 
 | 
|---|
| 68 | /**
 | 
|---|
| 69 |  * This class implements a simple system event queue to allow
 | 
|---|
| 70 |  * a simulation of cooperative multitasking. It also allows
 | 
|---|
| 71 |  * events to be scheduled from other tasks. This allows
 | 
|---|
| 72 |  * dispatching asynchronous tasks.
 | 
|---|
| 73 |  *
 | 
|---|
| 74 |  * @author Christoph Mayer, Sebastian Mies
 | 
|---|
| 75 |  */
 | 
|---|
| 76 | 
 | 
|---|
| 77 | #ifndef UNDERLAY_OMNET
 | 
|---|
| 78 | class SystemQueue : private boost::noncopyable {
 | 
|---|
| 79 | #else
 | 
|---|
| 80 | class SystemQueue : public cSimpleModule {
 | 
|---|
| 81 | #endif
 | 
|---|
| 82 |         
 | 
|---|
| 83 |         use_logging_h(SystemQueue);
 | 
|---|
| 84 |         friend class EnterMethod;
 | 
|---|
| 85 | public:
 | 
|---|
| 86 |         /**
 | 
|---|
| 87 |          * Get the SystemQueue singleton instance.
 | 
|---|
| 88 |          */
 | 
|---|
| 89 |         static SystemQueue& instance() {
 | 
|---|
| 90 |                 static SystemQueue _inst;
 | 
|---|
| 91 |                 return _inst;
 | 
|---|
| 92 |         }
 | 
|---|
| 93 | 
 | 
|---|
| 94 | #ifdef UNDERLAY_OMNET
 | 
|---|
| 95 |         /**
 | 
|---|
| 96 |          * Prevent deletion of this module
 | 
|---|
| 97 |          * by implementing the virtual method
 | 
|---|
| 98 |          * and doing nothing in it
 | 
|---|
| 99 |          */
 | 
|---|
| 100 |         virtual void deleteModule(){}
 | 
|---|
| 101 | #endif
 | 
|---|
| 102 | 
 | 
|---|
| 103 |         /**
 | 
|---|
| 104 |          * This methods schedules a given event.
 | 
|---|
| 105 |          *
 | 
|---|
| 106 |          * @param The event to be scheduled
 | 
|---|
| 107 |          * @param The delay in milli-seconds
 | 
|---|
| 108 |          */
 | 
|---|
| 109 |         void scheduleEvent( const SystemEvent& event, uint32_t delay = 0 );
 | 
|---|
| 110 | 
 | 
|---|
| 111 |         /**
 | 
|---|
| 112 |          * Starts the processing and waiting for events.
 | 
|---|
| 113 |          * Use <code>cancel()</code> to end system queue processing and
 | 
|---|
| 114 |          * <code>isEmpty()</code> to check wheter the queue is empty.
 | 
|---|
| 115 |          */
 | 
|---|
| 116 |         void run();
 | 
|---|
| 117 | 
 | 
|---|
| 118 |         /**
 | 
|---|
| 119 |          * Cancels the system queue and ends the processing after the
 | 
|---|
| 120 |          * currently processed event is processed.
 | 
|---|
| 121 |          *
 | 
|---|
| 122 |          * This method is thread-safe.
 | 
|---|
| 123 |          */
 | 
|---|
| 124 |         void cancel();
 | 
|---|
| 125 | 
 | 
|---|
| 126 |         /**
 | 
|---|
| 127 |          * Check wheter this queue has items or not.
 | 
|---|
| 128 |          *
 | 
|---|
| 129 |          * @return True, if this queue is empty.
 | 
|---|
| 130 |          */
 | 
|---|
| 131 |         bool isEmpty();
 | 
|---|
| 132 | 
 | 
|---|
| 133 |         /**
 | 
|---|
| 134 |          * Is the system queue already started and running?
 | 
|---|
| 135 |          *
 | 
|---|
| 136 |          * @return True, if the system queue is running.
 | 
|---|
| 137 |          */
 | 
|---|
| 138 |         bool isRunning();
 | 
|---|
| 139 | 
 | 
|---|
| 140 | protected:
 | 
|---|
| 141 | 
 | 
|---|
| 142 |         /**
 | 
|---|
| 143 |          * Aqcuire the mutex
 | 
|---|
| 144 |          */
 | 
|---|
| 145 |         void enterMethod();
 | 
|---|
| 146 | 
 | 
|---|
| 147 |         /**
 | 
|---|
| 148 |          * Leave the mutex
 | 
|---|
| 149 |          */
 | 
|---|
| 150 |         void leaveMethod();
 | 
|---|
| 151 | 
 | 
|---|
| 152 |         /**
 | 
|---|
| 153 |          * Constructs a system queue.
 | 
|---|
| 154 |          */
 | 
|---|
| 155 |         SystemQueue();
 | 
|---|
| 156 | 
 | 
|---|
| 157 |         /**
 | 
|---|
| 158 |          * Destroys the system queue. Beware that all events
 | 
|---|
| 159 |          * are canceled
 | 
|---|
| 160 |          */
 | 
|---|
| 161 |         ~SystemQueue();
 | 
|---|
| 162 | 
 | 
|---|
| 163 | #ifdef UNDERLAY_OMNET
 | 
|---|
| 164 |         virtual void handleMessage( cMessage* msg );
 | 
|---|
| 165 | #endif
 | 
|---|
| 166 | 
 | 
|---|
| 167 | private:
 | 
|---|
| 168 | 
 | 
|---|
| 169 | #ifndef UNDERLAY_OMNET
 | 
|---|
| 170 |         typedef vector<SystemEvent> EventQueue;
 | 
|---|
| 171 | 
 | 
|---|
| 172 |         //********************************************************
 | 
|---|
| 173 | 
 | 
|---|
| 174 |         class QueueThread {
 | 
|---|
| 175 |         public:
 | 
|---|
| 176 |                 QueueThread(QueueThread* _transferQueue = NULL);
 | 
|---|
| 177 |                 virtual ~QueueThread();
 | 
|---|
| 178 |                 void run();
 | 
|---|
| 179 |                 void cancel();
 | 
|---|
| 180 |                 bool isEmpty();
 | 
|---|
| 181 |                 void insert( const SystemEvent& event, uint32_t delay );
 | 
|---|
| 182 |                 void enter();
 | 
|---|
| 183 |                 void leave();
 | 
|---|
| 184 | 
 | 
|---|
| 185 |         protected:
 | 
|---|
| 186 |                 virtual void onItemInserted( const SystemEvent& event ) = 0;
 | 
|---|
| 187 |                 virtual void onNextQueueItem( const SystemEvent& event ) = 0;
 | 
|---|
| 188 |                 QueueThread* transferQueue;
 | 
|---|
| 189 |                 EventQueue eventsQueue;
 | 
|---|
| 190 |                 boost::mutex queueMutex;
 | 
|---|
| 191 |         private:
 | 
|---|
| 192 |                 boost::thread* queueThread;
 | 
|---|
| 193 |                 static void threadFunc( QueueThread* obj );
 | 
|---|
| 194 |                 boost::condition_variable itemsAvailable;
 | 
|---|
| 195 |                 volatile bool running;
 | 
|---|
| 196 |         }; // class QueueThread
 | 
|---|
| 197 | 
 | 
|---|
| 198 |         //********************************************************
 | 
|---|
| 199 | 
 | 
|---|
| 200 |         class QueueThreadDirect : public QueueThread {
 | 
|---|
| 201 |         public:
 | 
|---|
| 202 |                 QueueThreadDirect();
 | 
|---|
| 203 |                 ~QueueThreadDirect();
 | 
|---|
| 204 |         protected:
 | 
|---|
| 205 |                 virtual void onItemInserted( const SystemEvent& event );
 | 
|---|
| 206 |                 virtual void onNextQueueItem( const SystemEvent& event );
 | 
|---|
| 207 |         }; // class QueueThreadDirect
 | 
|---|
| 208 | 
 | 
|---|
| 209 |         //********************************************************
 | 
|---|
| 210 | 
 | 
|---|
| 211 |         class QueueThreadDelay : public QueueThread {
 | 
|---|
| 212 |         public:
 | 
|---|
| 213 |                 QueueThreadDelay(QueueThread* _transferQueue = NULL);
 | 
|---|
| 214 |                 ~QueueThreadDelay();
 | 
|---|
| 215 |         protected:
 | 
|---|
| 216 |                 virtual void onItemInserted( const SystemEvent& event );
 | 
|---|
| 217 |                 virtual void onNextQueueItem( const SystemEvent& event );
 | 
|---|
| 218 |         private:
 | 
|---|
| 219 |                 volatile bool isSleeping;
 | 
|---|
| 220 |                 ptime sleepStart;
 | 
|---|
| 221 |                 boost::mutex sleepMutex;
 | 
|---|
| 222 |                 boost::condition_variable sleepCond;
 | 
|---|
| 223 |         }; // class QueueThreadDelay
 | 
|---|
| 224 | 
 | 
|---|
| 225 |         //********************************************************
 | 
|---|
| 226 | 
 | 
|---|
| 227 |         QueueThreadDirect directScheduler;
 | 
|---|
| 228 |         QueueThreadDelay delayScheduler;
 | 
|---|
| 229 |         volatile bool systemQueueRunning;
 | 
|---|
| 230 | #endif
 | 
|---|
| 231 | 
 | 
|---|
| 232 | }; // class SystemQueue
 | 
|---|
| 233 | 
 | 
|---|
| 234 | #ifdef UNDERLAY_OMNET
 | 
|---|
| 235 | 
 | 
|---|
| 236 |         //
 | 
|---|
| 237 |         // the system queue must be a singleton in simulations, too.
 | 
|---|
| 238 |         // and to include it in the simulation the module is defined
 | 
|---|
| 239 |         // as submodule in every SpoVNet host. Therefore we hack the
 | 
|---|
| 240 |         // Define_Module (see omnet/includes/macros.h) the way we need
 | 
|---|
| 241 |         // it with our singleton ...
 | 
|---|
| 242 |         //
 | 
|---|
| 243 |         // this is the macro definition from macros.h
 | 
|---|
| 244 |         //
 | 
|---|
| 245 |         // #define Define_Module(CLASSNAME) \
 | 
|---|
| 246 |         //   static cModule *CLASSNAME##__create() {return new CLASSNAME();} \
 | 
|---|
| 247 |         //   EXECUTE_ON_STARTUP(CLASSNAME##__mod, modtypes.instance()->add(new cModuleType(#CLASSNAME,#CLASSNAME,(ModuleCreateFunc)CLASSNAME##__create));)
 | 
|---|
| 248 |         //
 | 
|---|
| 249 |         // and this is how we do it :)
 | 
|---|
| 250 |         //
 | 
|---|
| 251 | 
 | 
|---|
| 252 |         static cModule* SystemQueue__create() {
 | 
|---|
| 253 |                 return &SystemQueue::instance();
 | 
|---|
| 254 |         }
 | 
|---|
| 255 | 
 | 
|---|
| 256 |         EXECUTE_ON_STARTUP(SystemQueue__mod, modtypes.instance()->add(new cModuleType("SystemQueue","SystemQueue",(ModuleCreateFunc)SystemQueue__create));)
 | 
|---|
| 257 | 
 | 
|---|
| 258 | #endif
 | 
|---|
| 259 | 
 | 
|---|
| 260 | }} // spovnet, common
 | 
|---|
| 261 | 
 | 
|---|
| 262 | #endif /* SYSTEMQUEUE_H_ */
 | 
|---|