4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file linkgraphschedule.cpp Definition of link graph schedule used for cargo distribution. */
12 #include "../stdafx.h"
13 #include "linkgraphschedule.h"
17 #include "flowmapper.h"
19 #include "../safeguards.h"
22 * Static instance of LinkGraphSchedule.
23 * Note: This instance is created on task start.
24 * Lazy creation on first usage results in a data race between the CDist threads.
26 /* static */ LinkGraphSchedule
LinkGraphSchedule::instance
;
29 * Start the next job in the schedule.
31 void LinkGraphSchedule::SpawnNext()
33 if (this->schedule
.empty()) return;
34 LinkGraph
*next
= this->schedule
.front();
35 LinkGraph
*first
= next
;
36 while (next
->Size() < 2) {
37 this->schedule
.splice(this->schedule
.end(), this->schedule
, this->schedule
.begin());
38 next
= this->schedule
.front();
39 if (next
== first
) return;
41 assert(next
== LinkGraph::Get(next
->index
));
42 this->schedule
.pop_front();
43 if (LinkGraphJob::CanAllocateItem()) {
44 LinkGraphJob
*job
= new LinkGraphJob(*next
);
46 this->running
.push_back(job
);
53 * Join the next finished job, if available.
55 void LinkGraphSchedule::JoinNext()
57 if (this->running
.empty()) return;
58 LinkGraphJob
*next
= this->running
.front();
59 if (!next
->IsFinished()) return;
60 this->running
.pop_front();
61 LinkGraphID id
= next
->LinkGraphIndex();
62 delete next
; // implicitly joins the thread
63 if (LinkGraph::IsValidID(id
)) {
64 LinkGraph
*lg
= LinkGraph::Get(id
);
65 this->Unqueue(lg
); // Unqueue to avoid double-queueing recycled IDs.
71 * Run all handlers for the given Job. This method is tailored to
73 * @param j Pointer to a link graph job.
75 /* static */ void LinkGraphSchedule::Run(void *j
)
77 LinkGraphJob
*job
= (LinkGraphJob
*)j
;
78 for (uint i
= 0; i
< lengthof(instance
.handlers
); ++i
) {
79 instance
.handlers
[i
]->Run(*job
);
84 * Start all threads in the running list. This is only useful for save/load.
85 * Usually threads are started when the job is created.
87 void LinkGraphSchedule::SpawnAll()
89 for (JobList::iterator i
= this->running
.begin(); i
!= this->running
.end(); ++i
) {
95 * Clear all link graphs and jobs from the schedule.
97 /* static */ void LinkGraphSchedule::Clear()
99 for (JobList::iterator
i(instance
.running
.begin()); i
!= instance
.running
.end(); ++i
) {
102 instance
.running
.clear();
103 instance
.schedule
.clear();
107 * Shift all dates (join dates and edge annotations) of link graphs and link
108 * graph jobs by the number of days given.
109 * @param interval Number of days to be added or subtracted.
111 void LinkGraphSchedule::ShiftDates(int interval
)
114 FOR_ALL_LINK_GRAPHS(lg
) lg
->ShiftDates(interval
);
116 FOR_ALL_LINK_GRAPH_JOBS(lgj
) lgj
->ShiftJoinDate(interval
);
120 * Create a link graph schedule and initialize its handlers.
122 LinkGraphSchedule::LinkGraphSchedule()
124 this->handlers
[0] = new InitHandler
;
125 this->handlers
[1] = new DemandHandler
;
126 this->handlers
[2] = new MCFHandler
<MCF1stPass
>;
127 this->handlers
[3] = new FlowMapper(false);
128 this->handlers
[4] = new MCFHandler
<MCF2ndPass
>;
129 this->handlers
[5] = new FlowMapper(true);
133 * Delete a link graph schedule and its handlers.
135 LinkGraphSchedule::~LinkGraphSchedule()
138 for (uint i
= 0; i
< lengthof(this->handlers
); ++i
) {
139 delete this->handlers
[i
];
144 * Spawn or join a link graph job or compress a link graph if any link graph is
147 void OnTick_LinkGraph()
149 if (_date_fract
!= LinkGraphSchedule::SPAWN_JOIN_TICK
) return;
150 Date offset
= _date
% _settings_game
.linkgraph
.recalc_interval
;
152 LinkGraphSchedule::instance
.SpawnNext();
153 } else if (offset
== _settings_game
.linkgraph
.recalc_interval
/ 2) {
154 LinkGraphSchedule::instance
.JoinNext();