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