Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 7533 : GUIRunThread::GUIRunThread(FXApp* app, MFXInterThreadEventClient* parent, double& simDelay,
52 7533 : MFXSynchQue<GUIEvent*>& eq, FXEX::MFXThreadEvent& ev) :
53 : MFXSingleEventThread(app, parent),
54 7533 : myNet(nullptr),
55 7533 : myHalting(true),
56 7533 : myQuit(false),
57 7533 : mySimulationInProgress(false),
58 7533 : myOk(true),
59 7533 : myHaveSignaledEnd(false),
60 7533 : mySimDelay(simDelay),
61 7533 : myEventQue(eq),
62 7533 : myEventThrow(ev),
63 7533 : myLastEndMillis(-1),
64 7533 : myLastBreakMillis(0),
65 7533 : myAmLibsumo(false) {
66 7533 : myErrorRetriever = new MsgRetrievingFunction<GUIRunThread>(this, &GUIRunThread::retrieveMessage, MsgHandler::MsgType::MT_ERROR);
67 7533 : myMessageRetriever = new MsgRetrievingFunction<GUIRunThread>(this, &GUIRunThread::retrieveMessage, MsgHandler::MsgType::MT_MESSAGE);
68 7533 : myWarningRetriever = new MsgRetrievingFunction<GUIRunThread>(this, &GUIRunThread::retrieveMessage, MsgHandler::MsgType::MT_WARNING);
69 7533 : }
70 :
71 :
72 15046 : GUIRunThread::~GUIRunThread() {
73 : // the thread shall stop
74 7523 : myQuit = true;
75 7523 : deleteSim();
76 7523 : delete myErrorRetriever;
77 7523 : delete myMessageRetriever;
78 7523 : delete myWarningRetriever;
79 : // wait for the thread
80 7523 : while (mySimulationInProgress || myNet != nullptr);
81 15046 : }
82 :
83 :
84 : bool
85 7256 : GUIRunThread::init(GUINet* net, SUMOTime start, SUMOTime end) {
86 : assert(net != 0);
87 : // assign new values
88 7256 : myOk = true;
89 7256 : myNet = net;
90 7256 : mySimStartTime = start;
91 7256 : mySimEndTime = end;
92 7256 : myHaveSignaledEnd = false;
93 : // register message callbacks
94 7256 : MsgHandler::getErrorInstance()->addRetriever(myErrorRetriever);
95 7256 : MsgHandler::getMessageInstance()->addRetriever(myMessageRetriever);
96 14512 : if (!OptionsCont::getOptions().getBool("no-warnings")) {
97 7256 : MsgHandler::getWarningInstance()->addRetriever(myWarningRetriever);
98 : }
99 : // preload the routes especially for TraCI
100 7256 : mySimulationLock.lock();
101 : try {
102 : net->setCurrentTimeStep(start);
103 7256 : net->loadRoutes();
104 167 : } catch (ProcessError& e2) {
105 485 : if (std::string(e2.what()) != std::string("Process Error") && std::string(e2.what()) != std::string("")) {
106 300 : WRITE_ERROR(e2.what());
107 : }
108 167 : MsgHandler::getErrorInstance()->inform(TL("Quitting (on error)."), false);
109 167 : myHalting = true;
110 167 : myOk = false;
111 167 : mySimulationInProgress = false;
112 : #ifndef _DEBUG
113 167 : } 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 7256 : mySimulationLock.unlock();
121 7256 : return myOk;
122 : }
123 :
124 :
125 : FXint
126 7533 : GUIRunThread::run() {
127 : // perform an endless loop
128 5807352 : while (!myQuit) {
129 5799829 : if (myAmLibsumo) {
130 482 : myApp->run();
131 : } else {
132 : // if the simulation shall be performed, do it
133 5799347 : tryStep();
134 : }
135 : }
136 : // delete a maybe existing simulation at the end
137 7523 : deleteSim();
138 7523 : return 0;
139 : }
140 :
141 :
142 : void
143 5878637 : GUIRunThread::tryStep() {
144 5878637 : if (!myHalting && myNet != nullptr && myOk) {
145 5831831 : const long beg = SysUtils::getCurrentMillis();
146 5831831 : if (myLastEndMillis != -1) {
147 5824806 : getNet().setIdleDuration((int)(beg - myLastEndMillis));
148 : }
149 : // check whether we shall stop at this step
150 5831831 : myBreakpointLock.lock();
151 5831831 : const bool haltAfter = std::find(myBreakpoints.begin(), myBreakpoints.end(), myNet->getCurrentTimeStep()) != myBreakpoints.end();
152 5831831 : myBreakpointLock.unlock();
153 : // stop after this step if wished
154 5831831 : if (haltAfter) {
155 0 : stop();
156 : }
157 : // stop the execution when only a single step should have been performed
158 5831831 : if (mySingle) {
159 0 : myHalting = true;
160 : }
161 : // do the step
162 5831831 : makeStep();
163 5831831 : waitForSnapshots(myNet->getCurrentTimeStep() - DELTA_T);
164 : // wait if wanted (delay is per simulated second)
165 5831831 : long wait = (long)(mySimDelay * TS);
166 5831831 : myLastEndMillis = SysUtils::getCurrentMillis();
167 5831831 : getNet().setSimDuration((int)(myLastEndMillis - beg));
168 5831831 : wait -= (myLastEndMillis - beg);
169 5831831 : if (wait > 0) {
170 5075 : myLastBreakMillis = myLastEndMillis;
171 5075 : sleep(wait);
172 : #ifndef WIN32
173 5826756 : } else if (myLastEndMillis - myLastBreakMillis > 1000) {
174 : // ensure redraw event is successful at least once per second (#9028)
175 13850 : sleep(100);
176 13850 : myLastBreakMillis = myLastEndMillis;
177 : #endif
178 : }
179 : } else {
180 : // sleep if the simulation is not running
181 46806 : sleep(50);
182 : }
183 5878637 : }
184 :
185 :
186 : void
187 5831831 : GUIRunThread::makeStep() {
188 : GUIEvent* e = nullptr;
189 : // simulation is being performed
190 5831831 : mySimulationInProgress = true;
191 : // execute a single step
192 : try {
193 5831831 : mySimulationLock.lock();
194 5831831 : myNet->simulationStep();
195 5831718 : myNet->guiSimulationStep();
196 5831718 : mySimulationLock.unlock();
197 :
198 : // inform parent that a step has been performed
199 5831718 : e = new GUIEvent_SimulationStep();
200 5831718 : myEventQue.push_back(e);
201 5831718 : myEventThrow.signal();
202 :
203 : e = nullptr;
204 5831718 : MSNet::SimulationState state = myNet->adaptToState(myNet->simulationState(mySimEndTime), myAmLibsumo);
205 5831718 : switch (state) {
206 6494 : 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 6494 : if (!myHaveSignaledEnd || state != MSNet::SIMSTATE_END_STEP_REACHED) {
212 6494 : 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 6494 : myHaveSignaledEnd = true;
217 : }
218 : break;
219 : default:
220 : break;
221 : }
222 : if (e != nullptr) {
223 6494 : myEventQue.push_back(e);
224 6494 : myEventThrow.signal();
225 6494 : myHalting = true;
226 : }
227 : // simulation step is over
228 5831718 : mySimulationInProgress = false;
229 113 : } catch (ProcessError& e2) {
230 339 : if (std::string(e2.what()) != std::string("Process Error") && std::string(e2.what()) != std::string("")) {
231 226 : WRITE_ERROR(e2.what());
232 : }
233 113 : MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
234 113 : mySimulationLock.unlock();
235 113 : mySimulationInProgress = false;
236 113 : e = new GUIEvent_SimulationEnded(MSNet::SIMSTATE_ERROR_IN_SIM, myNet->getCurrentTimeStep());
237 113 : myEventQue.push_back(e);
238 113 : myEventThrow.signal();
239 113 : myHalting = true;
240 113 : myOk = false;
241 : #ifndef _DEBUG
242 113 : } 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 5831831 : }
254 :
255 :
256 : void
257 7086 : GUIRunThread::resume() {
258 7086 : mySingle = false;
259 7086 : myHalting = false;
260 7086 : }
261 :
262 :
263 : void
264 0 : GUIRunThread::singleStep() {
265 0 : mySingle = true;
266 0 : myHalting = false;
267 0 : }
268 :
269 :
270 : void
271 7086 : GUIRunThread::begin() {
272 : // report the begin when wished
273 14172 : WRITE_MESSAGEF(TL("Simulation started with time: %."), time2string(mySimStartTime));
274 7086 : myOk = true;
275 7086 : }
276 :
277 :
278 : void
279 6607 : GUIRunThread::stop() {
280 6607 : mySingle = false;
281 6607 : myHalting = true;
282 6607 : }
283 :
284 :
285 : bool
286 44171911 : GUIRunThread::networkAvailable() const {
287 44171911 : return myNet != nullptr;
288 : }
289 :
290 :
291 : void
292 37153 : GUIRunThread::deleteSim() {
293 37153 : myHalting = true;
294 : // flush aggregated warnings
295 37153 : MsgHandler::getWarningInstance()->clear();
296 : // remove message callbacks
297 37153 : MsgHandler::getErrorInstance()->removeRetriever(myErrorRetriever);
298 37153 : MsgHandler::getWarningInstance()->removeRetriever(myWarningRetriever);
299 37153 : MsgHandler::getMessageInstance()->removeRetriever(myMessageRetriever);
300 : //
301 37153 : mySimulationLock.lock();
302 37153 : if (myNet != nullptr) {
303 14492 : myNet->closeSimulation(mySimStartTime, MSNet::getStateMessage(myNet->simulationState(mySimEndTime)));
304 : }
305 37157 : while (mySimulationInProgress) {
306 4 : sleep(50);
307 : }
308 37153 : delete myNet;
309 37153 : GUIGlObjectStorage::gIDStorage.clear();
310 37153 : myNet = nullptr;
311 37153 : OutputDevice::closeAll();
312 37153 : mySimulationLock.unlock();
313 37153 : MsgHandler::cleanupOnEnd();
314 37153 : }
315 :
316 :
317 : GUINet&
318 42001658 : GUIRunThread::getNet() const {
319 42001658 : return *myNet;
320 : }
321 :
322 :
323 : void
324 7524 : GUIRunThread::prepareDestruction() {
325 7524 : myHalting = true;
326 7524 : myQuit = true;
327 7524 : }
328 :
329 :
330 : void
331 24604 : GUIRunThread::retrieveMessage(const MsgHandler::MsgType type, const std::string& msg) {
332 24604 : GUIEvent* e = new GUIEvent_Message(type, msg);
333 24604 : myEventQue.push_back(e);
334 24604 : myEventThrow.signal();
335 24604 : }
336 :
337 :
338 : bool
339 18153539 : GUIRunThread::simulationIsStartable() const {
340 18153539 : return myNet != nullptr && myHalting;
341 : }
342 :
343 :
344 : bool
345 12319492 : GUIRunThread::simulationIsStopable() const {
346 12319492 : return myNet != nullptr && (!myHalting);
347 : }
348 :
349 :
350 : bool
351 6159729 : GUIRunThread::simulationIsStepable() const {
352 6159729 : return myNet != nullptr && myHalting;
353 : }
354 :
355 :
356 : void
357 5831831 : GUIRunThread::waitForSnapshots(const SUMOTime snapshotTime) {
358 5831831 : GUIMainWindow* const mw = GUIMainWindow::getInstance();
359 5831831 : if (mw != nullptr) {
360 11663663 : for (GUIGlChildWindow* const window : mw->getViews()) {
361 5831832 : window->getView()->waitForSnapshots(snapshotTime);
362 : }
363 : }
364 5831831 : }
365 :
366 :
367 : /****************************************************************************/
|