pushing events from read method does not clear value flag

I found, that pushing event does not clean value_flag, event if value is cleand. Which makes this flag useless. This results in the crash in PyTango !, due to PyTango relays on this flag.

I added printout, when value is deleted, set and value_flag is set, and this is how it looks like:

The python code:

from tango import EventType
from tango.server import Device, attribute, command
from tango.test_context import DeviceTestContext

class MyDevice(Device):

    def init_device(self):
        super(MyDevice, self).init_device()
        self.set_change_event("attr", True, False)

    @attribute()
    def attr(self):
        self.push_change_event("attr", 1)
        return 1


def cb(evnt):
    print("Got event")


if __name__ == '__main__':
    with(DeviceTestContext(MyDevice, debug=5)) as proxy:
        eid = proxy.subscribe_event("attr", EventType.CHANGE_EVENT, cb)
        proxy.push_event()

The printouts:

2025-03-24T09:57:58,695390+0100 DEBUG (device_2.cpp:928) dserver/MyDevice/MyDevice Device_2Impl::command_list_query_2 arrived
2025-03-24T09:57:58,695403+0100 DEBUG (device_2.cpp:943) dserver/MyDevice/MyDevice 4 command(s) for device
2025-03-24T09:57:58,695414+0100 DEBUG (device_2.cpp:1025) dserver/MyDevice/MyDevice Leaving Device_2Impl::command_list_query_2
2025-03-24T09:57:58,695682+0100 DEBUG (device_4.cpp:459) dserver/MyDevice/MyDevice Device_4Impl::command_inout_4 arrived, source = 2, command = push_event
2025-03-24T09:57:58,695698+0100 DEBUG (device_2.cpp:124) dserver/MyDevice/MyDevice Device_2Impl::command_inout_2 arrived, source = 2, command = push_event
2025-03-24T09:57:58,695707+0100 DEBUG (tango_monitor.h:152) dserver/MyDevice/MyDevice In get_monitor() test/nodb/mydevice cache, thread = 0, ctr = 0
2025-03-24T09:57:58,695725+0100 DEBUG (tango_monitor.h:203) dserver/MyDevice/MyDevice In rel_monitor() test/nodb/mydevice cache, ctr = 1, thread = 0
2025-03-24T09:57:58,695733+0100 DEBUG (tango_monitor.h:213) dserver/MyDevice/MyDevice Signalling !
2025-03-24T09:57:58,695742+0100 DEBUG (tango_monitor.h:152) dserver/MyDevice/MyDevice In get_monitor() test/nodb/mydevice, thread = 0, ctr = 0
2025-03-24T09:57:58,695749+0100 DEBUG (tango_monitor.h:152) dserver/MyDevice/MyDevice In get_monitor() test/nodb/mydevice, thread = 0, ctr = 1
2025-03-24T09:57:58,695756+0100 DEBUG (tango_monitor.h:181) dserver/MyDevice/MyDevice owner_thread !!
2025-03-24T09:57:58,695764+0100 DEBUG (device.cpp:1798) dserver/MyDevice/MyDevice DeviceImpl::command_inout(): command received : push_event
2025-03-24T09:57:58,695772+0100 DEBUG (subdev_diag.cpp:99) dserver/MyDevice/MyDevice SubDevDiag::get_associated_device() entering ... 
2025-03-24T09:57:58,695779+0100 DEBUG (subdev_diag.cpp:105) dserver/MyDevice/MyDevice SubDevDiag::get_associated_device() found : 
2025-03-24T09:57:58,695787+0100 DEBUG (subdev_diag.cpp:78) dserver/MyDevice/MyDevice SubDevDiag::set_associated_device() entering ... 
2025-03-24T09:57:58,695795+0100 DEBUG (deviceclass.cpp:1152) dserver/MyDevice/MyDevice Entering DeviceClass::command_handler() method
2025-03-24T09:57:58,695833+0100 DEBUG (tango_monitor.h:152) dserver/MyDevice/MyDevice In get_monitor() test/nodb/mydevice, thread = 0, ctr = 2
2025-03-24T09:57:58,695842+0100 DEBUG (tango_monitor.h:181) dserver/MyDevice/MyDevice owner_thread !!
2025-03-24T09:57:58,695864+0100 DEBUG (attrsetval_templ.h:73) dserver/MyDevice/MyDevice Attribute::set_value() called 
2025-03-24T09:57:58,695874+0100 DEBUG (attribute.h:1664) dserver/MyDevice/MyDevice Attribute::set_value_flag() to 1
2025-03-24T09:57:58,695882+0100 DEBUG (attribute.cpp:2963) dserver/MyDevice/MyDevice Attribute::generic_fire_event() for change entering ...
2025-03-24T09:57:58,695890+0100 DEBUG (attribute.cpp:2963) dserver/MyDevice/MyDevice Attribute::generic_fire_event() for alarm entering ...
2025-03-24T09:57:58,695902+0100 DEBUG (attribute.h:1671) dserver/MyDevice/MyDevice Attribute::get_value_flag(), ret: 1
2025-03-24T09:57:58,695911+0100 DEBUG (attribute.h:1671) dserver/MyDevice/MyDevice Attribute::get_value_flag(), ret: 1
2025-03-24T09:57:58,695919+0100 DEBUG (attribute.h:1671) dserver/MyDevice/MyDevice Attribute::get_value_flag(), ret: 1
2025-03-24T09:57:58,695932+0100 DEBUG (device.cpp:5165) dserver/MyDevice/MyDevice DeviceImpl::data_into_net_object() called 
2025-03-24T09:57:58,695942+0100 DEBUG (zmqeventsupplier.cpp:1753) dserver/MyDevice/MyDevice ZmqEventSupplier::push_event_loop(): called for attribute attr
2025-03-24T09:57:58,695956+0100 DEBUG (zmqeventsupplier.cpp:1040) dserver/MyDevice/MyDevice ZmqEventSupplier::push_event(): called for attribute/pipe attr
2025-03-24T09:57:58,695990+0100 DEBUG (attribute.cpp:2147) dserver/MyDevice/MyDevice Attribute::delete_seq_and_reset_alarm() called 
2025-03-24T09:57:58,696002+0100 DEBUG (attribute.cpp:2171) dserver/MyDevice/MyDevice Attribute::delete_seq() called 
2025-03-24T09:57:58,696011+0100 DEBUG (tango_monitor.h:203) dserver/MyDevice/MyDevice In rel_monitor() test/nodb/mydevice, ctr = 3, thread = 0
2025-03-24T09:57:58,696025+0100 DEBUG (deviceclass.cpp:1262) dserver/MyDevice/MyDevice Leaving DeviceClass::command_handler() method
2025-03-24T09:57:58,696033+0100 DEBUG (subdev_diag.cpp:78) dserver/MyDevice/MyDevice SubDevDiag::set_associated_device() entering ... 
2025-03-24T09:57:58,696043+0100 DEBUG (device.cpp:1848) dserver/MyDevice/MyDevice DeviceImpl::command_inout(): leaving method for command push_event
2025-03-24T09:57:58,696053+0100 DEBUG (tango_monitor.h:203) dserver/MyDevice/MyDevice In rel_monitor() test/nodb/mydevice, ctr = 2, thread = 0
2025-03-24T09:57:58,696065+0100 DEBUG (tango_monitor.h:203) dserver/MyDevice/MyDevice In rel_monitor() test/nodb/mydevice, ctr = 1, thread = 0
2025-03-24T09:57:58,696074+0100 DEBUG (tango_monitor.h:213) dserver/MyDevice/MyDevice Signalling !

