linkgraphschedule.cpp

Go to the documentation of this file.
00001 /* $Id: linkgraphschedule.cpp 26347 2014-02-16 18:42:59Z 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 
00022 void LinkGraphSchedule::SpawnNext()
00023 {
00024   if (this->schedule.empty()) return;
00025   LinkGraph *next = this->schedule.front();
00026   LinkGraph *first = next;
00027   while (next->Size() < 2) {
00028     this->schedule.splice(this->schedule.end(), this->schedule, this->schedule.begin());
00029     next = this->schedule.front();
00030     if (next == first) return;
00031   }
00032   assert(next == LinkGraph::Get(next->index));
00033   this->schedule.pop_front();
00034   if (LinkGraphJob::CanAllocateItem()) {
00035     LinkGraphJob *job = new LinkGraphJob(*next);
00036     job->SpawnThread();
00037     this->running.push_back(job);
00038   } else {
00039     NOT_REACHED();
00040   }
00041 }
00042 
00046 void LinkGraphSchedule::JoinNext()
00047 {
00048   if (this->running.empty()) return;
00049   LinkGraphJob *next = this->running.front();
00050   if (!next->IsFinished()) return;
00051   this->running.pop_front();
00052   LinkGraphID id = next->LinkGraphIndex();
00053   delete next; // implicitly joins the thread
00054   if (LinkGraph::IsValidID(id)) {
00055     LinkGraph *lg = LinkGraph::Get(id);
00056     this->Unqueue(lg); // Unqueue to avoid double-queueing recycled IDs.
00057     this->Queue(lg);
00058   }
00059 }
00060 
00066 /* static */ void LinkGraphSchedule::Run(void *j)
00067 {
00068   LinkGraphJob *job = (LinkGraphJob *)j;
00069   LinkGraphSchedule *schedule = LinkGraphSchedule::Instance();
00070   for (uint i = 0; i < lengthof(schedule->handlers); ++i) {
00071     schedule->handlers[i]->Run(*job);
00072   }
00073 }
00074 
00079 void LinkGraphSchedule::SpawnAll()
00080 {
00081   for (JobList::iterator i = this->running.begin(); i != this->running.end(); ++i) {
00082     (*i)->SpawnThread();
00083   }
00084 }
00085 
00089 /* static */ void LinkGraphSchedule::Clear()
00090 {
00091   LinkGraphSchedule *inst = LinkGraphSchedule::Instance();
00092   for (JobList::iterator i(inst->running.begin()); i != inst->running.end(); ++i) {
00093     (*i)->JoinThread();
00094   }
00095   inst->running.clear();
00096   inst->schedule.clear();
00097 }
00098 
00104 void LinkGraphSchedule::ShiftDates(int interval)
00105 {
00106   LinkGraph *lg;
00107   FOR_ALL_LINK_GRAPHS(lg) lg->ShiftDates(interval);
00108   LinkGraphJob *lgj;
00109   FOR_ALL_LINK_GRAPH_JOBS(lgj) lgj->ShiftJoinDate(interval);
00110 }
00111 
00115 LinkGraphSchedule::LinkGraphSchedule()
00116 {
00117   this->handlers[0] = new InitHandler;
00118   this->handlers[1] = new DemandHandler;
00119   this->handlers[2] = new MCFHandler<MCF1stPass>;
00120   this->handlers[3] = new FlowMapper(false);
00121   this->handlers[4] = new MCFHandler<MCF2ndPass>;
00122   this->handlers[5] = new FlowMapper(true);
00123 }
00124 
00128 LinkGraphSchedule::~LinkGraphSchedule()
00129 {
00130   this->Clear();
00131   for (uint i = 0; i < lengthof(this->handlers); ++i) {
00132     delete this->handlers[i];
00133   }
00134 }
00135 
00139 /* static */ LinkGraphSchedule *LinkGraphSchedule::Instance()
00140 {
00141   static LinkGraphSchedule inst;
00142   return &inst;
00143 }
00144 
00149 void OnTick_LinkGraph()
00150 {
00151   if (_date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return;
00152   Date offset = _date % _settings_game.linkgraph.recalc_interval;
00153   if (offset == 0) {
00154     LinkGraphSchedule::Instance()->SpawnNext();
00155   } else if (offset == _settings_game.linkgraph.recalc_interval / 2) {
00156     LinkGraphSchedule::Instance()->JoinNext();
00157   }
00158 }
00159 
00160