linkgraphschedule.cpp

Go to the documentation of this file.
00001 /* $Id: linkgraphschedule.cpp 26276 2014-01-24 21:39:07Z 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   LinkGraph *first = next;
00061   while (next->Size() < 2) {
00062     this->schedule.splice(this->schedule.end(), this->schedule, this->schedule.begin());
00063     next = this->schedule.front();
00064     if (next == first) return;
00065   }
00066   assert(next == LinkGraph::Get(next->index));
00067   this->schedule.pop_front();
00068   if (LinkGraphJob::CanAllocateItem()) {
00069     LinkGraphJob *job = new LinkGraphJob(*next);
00070     this->SpawnThread(job);
00071     this->running.push_back(job);
00072   } else {
00073     NOT_REACHED();
00074   }
00075 }
00076 
00080 void LinkGraphSchedule::JoinNext()
00081 {
00082   if (this->running.empty()) return;
00083   LinkGraphJob *next = this->running.front();
00084   if (!next->IsFinished()) return;
00085   this->running.pop_front();
00086   LinkGraphID id = next->LinkGraphIndex();
00087   this->JoinThread(next);
00088   delete next;
00089   if (LinkGraph::IsValidID(id)) {
00090     LinkGraph *lg = LinkGraph::Get(id);
00091     this->Unqueue(lg); // Unqueue to avoid double-queueing recycled IDs.
00092     this->Queue(lg);
00093   }
00094 }
00095 
00101 /* static */ void LinkGraphSchedule::Run(void *j)
00102 {
00103   LinkGraphJob *job = (LinkGraphJob *)j;
00104   LinkGraphSchedule *schedule = LinkGraphSchedule::Instance();
00105   for (uint i = 0; i < lengthof(schedule->handlers); ++i) {
00106     schedule->handlers[i]->Run(*job);
00107   }
00108 }
00109 
00114 void LinkGraphSchedule::SpawnAll()
00115 {
00116   for (JobList::iterator i = this->running.begin(); i != this->running.end(); ++i) {
00117     this->SpawnThread(*i);
00118   }
00119 }
00120 
00124 /* static */ void LinkGraphSchedule::Clear()
00125 {
00126   LinkGraphSchedule *inst = LinkGraphSchedule::Instance();
00127   for (JobList::iterator i(inst->running.begin()); i != inst->running.end(); ++i) {
00128     inst->JoinThread(*i);
00129   }
00130   inst->running.clear();
00131   inst->schedule.clear();
00132 }
00133 
00139 void LinkGraphSchedule::ShiftDates(int interval)
00140 {
00141   LinkGraph *lg;
00142   FOR_ALL_LINK_GRAPHS(lg) lg->ShiftDates(interval);
00143   LinkGraphJob *lgj;
00144   FOR_ALL_LINK_GRAPH_JOBS(lgj) lgj->ShiftJoinDate(interval);
00145 }
00146 
00150 LinkGraphSchedule::LinkGraphSchedule()
00151 {
00152   this->handlers[0] = new InitHandler;
00153   this->handlers[1] = new DemandHandler;
00154   this->handlers[2] = new MCFHandler<MCF1stPass>;
00155   this->handlers[3] = new FlowMapper(false);
00156   this->handlers[4] = new MCFHandler<MCF2ndPass>;
00157   this->handlers[5] = new FlowMapper(true);
00158 }
00159 
00163 LinkGraphSchedule::~LinkGraphSchedule()
00164 {
00165   this->Clear();
00166   for (uint i = 0; i < lengthof(this->handlers); ++i) {
00167     delete this->handlers[i];
00168   }
00169 }
00170 
00174 /* static */ LinkGraphSchedule *LinkGraphSchedule::Instance()
00175 {
00176   static LinkGraphSchedule inst;
00177   return &inst;
00178 }
00179 
00184 void OnTick_LinkGraph()
00185 {
00186   if (_date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return;
00187   Date offset = _date % _settings_game.linkgraph.recalc_interval;
00188   if (offset == 0) {
00189     LinkGraphSchedule::Instance()->SpawnNext();
00190   } else if (offset == _settings_game.linkgraph.recalc_interval / 2) {
00191     LinkGraphSchedule::Instance()->JoinNext();
00192   }
00193 }
00194 
00195