Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file GUIRunThread.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Sept 2002
19 : ///
20 : // The thread that runs the simulation
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <cassert>
25 : #include <string>
26 : #include <iostream>
27 : #include <algorithm>
28 :
29 : #include <guisim/GUINet.h>
30 : #include <utils/gui/events/GUIEvent_Message.h>
31 : #include <utils/gui/events/GUIEvent_SimulationStep.h>
32 : #include "GUIEvent_SimulationEnded.h"
33 : #include "GUIApplicationWindow.h"
34 : #include "GUIRunThread.h"
35 : #include "GUIGlobals.h"
36 : #include <microsim/MSVehicleControl.h>
37 : #include <utils/options/OptionsCont.h>
38 : #include <utils/options/OptionsIO.h>
39 : #include <utils/common/SysUtils.h>
40 : #include <utils/common/MsgRetrievingFunction.h>
41 : #include <utils/common/MsgHandler.h>
42 : #include <utils/common/UtilExceptions.h>
43 : #include <utils/iodevices/OutputDevice.h>
44 : #include <traci-server/TraCIServer.h>
45 : #include <libsumo/Simulation.h>
46 :
47 :
48 : // ===========================================================================
49 : // member method definitions
50 : // ===========================================================================
51 8523 : GUIRunThread::GUIRunThread(FXApp* app, MFXInterThreadEventClient* parent, double& simDelay,
52 8523 : MFXSynchQue<GUIEvent*>& eq, FXEX::MFXThreadEvent& ev) :
53 : MFXSingleEventThread(app, parent),
54 8523 : myNet(nullptr),
55 8523 : myHalting(true),
56 8523 : myQuit(false),
57 8523 : mySimulationInProgress(false),
58 8523 : myOk(true),
59 8523 : myHaveSignaledEnd(false),
60 8523 : mySimDelay(simDelay),
61 8523 : myEventQue(eq),
62 8523 : myEventThrow(ev),
63 8523 : myLastEndMillis(-1),
64 8523 : myLastBreakMillis(0),
65 8523 : myAmLibsumo(false) {
66 8523 : myErrorRetriever = new MsgRetrievingFunction<GUIRunThread>(this, &GUIRunThread::retrieveMessage, MsgHandler::MsgType::MT_ERROR);
67 8523 : myMessageRetriever = new MsgRetrievingFunction<GUIRunThread>(this, &GUIRunThread::retrieveMessage, MsgHandler::MsgType::MT_MESSAGE);
68 8523 : myWarningRetriever = new MsgRetrievingFunction<GUIRunThread>(this, &GUIRunThread::retrieveMessage, MsgHandler::MsgType::MT_WARNING);
69 8523 : }
70 :
71 :
72 17002 : GUIRunThread::~GUIRunThread() {
73 : // the thread shall stop
74 8501 : myQuit = true;
75 8501 : deleteSim();
76 8501 : delete myErrorRetriever;
77 8501 : delete myMessageRetriever;
78 8501 : delete myWarningRetriever;
79 : // wait for the thread
80 8501 : while (mySimulationInProgress || myNet != nullptr);
81 17002 : }
82 :
83 :
84 : bool
85 8218 : GUIRunThread::init(GUINet* net, SUMOTime start, SUMOTime end) {
86 : assert(net != 0);
87 : // assign new values
88 8218 : myOk = true;
89 8218 : myNet = net;
90 8218 : mySimStartTime = start;
91 8218 : mySimEndTime = end;
92 8218 : myHaveSignaledEnd = false;
93 : // register message callbacks
94 8218 : MsgHandler::getErrorInstance()->addRetriever(myErrorRetriever);
95 8218 : MsgHandler::getMessageInstance()->addRetriever(myMessageRetriever);
96 16436 : if (!OptionsCont::getOptions().getBool("no-warnings")) {
97 8218 : MsgHandler::getWarningInstance()->addRetriever(myWarningRetriever);
98 : }
99 : // preload the routes especially for TraCI
100 8218 : mySimulationLock.lock();
101 : try {
102 : net->setCurrentTimeStep(start);
103 8218 : net->loadRoutes();
104 171 : } catch (ProcessError& e2) {
105 493 : if (std::string(e2.what()) != std::string("Process Error") && std::string(e2.what()) != std::string("")) {
106 304 : WRITE_ERROR(e2.what());
107 : }
108 171 : MsgHandler::getErrorInstance()->inform(TL("Quitting (on error)."), false);
109 171 : myHalting = true;
110 171 : myOk = false;
111 171 : mySimulationInProgress = false;
112 : #ifndef _DEBUG
113 171 : } catch (...) {
114 0 : MsgHandler::getErrorInstance()->inform(TL("Quitting (on error)."), false);
115 0 : myHalting = true;
116 0 : myOk = false;
117 0 : mySimulationInProgress = false;
118 : #endif
119 0 : }
120 8218 : mySimulationLock.unlock();
121 8218 : return myOk;
122 : }
123 :
124 :
125 : FXint
126 8523 : GUIRunThread::run() {
127 : // perform an endless loop
128 9535358 : while (!myQuit) {
129 9526857 : if (myAmLibsumo) {
130 538 : myApp->run();
131 : } else {
132 : // if the simulation shall be performed, do it
133 9526319 : tryStep();
134 : }
135 : }
136 : // delete a maybe existing simulation at the end
137 8501 : deleteSim();
138 8501 : return 0;
139 : }
140 :
141 :
142 : void
143 9614284 : GUIRunThread::tryStep() {
144 9614284 : if (!myHalting && myNet != nullptr && myOk) {
145 9541296 : const long beg = SysUtils::getCurrentMillis();
146 9541296 : if (myLastEndMillis != -1) {
147 9533308 : getNet().setIdleDuration((int)(beg - myLastEndMillis));
148 : }
149 : // check whether we shall stop at this step
150 9541296 : myBreakpointLock.lock();
151 9541296 : const bool haltAfter = std::find(myBreakpoints.begin(), myBreakpoints.end(), myNet->getCurrentTimeStep()) != myBreakpoints.end();
152 9541296 : myBreakpointLock.unlock();
153 : // stop after this step if wished
154 9541296 : if (haltAfter) {
155 0 : stop();
156 : }
157 : // stop the execution when only a single step should have been performed
158 9541296 : if (mySingle) {
159 0 : myHalting = true;
160 : }
161 : // do the step
162 9541296 : makeStep();
163 9541296 : waitForSnapshots(myNet->getCurrentTimeStep() - DELTA_T);
164 : // wait if wanted (delay is per simulated second)
165 9541296 : long wait = (long)(mySimDelay * TS);
166 9541296 : myLastEndMillis = SysUtils::getCurrentMillis();
167 9541296 : getNet().setSimDuration((int)(myLastEndMillis - beg));
168 9541296 : wait -= (myLastEndMillis - beg);
169 9541296 : if (wait > 0) {
170 5623 : myLastBreakMillis = myLastEndMillis;
171 5623 : sleep(wait);
172 : #ifndef WIN32
173 9535673 : } else if (myLastEndMillis - myLastBreakMillis > 1000) {
174 : // ensure redraw event is successful at least once per second (#9028)
175 12981 : sleep(100);
176 12981 : myLastBreakMillis = myLastEndMillis;
177 : #endif
178 : }
179 : } else {
180 : // sleep if the simulation is not running
181 72988 : sleep(50);
182 : }
183 9614284 : }
184 :
185 :
186 : void
187 9541296 : GUIRunThread::makeStep() {
188 : GUIEvent* e = nullptr;
189 : // simulation is being performed
190 9541296 : mySimulationInProgress = true;
191 : // execute a single step
192 : try {
193 9541296 : mySimulationLock.lock();
194 9541296 : myNet->simulationStep();
195 9541174 : myNet->guiSimulationStep();
196 9541174 : mySimulationLock.unlock();
197 :
198 : // inform parent that a step has been performed
199 9541174 : e = new GUIEvent_SimulationStep();
200 9541174 : myEventQue.push_back(e);
201 9541174 : myEventThrow.signal();
202 :
203 : e = nullptr;
204 9541174 : MSNet::SimulationState state = myNet->adaptToState(myNet->simulationState(mySimEndTime), myAmLibsumo);
205 9541174 : switch (state) {
206 7387 : case MSNet::SIMSTATE_LOADING:
207 : case MSNet::SIMSTATE_END_STEP_REACHED:
208 : case MSNet::SIMSTATE_NO_FURTHER_VEHICLES:
209 : case MSNet::SIMSTATE_CONNECTION_CLOSED:
210 : case MSNet::SIMSTATE_TOO_MANY_TELEPORTS:
211 7387 : if (!myHaveSignaledEnd || state != MSNet::SIMSTATE_END_STEP_REACHED) {
212 7387 : e = new GUIEvent_SimulationEnded(state, myNet->getCurrentTimeStep() - DELTA_T);
213 : // ensure that files are closed (deleteSim is called a bit later by the gui thread)
214 : // MSNet destructor may trigger MsgHandler (via routing device cleanup). Closing output devices here is not safe
215 : // OutputDevice::closeAll();
216 7387 : myHaveSignaledEnd = true;
217 : }
218 : break;
219 : default:
220 : break;
221 : }
222 : if (e != nullptr) {
223 7387 : myEventQue.push_back(e);
224 7387 : myEventThrow.signal();
225 7387 : myHalting = true;
226 : }
227 : // simulation step is over
228 9541174 : mySimulationInProgress = false;
229 122 : } catch (ProcessError& e2) {
230 366 : if (std::string(e2.what()) != std::string("Process Error") && std::string(e2.what()) != std::string("")) {
231 244 : WRITE_ERROR(e2.what());
232 : }
233 122 : MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
234 122 : mySimulationLock.unlock();
235 122 : mySimulationInProgress = false;
236 122 : e = new GUIEvent_SimulationEnded(MSNet::SIMSTATE_ERROR_IN_SIM, myNet->getCurrentTimeStep());
237 122 : myEventQue.push_back(e);
238 122 : myEventThrow.signal();
239 122 : myHalting = true;
240 122 : myOk = false;
241 : #ifndef _DEBUG
242 122 : } catch (...) {
243 0 : MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
244 0 : mySimulationLock.unlock();
245 0 : mySimulationInProgress = false;
246 0 : e = new GUIEvent_SimulationEnded(MSNet::SIMSTATE_ERROR_IN_SIM, myNet->getCurrentTimeStep());
247 0 : myEventQue.push_back(e);
248 0 : myEventThrow.signal();
249 0 : myHalting = true;
250 0 : myOk = false;
251 : #endif
252 0 : }
253 9541296 : }
254 :
255 :
256 : void
257 8046 : GUIRunThread::resume() {
258 8046 : mySingle = false;
259 8046 : myHalting = false;
260 8046 : }
261 :
262 :
263 : void
264 0 : GUIRunThread::singleStep() {
265 0 : mySingle = true;
266 0 : myHalting = false;
267 0 : }
268 :
269 :
270 : void
271 8046 : GUIRunThread::begin() {
272 : // report the begin when wished
273 16092 : WRITE_MESSAGEF(TL("Simulation started with time: %."), time2string(mySimStartTime));
274 8046 : myOk = true;
275 8046 : }
276 :
277 :
278 : void
279 7509 : GUIRunThread::stop() {
280 7509 : mySingle = false;
281 7509 : myHalting = true;
282 7509 : }
283 :
284 :
285 : bool
286 96910626 : GUIRunThread::networkAvailable() const {
287 96910626 : return myNet != nullptr;
288 : }
289 :
290 :
291 : void
292 42011 : GUIRunThread::deleteSim() {
293 42011 : myHalting = true;
294 : // flush aggregated warnings
295 42011 : MsgHandler::getWarningInstance()->clear();
296 : // remove message callbacks
297 42011 : MsgHandler::getErrorInstance()->removeRetriever(myErrorRetriever);
298 42011 : MsgHandler::getWarningInstance()->removeRetriever(myWarningRetriever);
299 42011 : MsgHandler::getMessageInstance()->removeRetriever(myMessageRetriever);
300 : //
301 42011 : mySimulationLock.lock();
302 42011 : if (myNet != nullptr) {
303 16392 : myNet->closeSimulation(mySimStartTime, MSNet::getStateMessage(myNet->simulationState(mySimEndTime)));
304 : }
305 42017 : while (mySimulationInProgress) {
306 6 : sleep(50);
307 : }
308 42011 : delete myNet;
309 42011 : GUIGlObjectStorage::gIDStorage.clear();
310 42011 : myNet = nullptr;
311 42011 : OutputDevice::closeAll();
312 42011 : mySimulationLock.unlock();
313 42011 : MsgHandler::cleanupOnEnd();
314 42011 : }
315 :
316 :
317 : GUINet&
318 68136712 : GUIRunThread::getNet() const {
319 68136712 : return *myNet;
320 : }
321 :
322 :
323 : void
324 8502 : GUIRunThread::prepareDestruction() {
325 8502 : myHalting = true;
326 8502 : myQuit = true;
327 8502 : }
328 :
329 :
330 : void
331 26198 : GUIRunThread::retrieveMessage(const MsgHandler::MsgType type, const std::string& msg) {
332 26198 : GUIEvent* e = new GUIEvent_Message(type, msg);
333 26198 : myEventQue.push_back(e);
334 26198 : myEventThrow.signal();
335 26198 : }
336 :
337 :
338 : bool
339 31046270 : GUIRunThread::simulationIsStartable() const {
340 31046270 : return myNet != nullptr && myHalting && myOk;
341 : }
342 :
343 :
344 : bool
345 21505566 : GUIRunThread::simulationIsStopable() const {
346 21505566 : return myNet != nullptr && (!myHalting);
347 : }
348 :
349 :
350 : bool
351 10752771 : GUIRunThread::simulationIsStepable() const {
352 10752771 : return myNet != nullptr && myHalting && myOk;
353 : }
354 :
355 :
356 : void
357 9541296 : GUIRunThread::waitForSnapshots(const SUMOTime snapshotTime) {
358 9541296 : GUIMainWindow* const mw = GUIMainWindow::getInstance();
359 9541296 : if (mw != nullptr) {
360 19082894 : for (GUIGlChildWindow* const window : mw->getViews()) {
361 9541598 : window->getView()->waitForSnapshots(snapshotTime);
362 : }
363 : }
364 9541296 : }
365 :
366 :
367 : /****************************************************************************/
|