linkgraphschedule.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "../stdafx.h"
00013 #include "linkgraphschedule.h"
00014 #include "init.h"
00015 #include "demands.h"
00016 #include "mcf.h"
00017 #include "flowmapper.h"
00018 
00024 void LinkGraphSchedule::SpawnThread(LinkGraphJob *job)
00025 {
00026   if (!ThreadObject::New(&(LinkGraphSchedule::Run), job, &job->thread)) {
00027     job->thread = NULL;
00028     /* Of course this will hang a bit.
00029      * On the other hand, if you want to play games which make this hang noticably
00030      * on a platform without threads then you'll probably get other problems first.
00031      * OK:
00032      * If someone comes and tells me that this hangs for him/her, I'll implement a
00033      * smaller grained "Step" method for all handlers and add some more ticks where
00034      * "Step" is called. No problem in principle.
00035      */
00036     LinkGraphSchedule::Run(job);
00037   }
00038 }
00039 
00044 void LinkGraphSchedule::JoinThread(LinkGraphJob *job)
00045 {
00046   if (job->thread != NULL) {
00047     job->thread->Join();
00048     delete job->thread;
00049     job->thread = NULL;
00050   }
00051 }
00052 
00056 void LinkGraphSchedule::SpawnNext()
00057 {
00058   if (this->schedule.empty()) return;
00059   LinkGraph *next = this->schedule.front();
00060   assert(next == LinkGraph::Get(next->index));
00061   this->schedule.pop_front();
00062   if (LinkGraphJob::CanAllocateItem()) {
00063     LinkGraphJob *job = new LinkGraphJob(*next);
00064     this->SpawnThread(job);
00065     this->running.push_back(job);
00066   } else {
00067     NOT_REACHED();
00068   }
00069 }
00070 
00074 void LinkGraphSchedule::JoinNext()
00075 {
00076   if (this->running.empty()) return;
00077   LinkGraphJob *next = this->running.front();
00078   if (!next->IsFinished()) return;
00079   this->running.pop_front();
00080   LinkGraphID id = next->LinkGraphIndex();
00081   this->JoinThread(next);
00082   delete next;
00083   if (LinkGraph::IsValidID(id)) {
00084     LinkGraph *lg = LinkGraph::Get(id);
00085     this->Unqueue(lg); // Unqueue to avoid double-queueing recycled IDs.
00086     this->Queue(lg);
00087   }
00088 }
00089 
00095 /* static */ void LinkGraphSchedule::Run(void *j)
00096 {
00097   LinkGraphJob *job = (LinkGraphJob *)j;
00098   LinkGraphSchedule *schedule = LinkGraphSchedule::Instance();
00099   for (uint i = 0; i < lengthof(schedule->handlers); ++i) {
00100     schedule->handlers[i]->Run(*job);
00101   }
00102 }
00103 
00108 void LinkGraphSchedule::SpawnAll()
00109 {
00110   for (JobList::iterator i = this->running.begin(); i != this->running.end(); ++i) {
00111     this->SpawnThread(*i);
00112   }
00113 }
00114 
00118 /* static */ void LinkGraphSchedule::Clear()
00119 {
00120   LinkGraphSchedule *inst = LinkGraphSchedule::Instance();
00121   for (JobList::iterator i(inst->running.begin()); i != inst->running.end(); ++i) {
00122     inst->JoinThread(*i);
00123   }
00124   inst->running.clear();
00125   inst->schedule.clear();
00126 }
00127 
00131 LinkGraphSchedule::LinkGraphSchedule()
00132 {
00133   this->handlers[0] = new InitHandler;
00134   this->handlers[1] = new DemandHandler;
00135   this->handlers[2] = new MCFHandler<MCF1stPass>;
00136   this->handlers[3] = new FlowMapper;
00137   this->handlers[4] = new MCFHandler<MCF2ndPass>;
00138   this->handlers[5] = new FlowMapper;
00139 }
00140 
00144 LinkGraphSchedule::~LinkGraphSchedule()
00145 {
00146   this->Clear();
00147   for (uint i = 0; i < lengthof(this->handlers); ++i) {
00148     delete this->handlers[i];
00149   }
00150 }
00151 
00155 /* static */ LinkGraphSchedule *LinkGraphSchedule::Instance()
00156 {
00157   static LinkGraphSchedule inst;
00158   return &inst;
00159 }
00160 
00165 void OnTick_LinkGraph()
00166 {
00167   if (_date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK) {
00168     Date offset = _date % _settings_game.linkgraph.recalc_interval;
00169     if (offset == 0) {
00170       LinkGraphSchedule::Instance()->SpawnNext();
00171     } else if (offset == _settings_game.linkgraph.recalc_interval / 2) {
00172       LinkGraphSchedule::Instance()->JoinNext();
00173     }
00174   } else if (_date_fract == LinkGraph::COMPRESSION_TICK) {
00175     LinkGraph *lg;
00176     /* Compress graphs after 256 to 512 days; approximately once a year. */
00177     int cutoff = RandomRange(256) + 256;
00178     FOR_ALL_LINK_GRAPHS(lg) {
00179       if (_date - lg->LastCompression() > cutoff) lg->Compress();
00180     }
00181   }
00182 }
00183 
00184