# 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