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