00001 #ifndef GCACHE_CONTROLLER_H 00002 #define GCACHE_CONTROLLER_H 00003 00004 #include "cache.h" 00005 00008 namespace vcg { 00009 00010 template <class Token> 00011 class Controller { 00012 public: 00014 std::vector<Token *> tokens; 00017 bool paused; 00019 bool stopped; 00020 00021 public: 00023 Provider<Token> provider; 00025 std::vector<Cache<Token> *> caches; 00026 00027 Controller(): paused(false), stopped(true) {} 00028 ~Controller() { if(!stopped) finish(); } 00029 00031 00032 void addCache(Cache<Token> *cache) { 00033 if(caches.size() == 0) 00034 cache->setInputCache(&provider); 00035 else 00036 cache->setInputCache(caches.back()); 00037 assert(cache->input); 00038 caches.push_back(cache); 00039 } 00040 00042 bool addToken(Token *token) { 00043 if(token->count.testAndSetOrdered(Token::OUTSIDE, Token::CACHE)) { 00044 tokens.push_back(token); 00045 return true; 00046 } 00047 return false; 00048 } 00049 00051 //FUNCTOR has bool operator(Token *) and return true to remove 00052 template<class FUNCTOR> void removeTokens(FUNCTOR functor) { 00053 pause(); //this might actually be unnecessary if you mark tokens to be removed 00054 for(int i = (int)caches.size()-1; i >= 0; i--) 00055 caches[i]->flush(functor); 00056 provider.flush(functor); 00057 00058 resume(); 00059 } 00060 00062 void setMaxTokens(int m) { 00063 mt::mutexlocker l(&provider.heap_lock); 00064 provider.max_tokens = m; 00065 } 00066 00069 void updatePriorities() { 00070 if(tokens.size()) { 00071 mt::mutexlocker l(&provider.heap_lock); 00072 for(unsigned int i = 0; i < tokens.size(); i++) 00073 provider.heap.push(tokens[i]); 00074 tokens.clear(); 00075 } 00076 00077 provider.pushPriorities(); 00078 for(unsigned int i = 0; i < caches.size(); i++) 00079 caches[i]->pushPriorities(); 00080 } 00081 00083 void start() { 00084 assert(stopped); 00085 assert(!paused); 00086 assert(caches.size() > 1); 00087 caches.back()->final = true; 00088 for(unsigned int i = 0; i < caches.size(); i++) //cache 0 is a provider, and his thread is not running. 00089 caches[i]->start(); 00090 stopped = false; 00091 } 00092 00094 void stop() { 00095 if(stopped) return; 00096 assert(!paused); 00097 00098 //signal al caches to quit 00099 for(unsigned int i = 0; i < caches.size(); i++) 00100 caches[i]->quit = true; 00101 00102 //abort current gets 00103 for(unsigned int i = 0; i < caches.size(); i++) 00104 caches[i]->abort(); 00105 00106 //make sure all caches actually run a cycle. 00107 for(unsigned int i = 0; i < caches.size(); i++) 00108 caches[i]->input->check_queue.open(); 00109 00110 for(unsigned int i = 0; i < caches.size(); i++) 00111 caches[i]->wait(); 00112 00113 stopped = true; 00114 } 00115 00116 void finish() { 00117 stop(); 00118 flush(); 00119 } 00120 00121 void pause() { 00122 assert(!stopped); 00123 assert(!paused); 00124 00125 //lock all doors. 00126 for(unsigned int i = 0; i < caches.size(); i++) 00127 caches[i]->input->check_queue.lock(); 00128 00129 //abort all pending calls 00130 for(unsigned int i = 0; i < caches.size(); i++) 00131 caches[i]->abort(); 00132 00133 //make sure no cache is running (must be done after abort! otherwise we have to wait for the get) 00134 for(unsigned int i = 0; i < caches.size()-1; i++) 00135 caches[i]->input->check_queue.room.lock(); 00136 00137 paused = true; 00138 } 00139 00140 void resume() { 00141 assert(!stopped); 00142 assert(paused); 00143 cout << "Resume" << endl; 00144 00145 //unlock and open all doors 00146 for(unsigned int i = 0; i < caches.size(); i++) { 00147 caches[i]->input->check_queue.unlock(); 00148 caches[i]->input->check_queue.open(); 00149 } 00150 00151 //allow all cache to enter again. 00152 for(unsigned int i = 0; i < caches.size()-1; i++) 00153 caches[i]->input->check_queue.room.unlock(); 00154 00155 paused = false; 00156 } 00158 void flush() { 00159 for(int i = (int)caches.size()-1; i >= 0; i--) 00160 caches[i]->flush(); 00161 provider.heap.clear(); 00162 } 00163 00164 bool newData() { 00165 bool c = false; 00166 for(int i = (int)caches.size() -1; i >= 0; i--) { 00167 c |= caches[i]->newData(); 00168 } 00169 return c; 00170 } 00171 00172 bool isWaiting() { 00173 bool waiting = true; 00174 for(int i = (int)caches.size() -1; i >= 0; i--) { 00175 waiting &= caches[i]->input->check_queue.isWaiting(); 00176 } 00177 return waiting; 00178 } 00179 }; 00180 00181 } //namespace 00182 #endif // CONTROLLER_H