map-manager.cpp

Go to the documentation of this file.
00001 /*
00002  * map-manager.cpp
00003  *
00004  * Copyright (C) 2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are 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 the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  * Map management.  See map-manager.h
00031  */
00032 
00033 // includes -------------------------------------------------------------------
00034 #include "map-manager.h"                // always include our own header first!
00035 
00036 #include "common/wave_ex.h"
00037 
00038 #include "threadsafe/smart_mutex.h"
00039 #include "threadsafe/threadsafe_queue.h"
00040 
00041 
00042 namespace aesop {
00043 
00044 
00045 MapManager::~MapManager(void) throw() { }
00046 
00047 
00048 static const useconds_t s_sleepMicroseconds             = 2000; // 2ms
00049 
00050 
00051 
00053 //
00054 //      MapMgr -- object that implements the MapManager interface
00055 //
00057 
00058 class MapMgr : public MapManager {
00059 public:
00060         MapMgr(void) throw();
00061         ~MapMgr(void) throw() { }
00062 
00063         // public class methods ------------------------------------------------
00064         void initialize(IN smart_ptr<Datahash>& params,
00065                                 IN smart_ptr<story::Story>& story);
00066 
00067         // aesop::MapManager class interface methods --------------------------
00068         void clear(void);
00069         void requestLoad(IN const char * id);
00070         smart_ptr<MapDynamics> getMap(IN const char * id);
00071         void tickMaps(IN float seconds);
00072         void getIterator(OUT iterator_t& i);
00073         bool getNextMap(IO iterator_t& i,
00074                                 OUT smart_ptr<MapDynamics>& map);
00075 
00076 private:
00077         // private typedefs ----------------------------------------------------
00078         typedef std::map<std::string, smart_ptr<MapDynamics> > id_map_t;
00079 
00080         typedef threadsafe_queue<std::string> id_queue_t;
00081 
00082         struct real_iter_t {
00083                 dword_t                 rvn;
00084                 id_map_t::iterator      iter;
00085         };
00086 
00087         // private helper methods ----------------------------------------------
00088         void doThread(void);
00089         static void * threadStart(void *);
00090         static real_iter_t * getRealIterator(IN iterator_t& i) throw()
00091                 { return (real_iter_t *) &i; }
00092 
00093         // private member data -------------------------------------------------
00094         smart_mutex                     m_mutex;
00095         smart_ptr<Datahash>             m_params;
00096         smart_ptr<story::Story>         m_story;
00097         id_queue_t                      m_loadQueue;
00098         pthread_t                       m_thread;
00099         id_map_t                        m_maps;         // ID --> map
00100         dword_t                         m_rvn;
00101 };
00102 
00103 
00104 
00105 MapMgr::MapMgr(void)
00106 throw()
00107 {
00108         m_rvn = 4381;           // random
00109 }
00110 
00111 
00112 
00113 void
00114 MapMgr::initialize
00115 (
00116 IN smart_ptr<Datahash>& params,
00117 IN smart_ptr<story::Story>& story
00118 )
00119 {
00120         ASSERT(params, "null");
00121         ASSERT(story, "null");
00122 
00123         m_params = params;
00124         m_story = story;
00125 
00126         // create worker thread
00127         ASSERT(!pthread_create(&m_thread, NULL, threadStart, this),
00128             "Failed to create map manager worker thread");
00129         DPRINTF("Thread id = 0x%08lx", m_thread);
00130 }
00131 
00132 
00133 
00135 //
00136 //      MapMgr -- aesop::MapManager class interface methods
00137 //
00139 
00140 void
00141 MapMgr::clear
00142 (
00143 void
00144 )
00145 {
00146         DPRINTF("WARNING: requested to clear all map state!");
00147 
00148         // brutally easy...  entire ecosystems wiped away here...
00149         mlock l(m_mutex);
00150         ++m_rvn;
00151         m_maps.clear();
00152 }
00153 
00154 
00155 
00156 void
00157 MapMgr::requestLoad
00158 (
00159 IN const char * id
00160 )
00161 {
00162         ASSERT(id, "null");
00163         ASSERT(m_story, "null");
00164 
00165         std::string str_id = id;
00166 
00167         // threadsafe!  push request onto threadsafe queue...
00168         m_loadQueue.push_back(str_id);
00169 }
00170 
00171 
00172 
00173 smart_ptr<MapDynamics>
00174 MapMgr::getMap
00175 (
00176 IN const char * id
00177 )
00178 {
00179         ASSERT(id, "null");
00180 
00181         // threadsafe!
00182         mlock l(m_mutex);
00183 
00184         // do we have this map?
00185         id_map_t::iterator i = m_maps.find(id);
00186         if (m_maps.end() == i) {
00187                 DPRINTF("No such map!");
00188                 return NULL;
00189         }
00190         ASSERT(i->second, "null");
00191 
00192         return i->second;
00193 }
00194 
00195 
00196 
00197 void
00198 MapMgr::tickMaps
00199 (
00200 IN float seconds
00201 )
00202 {
00203         ASSERT(seconds > 0, "Bad seconds: %f", seconds);
00204 
00205         // lock!
00206         mlock l(m_mutex);
00207 
00208         // iterate over all maps and tick
00209         for (id_map_t::iterator i = m_maps.begin(); i != m_maps.end(); ++i) {
00210                 MapDynamics * md = i->second;
00211                 ASSERT(md, "null");
00212 
00213                 md->tickMap(seconds);
00214         }
00215 }
00216 
00217 
00218 
00219 void
00220 MapMgr::getIterator
00221 (
00222 OUT iterator_t& i
00223 )
00224 {
00225         real_iter_t * ri = getRealIterator(i);
00226 
00227         // lock!
00228         mlock l(m_mutex);
00229         ri->rvn = m_rvn;
00230         ri->iter = m_maps.begin();
00231 }
00232 
00233 
00234 
00235 bool
00236 MapMgr::getNextMap
00237 (
00238 IO iterator_t& i,
00239 OUT smart_ptr<MapDynamics>& map
00240 )
00241 {
00242         map = NULL;
00243         real_iter_t * ri = getRealIterator(i);
00244 
00245         // lock!
00246         mlock l(m_mutex);
00247 
00248         if (m_rvn != ri->rvn)
00249                 return false;   // something has changed
00250 
00251         if (m_maps.end() == ri->iter)
00252                 return false;   // at end of iteration
00253 
00254         // have a valid iterator!
00255         map = ri->iter->second;
00256         ASSERT(map, "null dynamics object?");
00257         ++ri->iter;
00258         return true;
00259 }
00260 
00261 
00262 
00264 //
00265 //      MapMgr -- private helper methods
00266 //
00268 
00269 void
00270 MapMgr::doThread
00271 (
00272 void
00273 )
00274 {
00275         // infinite loop, waiting for work!
00276         for (;;) {
00277                 usleep(s_sleepMicroseconds);
00278 
00279                 // anything to do?
00280                 std::string id;
00281                 if (!m_loadQueue.pop_front(id))
00282                         continue;       // nope
00283 
00284                 // okay, have an ID to load! 
00285                 // quick lock to check some data points
00286                 std::string path;
00287                 {
00288                         mlock l(m_mutex);
00289                         if (m_maps.end() != m_maps.find(id)) {
00290                                 // already loaded!
00291                                 continue;
00292                         }
00293 
00294                         // not yet loaded
00295                         path = m_story->getObjectPath("map", id.c_str());
00296                 }
00297 
00298                 // load here, on thread, outside mutex
00299                 DPRINTF("******* Loading map: %s", id.c_str());
00300                 smart_ptr<Map> map = loadMap(id.c_str(), path.c_str());
00301                 ASSERT(map, "null");
00302 
00303                 smart_ptr<MapDynamics> dyn = MapDynamics::create(map, m_params);
00304                 ASSERT(dyn, "null");
00305 
00306                 // okay!  add to our map
00307                 {
00308                         mlock l(m_mutex);
00309                         ++m_rvn;
00310                         m_maps[id] = dyn;
00311                 }
00312         }
00313 }
00314 
00315 
00316 
00317 void *
00318 MapMgr::threadStart
00319 (
00320 IN void * ctx
00321 )
00322 {
00323         MapMgr * pThis = (MapMgr *) ctx;
00324         for (;;) {
00325                 try {
00326                         pThis->doThread();
00327                 } catch (std::exception& e) {
00328                         DPRINTF("Exception from MapMgr worker thread:\n  %s",
00329                             e.what());
00330                 }
00331         }
00332         return NULL;
00333 }
00334 
00335 
00336 
00338 //
00339 //      public API
00340 //
00342 
00343 smart_ptr<MapManager>
00344 MapManager::create
00345 (
00346 IN smart_ptr<Datahash>& params,
00347 IN smart_ptr<story::Story>& story
00348 )
00349 {
00350         ASSERT(params, "null");
00351         ASSERT(story, "null");
00352 
00353         smart_ptr<MapMgr> local = new MapMgr;
00354         ASSERT(local, "out of memory");
00355 
00356         local->initialize(params, story);
00357 
00358         return local;
00359 }
00360 
00361 
00362 
00363 };      // aesop namespace
00364