As you see, we do:

2025-03-24T09:57:58,695864+0100 DEBUG (attrsetval_templ.h:73) dserver/MyDevice/MyDevice Attribute::set_value() called 
2025-03-24T09:57:58,695874+0100 DEBUG (attribute.h:1664) dserver/MyDevice/MyDevice Attribute::set_value_flag() to 1

And then

2025-03-24T09:57:58,695990+0100 DEBUG (attribute.cpp:2147) dserver/MyDevice/MyDevice Attribute::delete_seq_and_reset_alarm() called 
2025-03-24T09:57:58,696002+0100 DEBUG (attribute.cpp:2171) dserver/MyDevice/MyDevice Attribute::delete_seq() called 

But there is no call to set value_flag to 0

This is Catch2 equivalent to pytango code:

#include "catch2_common.h"

template <class Base>
class EventDev : public Base
{
public:
    using Base::Base;

    ~EventDev() override { }

    void init_device() override
    {
        Base::set_change_event("attr", true, false);
    }

    void read_attribute(Tango::Attribute &att)
    {
        {
            Tango::DevLong* val = new Tango::DevLong(1);
            Tango::AutoTangoMonitor tango_guard(this);
            att.set_value(val, 1, 0, true);
            att.fire_change_event(nullptr);
        }

        if (!att.get_value_flag()){
            Tango::DevLong* val_ret = new Tango::DevLong(1);
            att.set_value(val_ret);
        }
    }

    static void attribute_factory(std::vector<Tango::Attr *> &attrs)
    {
        {
            auto long_attr = new TangoTest::AutoAttr<&EventDev::read_attribute>("attr", Tango::DEV_LONG);
            attrs.push_back(long_attr);
        }
    }
};

TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE(EventDev, 4)

SCENARIO("Subscribe to event with simultaneous push")
{
    int idlver = GENERATE(TangoTest::idlversion(4));
    GIVEN("a device proxy to a simple IDLv" << idlver << " device")
    {
        TangoTest::Context ctx{"change_event_state", "EventDev", idlver};
        auto device = ctx.get_proxy();

        REQUIRE(idlver == device->get_idl_version());

        AND_GIVEN("an event subscription to attr attribute")
        {
            TangoTest::CallbackMock<Tango::EventData> callback;
            REQUIRE_NOTHROW(device->subscribe_event("attr", Tango::CHANGE_EVENT, &callback));
        }
    }
}
Edited Mar 27, 2025 by Yury Matveev
Assignee Loading
Time tracking Loading