Deadlock when pushing event inside DynamicAttribute's read method
Recently I was testing new PyAlarm version with the latest PyTango release (9.5.1).
When reading value of a PyAlarm-defined dynamic attribute, I noticed that a deadlock. What's interesting is that when running the same DS, with PyTango==9.5.0
, it ran fine.
I concluded that, the deadlock happened withing call to push_change_event
and came up with this recreation:
Click to expand - code with recreation steps.
import sys
import time
import tango
class MyDevice(tango.LatestDeviceImpl):
def __init__(self, cl, name):
tango.LatestDeviceImpl.__init__(self, cl, name)
self._values = {}
def CreateBooleanAttribute(self, attr_name):
if attr_name in self._values:
raise ValueError(f"Already have an attribute called {repr(attr_name)}")
self._values[attr_name] = False
attr = tango.Attr(attr_name, tango.ArgType.DevBoolean, tango.AttrWriteType.READ)
self.add_attribute(
attr,
self.generic_read,
)
self.set_change_event(attr_name.lower(), True, False)
def generic_read(self, attr):
attr_name = attr.get_name()
self.info_stream("Reading attribute %s", attr_name)
value = self._values[attr.get_name()]
self.push_change_event(attr_name, value)
t = time.time()
quality = tango.AttrQuality.ATTR_VALID
self.push_change_event(attr_name, value, t, quality)
attr.set_value_date_quality(value, t, quality)
class MyDeviceClass(tango.DeviceClass):
cmd_list = {
"CreateBooleanAttribute": [[tango.DevString], [tango.DevBoolean]],
}
def __init__(self, name):
tango.DeviceClass.__init__(self, name)
self.set_type(name)
if __name__ == "__main__":
util = tango.Util(sys.argv)
util.add_class(MyDeviceClass, MyDevice)
U = tango.Util.instance()
U.server_init()
print("running...")
U.server_run()
In the example above, I am creating a device that has dynamic attributes created using CreateBooleanAttribute
command.
These attributes are being read by the generic_read
function, which during the reading, pushes event.
When running this code with Pytango==9.5.0
, it works, but with PyTango==9.5.1
it does not.
Exact steps of reproduction
- run code above, like so:
python MyDevice.py <name>
- open jive, right click on the device and open
test device
menu - run
CreateBooleanAttribute
command to create a new attribute - open the
test device
menu again, and attempt to read newly created attribute - Deadlock
Error messages
When default timeout is set (3000ms) I get this message:
Device (pytango/test/1) timed out (>3000 ms)!
After setting bigger value for the timeout I got this message:
Not able to acquire serialization (dev, class or process) monitor
which most probably suggests a deadlock has happened.
I am not very familiar with Tango internals, but I would be very willing to provide any additional information that would help to resolve the issue.