Fix non-graceful exiting behaviour in launch_passive.

The viewer currently hard crashes when the user script loops on the passive viewer handle without paying attention to `is_running`. This is considered user error, however this change makes the user script hang on the loop rather than hard crashing.

Startblock:
   diffbase is submitted
PiperOrigin-RevId: 572336261
Change-Id: Id53126a158242b947584da1f946304ae8e792d4a
This commit is contained in:
Saran Tunyasuvunakool
2023-10-10 12:38:42 -07:00
committed by Copybara-Service
parent a1d0cbd654
commit a84499e904
2 changed files with 21 additions and 15 deletions
+5 -7
View File
@@ -97,9 +97,9 @@ class SimulateWrapper {
}
}
void WaitUntilDestroyed() {
void WaitUntilExit() {
// TODO: replace with atomic wait when we migrate to C++20
while (!destroyed_.load()) {
while (simulate_ && simulate_->exitrequest.load() != 2) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
@@ -206,8 +206,7 @@ PYBIND11_MODULE(_simulate, pymodule) {
key_callback),
scn, cam, opt, pert, is_passive);
}))
.def("destroy", &SimulateWrapper::Destroy,
py::call_guard<py::gil_scoped_release>())
.def("destroy", &SimulateWrapper::Destroy)
.def("load_message", CallIfNotNull(&mujoco::Simulate::LoadMessage),
py::call_guard<py::gil_scoped_release>())
.def("load", &SimulateWrapper::Load)
@@ -266,9 +265,8 @@ PYBIND11_MODULE(_simulate, pymodule) {
int value = 0;
sim->exitrequest.compare_exchange_strong(value, 1);
wrapper.WaitUntilDestroyed();
},
py::call_guard<py::gil_scoped_release>())
wrapper.WaitUntilExit();
})
.def_property_readonly("uiloadrequest",
CallIfNotNull(+[](mujoco::Simulate& sim) {
+16 -8
View File
@@ -99,35 +99,43 @@ class Handle:
if sim is not None:
sim.exit()
def is_running(self) -> bool:
def _get_sim(self) -> Optional[_Simulate]:
sim = self._sim()
if sim is not None:
return sim.exitrequest < 2
return False
try:
return sim if sim.exitrequest == 0 else None
except mujoco.UnexpectedError:
# UnexpectedError is raised when accessing `exitrequest` after the
# underlying simulate instance has been deleted in C++.
return None
return None
def is_running(self) -> bool:
return self._get_sim() is not None
def lock(self):
sim = self._sim()
sim = self._get_sim()
if sim is not None:
return sim.lock()
return contextlib.nullcontext()
def sync(self):
sim = self._sim()
sim = self._get_sim()
if sim is not None:
sim.sync() # locks internally
def update_hfield(self, hfieldid: int):
sim = self._sim()
sim = self._get_sim()
if sim is not None:
sim.update_hfield(hfieldid) # locks internally and blocks until done
def update_mesh(self, meshid: int):
sim = self._sim()
sim = self._get_sim()
if sim is not None:
sim.update_mesh(meshid) # locks internally and blocks until done
def update_texture(self, texid: int):
sim = self._sim()
sim = self._get_sim()
if sim is not None:
sim.update_texture(texid) # locks internally and blocks until done