Sirikata
libcore/include/sirikata/core/service/Context.hpp
Go to the documentation of this file.
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_