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:
committed by
Copybara-Service
parent
a1d0cbd654
commit
a84499e904
@@ -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
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user