linkgraphschedule.cpp

Go to the documentation of this file.
00001 /* $Id: linkgraphschedule.cpp 26166 2013-12-20 14:57:44Z fonsinchen $ */
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 
00133 void LinkGraphSchedule::ShiftDates(int interval)
00134 {
00135   LinkGraph *lg;
00136   FOR_ALL_LINK_GRAPHS(lg) lg->ShiftDates(interval);
00137   LinkGraphJob *lgj;
00138   FOR_ALL_LINK_GRAPH_JOBS(lgj) lgj->ShiftJoinDate(interval);
00139 }
00140 
00144 LinkGraphSchedule::LinkGraphSchedule()
00145 {
00146   this->handlers[0] = new InitHandler;
00147   this->handlers[1] = new DemandHandler;
00148   this->handlers[2] = new MCFHandler<MCF1stPass>;
00149   this->handlers[3] = new FlowMapper(false);
00150   this->handlers[4] = new MCFHandler<MCF2ndPass>;
00151   this->handlers[5] = new FlowMapper(true);
00152 }
00153 
00157 LinkGraphSchedule::~LinkGraphSchedule()
00158 {
00159   this->Clear();
00160   for (uint i = 0; i < lengthof(this->handlers); ++i) {
00161     delete this->handlers[i];
00162   }
00163 }
00164 
00168 /* static */ LinkGraphSchedule *LinkGraphSchedule::Instance()
00169 {
00170   static LinkGraphSchedule inst;
00171   return &inst;
00172 }
00173 
00178 void OnTick_LinkGraph()
00179 {
00180   if (_date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return;
00181   Date offset = _date % _settings_game.linkgraph.recalc_interval;
00182   if (offset == 0) {
00183     LinkGraphSchedule::Instance()->SpawnNext();
00184   } else if (offset == _settings_game.linkgraph.recalc_interval / 2) {
00185     LinkGraphSchedule::Instance()->JoinNext();
00186   }
00187 }
00188 
00189