Sirikata
|
00001 /* Sirikata 00002 * Context.hpp 00003 * 00004 * Copyright (c) 2009, Ewen Cheslack-Postava 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions are 00009 * met: 00010 * * Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * * Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in 00014 * the documentation and/or other materials provided with the 00015 * distribution. 00016 * * Neither the name of Sirikata nor the names of its contributors may 00017 * be used to endorse or promote products derived from this software 00018 * without specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 00021 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 00022 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 00023 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 00024 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00026 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00027 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00028 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00029 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00030 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 */ 00032 00033 #ifndef _SIRIKATA_CONTEXT_HPP_ 00034 #define _SIRIKATA_CONTEXT_HPP_ 00035 00036 #include <sirikata/core/network/IOService.hpp> 00037 #include <sirikata/core/network/IOStrand.hpp> 00038 #include <sirikata/core/network/IOTimer.hpp> 00039 #include <sirikata/core/util/Thread.hpp> 00040 #include <sirikata/core/util/Timer.hpp> 00041 #include "TimeProfiler.hpp" 00042 #include "Service.hpp" 00043 #include "Signal.hpp" 00044 #include <sirikata/core/trace/TimeSeries.hpp> 00045 00046 #define FORCE_MONOTONIC_CLOCK 1 00047 00048 namespace Sirikata { 00049 00050 namespace Trace { 00051 class Trace; 00052 } 00053 00054 namespace Command { 00055 class Commander; 00056 } 00057 00061 class SIRIKATA_EXPORT Context : public Service { 00062 public: 00063 00068 enum ExecutionThreads { 00069 IncludeOriginal, 00070 AllNew 00071 }; 00072 00073 Context(const String& name, Network::IOService* ios, Network::IOStrand* strand, Trace::Trace* _trace, const Time& epoch, const Duration& simlen = Duration::zero()); 00074 ~Context(); 00075 00076 Time epoch() const { 00077 return mEpoch.read(); 00078 } 00079 Duration sinceEpoch(const Time& rawtime) const { 00080 return rawtime - mEpoch.read(); 00081 } 00082 Time simTime(const Duration& sinceStart) const { 00083 if (sinceStart.toMicroseconds() < 0) 00084 return Time::null(); 00085 return Time::null() + sinceStart; 00086 } 00087 Time simTime(const Time& rawTime) const { 00088 return simTime( sinceEpoch(rawTime) ); 00089 } 00090 // WARNING: The evaluates Timer::now, which shouldn't be done too often 00091 Time simTime() const { 00092 Time curt = simTime( Timer::now() ); 00093 00094 #if FORCE_MONOTONIC_CLOCK 00095 Time last = mLastSimTime.read(); 00096 if (curt < last) 00097 curt = last; 00098 00099 // FIXME this is to avoid const fallout since this didn't used to 00100 // need to modify data 00101 const_cast< Sirikata::AtomicValue<Time>& >(this->mLastSimTime) = curt; 00102 #endif 00103 return curt; 00104 } 00105 00106 // A low cost alternative to simTime(). Gets that last value simTime() 00107 // returned. This should be used when a Time is needed, but the cost of 00108 // calling simTime() is too high. Obviously not everybody can use this or 00109 // simTime() will never progress. 00110 Time recentSimTime() const { 00111 return this->mLastSimTime.read(); 00112 } 00113 00123 Time realTime() const { 00124 return simTime() + (mEpoch.read()-Time::null()) + Timer::getUTCOffset(); 00125 } 00126 Time recentRealTime() const { 00127 return recentSimTime() + (mEpoch.read()-Time::null()) + Timer::getUTCOffset(); 00128 } 00129 00130 void add(Service* ps) { 00131 mServices.push_back(ps); 00132 ps->start(); 00133 } 00134 00135 void remove(Service* ps) { 00136 for(ServiceList::iterator it = mServices.begin(); it != mServices.end(); it++) { 00137 if (*it == ps) { 00138 mServices.erase(it); 00139 return; 00140 } 00141 } 00142 } 00143 00144 void run(uint32 nthreads = 1, ExecutionThreads exthreads = IncludeOriginal); 00145 00146 // Stop the simulation 00147 void shutdown(); 00148 00149 bool stopped() const { return mStopRequested.read(); } 00150 00151 // Call after run returns to ensure all resources get cleaned up. 00152 void cleanup(); 00153 00154 Trace::Trace* trace() const { 00155 return mTrace; 00156 } 00157 00158 Command::Commander* commander() const { 00159 return mCommander; 00160 } 00161 void setCommander(Command::Commander* c); 00162 00163 const String name; 00164 Network::IOService* ioService; 00165 Network::IOStrand* mainStrand; 00166 TimeProfiler* profiler; 00167 00168 Trace::TimeSeries* timeSeries; 00169 protected: 00170 00171 // Main Lifetime Management 00172 virtual void start(); 00173 virtual void stop(); 00174 Network::IOTimerPtr mFinishedTimer; 00175 00176 00177 // Forced Quit Management 00178 void startForceQuitTimer(); 00179 00180 // Forces quit by stopping event processing. Should only be 00181 // invoked after waiting a sufficient period after an initial stop 00182 // request. 00183 void forceQuit() { 00184 SILOG(forcequit,fatal,"Fatal error: Quit forced by timeout."); 00185 ioService->stop(); 00186 } 00187 00188 void workerThread(); 00189 void cleanupWorkerThreads(); 00190 00191 // Signal handling 00192 void handleSignal(Signal::Type stype); 00193 00194 Trace::Trace* mTrace; 00195 Command::Commander* mCommander; 00196 00197 Sirikata::AtomicValue<Time> mEpoch; 00198 Sirikata::AtomicValue<Time> mLastSimTime; 00199 Duration mSimDuration; 00200 typedef std::vector<Service*> ServiceList; 00201 ServiceList mServices; 00202 00203 std::tr1::shared_ptr<Thread> mKillThread; 00204 Network::IOService* mKillService; 00205 Network::IOTimerPtr mKillTimer; 00206 00207 Sirikata::AtomicValue<bool> mStopRequested; 00208 00209 Signal::HandlerID mSignalHandler; 00210 00211 ExecutionThreads mExecutionThreadsType; 00212 typedef std::vector<Thread*> ThreadList; 00213 ThreadList mWorkerThreads; 00214 }; // class ObjectHostContext 00215 00216 } // namespace Sirikata 00217 00218 00219 #endif //_SIRIKATA_CONTEXT_HPP_