Skip to content

Commit

Permalink
Avoid deadlock if energyplus stops running for any reason
Browse files Browse the repository at this point in the history
Before this change if EnergyPlus came to the end of the run period,
threw an execption, or suffered a fatal error, then the control thread
would just hang due to a deadlock. This should address that issue. A
future change will make spawn/EnergyPlus ignore the run period
completely.

ref lbl-srg/modelica-buildings#1678
  • Loading branch information
kbenne committed Mar 17, 2020
1 parent 26fd4ac commit cf7a88d
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 28 deletions.
51 changes: 32 additions & 19 deletions epfmi/EPComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,14 @@ int EPComponent::start() {

EnergyPlus::CommandLineInterface::ProcessArgs( argc, argv );
EnergyPlus::DataGlobals::externalHVACManager = std::bind(&EPComponent::externalHVACManager, this);
RunEnergyPlus();
try {
auto result = RunEnergyPlus();
std::unique_lock<std::mutex> lk(control_mutex);
epstatus = result ? EPStatus::ERROR : EPStatus::DONE;
} catch(...) {
epstatus = EPStatus::ERROR;
}
control_cv.notify_one();
};

{
Expand All @@ -64,13 +71,8 @@ int EPComponent::start() {

simthread = std::thread(simulation);

{
// Wait for E+ to go back to IDLE
std::unique_lock<std::mutex> lk(control_mutex);
control_cv.wait( lk, [&](){ return epstatus == EPStatus::NONE; } );
}

return 0;
// Wait for EnergyPlus to go through startup/warmup etc
return controlWait();
}

int EPComponent::stop() {
Expand All @@ -79,11 +81,14 @@ int EPComponent::stop() {
epstatus = EPStatus::TERMINATE;
}

stopSimulation();
control_cv.notify_one();
simthread.join();

return 0;
try {
stopSimulation();
control_cv.notify_one();
simthread.join();
return 0;
} catch(...) {
return 1;
}
}

int EPComponent::setTime(const double & time)
Expand All @@ -98,13 +103,9 @@ int EPComponent::setTime(const double & time)
}
// Notify E+ to advance
control_cv.notify_one();
{
// Wait for E+ to advance and go back to IDLE before returning
std::unique_lock<std::mutex> lk( control_mutex );
control_cv.wait( lk, [&](){ return epstatus == EPStatus::NONE; } );
}

return 0;
// Wait for EnergyPlus to complete the step
return controlWait();
}

fmi2Real EPComponent::currentSimTime() const {
Expand Down Expand Up @@ -268,6 +269,18 @@ void EPComponent::exchange()
}
}

int EPComponent::controlWait() {
std::unique_lock<std::mutex> lk(control_mutex);
// Wait until EnergyPlus is not Advancing or Terminating (ie in the process of cleanup)
control_cv.wait( lk, [&](){
return
(epstatus == EPStatus::NONE) ||
(epstatus == EPStatus::ERROR) ||
(epstatus == EPStatus::DONE);
});
return epstatus == EPStatus::ERROR ? 1 : 0;
}

void EPComponent::externalHVACManager() {
// Although we do not use the ZoneTempPredictorCorrector,
// some global variables need to be initialized by InitZoneAirSetPoints
Expand Down
6 changes: 5 additions & 1 deletion epfmi/EPComponent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
#include <sstream>
#include <condition_variable>

enum class EPStatus { ADVANCE, NONE, TERMINATE, EXCHANGE };
enum class EPStatus { ADVANCE, NONE, TERMINATE, ERROR, DONE };

class EPComponent {
public:
Expand Down Expand Up @@ -111,6 +111,10 @@ class EPComponent {

private:

// Wait for the EnergyPlus thread from the control thread
// Return 0 on success
// This should be called from the control thread
int controlWait();
Real64 zoneHeatTransfer(const int ZoneNum);

fmi2Real requestedTime;
Expand Down
12 changes: 4 additions & 8 deletions epfmi/EPFMI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,14 @@ EPFMI_API fmi2Status fmi2SetupExperiment(fmi2Component c,
UNUSED(stopTimeDefined);
UNUSED(stopTime);

epcomp->start();

return fmi2OK;
return epcomp->start() ? fmi2Error : fmi2OK;
}

EPFMI_API fmi2Status fmi2SetTime(fmi2Component c, fmi2Real time)
{
EPComponent * epcomp = static_cast<EPComponent*>(c);

epcomp->setTime(time);

return fmi2OK;
return epcomp->setTime(time) ? fmi2Error : fmi2OK;
}

EPFMI_API fmi2Status fmi2SetReal(fmi2Component c,
Expand Down Expand Up @@ -113,12 +109,12 @@ EPFMI_API fmi2Status fmi2Terminate(fmi2Component c)
{
EPComponent * epcomp = static_cast<EPComponent*>(c);

epcomp->stop();
auto result = epcomp->stop();

auto it = std::find(epComponents.begin(), epComponents.end(), *epcomp);
epComponents.erase(it);

return fmi2OK;
return result ? fmi2Error : fmi2OK;
}

EPFMI_API const char* fmi2GetTypesPlatform(void)
Expand Down

0 comments on commit cf7a88d

Please sign in to comment.