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