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