RTT::Events

Hi,

I'm having problems with making the RTT::Event class send/receive
commands over CAN.
I have a EventProxy derived from the signal template
implementing a RTT::LocalCommand with a overridden operator()(). In this
operator I do:

void CLocalEventProxy::operator()()
{
if(m_El)
m_El->sendEvent(m_Id); //--> send a CAN message.
this->emit();
}

Where I receive the CAN message I just call emit() thus preventing an
other CAN message being sent.

Using this construction I can fire an event over the CAN network from a
proxy to a server. It is the other way around I can't get away with.

For Commands and DataPorts I change the implementation to a
server-implementation if they are in the interface of the TaskContex's I
want to export over CAN (using commands() and ports()). I was hoping I
could do the same thing with Events. The problem is that the objects
stored in the EventService, returned by events(), are already
implementations. So I can't just change them can I? Or are the shared
pointers smart enough to handle this?

Kind regards,
Sander Vandenbroucke

RTT::Events

On Friday 14 November 2008 15:42:15 Vandenbroucke Sander wrote:
> > -----Original Message-----
> >
> > Nasty. That check shouldn't be there for the reasons you list. It was
> > meant to
> > prevent infinite recursion when a handler function would emit the
>
> event
>
> > again.
> > Bad luck in my opinion. We don't prevent recursion in other places, so
>
> why
>
> > would we here...
> >
> > We need to define a unit test where two or more threads emit an event
>
> and
>
> > check
> > that all the emits resulted in calling the callback.
>
> I can leave this check out?

It looks like you can (the callback lock-free list is thread-safe). But we
need to unit test to be sure.

Peter

RTT::Events - Good news

On Friday 14 November 2008 16:34:21 Peter Soetens wrote:
> On Friday 14 November 2008 15:42:15 Vandenbroucke Sander wrote:
> > > -----Original Message-----
> > >
> > > Nasty. That check shouldn't be there for the reasons you list. It was
> > > meant to
> > > prevent infinite recursion when a handler function would emit the
> >
> > event
> >
> > > again.
> > > Bad luck in my opinion. We don't prevent recursion in other places, so
> >
> > why
> >
> > > would we here...
> > >
> > > We need to define a unit test where two or more threads emit an event
> >
> > and
> >
> > > check
> > > that all the emits resulted in calling the callback.
> >
> > I can leave this check out?
>
> It looks like you can (the callback lock-free list is thread-safe). But we
> need to unit test to be sure.

It seemed the proposed fix was working after-all. It was another unit test
which assumed that we wouldn't recurse and which let the change fail. I got
all the unit tests passing for lock-free events and lock-based events. The
default remains lock-free.

I'll merge this on trunk soon.

Peter

RTT::Events

Hi, I took the following code out of signal_template.hpp

R emit(OROCOS_SIGNATURE_PARMS)
{
#ifdef ORO_SIGNAL_USE_LIST_LOCK_FREE
if (this->emitting)
return detail::NA::na(); // avoid uglyness : Handlers calling
emit.
this->emitting = true;

// this code did initially not work under gcc 4.0/ubuntu breezy.
// connection_t::get() const becomes an undefined symbol.
// works under gcc 3.4
mconnections.apply( boost::lambda::bind(&connection_impl::emit,
boost::lambda::bind(
&applyEmit, boost::lambda::_1) // works for any compiler
//not in gcc 4.0.2:
boost::lambda::ll_static_cast(boost::lambda::bind(&con
nection_t::get, boost::lambda::_1))
#if OROCOS_SIGNATURE_NUM_ARGS != 0
,OROCOS_SIGNATURE_ARGS
#endif
) );
this->emitting = false;
#else
OS::MutexLock lock(m);
if (this->emitting)
return detail::NA::na(); // avoid uglyness : Handlers calling
emit.
this->emitting = true;
iterator it = mconnections.begin();
const_iterator end = mconnections.end();
for (; it != end; ++it ) {
connection_impl* ci = static_cast( it->get()
);
if (ci)
ci->emit(OROCOS_SIGNATURE_ARGS); // this if... race is
guarded by the mutex.
}
this->emitting = false;
this->cleanup();
#endif
return detail::NA::na();
}

Notice the
if (this->emitting)
return detail::NA::na(); // avoid uglyness : Handlers calling
statements witch causes trouble for me.

I have a situation where two threads call the same event, one sometimes
preempting the other resulting in 'missed' events due to this if()
statement. I wonder what the OROCOS point of view is on this mather? I
mean: is it advised to call one event from more than one thread? Or
should I look for an other way to solve this?

Kind regards.
Sander.

RTT::Events

On Wednesday 12 November 2008 16:22:48 Vandenbroucke Sander wrote:
> Hi, I took the following code out of signal_template.hpp
>
...
>
> Notice the
> if (this->emitting)
> return detail::NA::na(); // avoid uglyness : Handlers calling
> statements witch causes trouble for me.
>
> I have a situation where two threads call the same event, one sometimes
> preempting the other resulting in 'missed' events due to this if()
> statement. I wonder what the OROCOS point of view is on this mather? I
> mean: is it advised to call one event from more than one thread? Or
> should I look for an other way to solve this?

Nasty. That check shouldn't be there for the reasons you list. It was meant to
prevent infinite recursion when a handler function would emit the event again.
Bad luck in my opinion. We don't prevent recursion in other places, so why
would we here...

We need to define a unit test where two or more threads emit an event and check
that all the emits resulted in calling the callback.

Peter

RTT::Events

On Monday 14 May 2007 11:50:06 Vandenbroucke Sander wrote:
> Hi,
>
> I'm having problems with making the RTT::Event class send/receive
> commands over CAN.
> I have a EventProxy derived from the signal template
> implementing a RTT::LocalCommand with a overridden operator()(). In this
> operator I do:
>
> void CLocalEventProxy::operator()()
> {
> if(m_El)
> m_El->sendEvent(m_Id); //--> send a CAN message.
> this->emit();
> }

Interesting, using a command for emiting events.

>
> Where I receive the CAN message I just call emit() thus preventing an
> other CAN message being sent.
>
> Using this construction I can fire an event over the CAN network from a
> proxy to a server. It is the other way around I can't get away with.
>
> For Commands and DataPorts I change the implementation to a
> server-implementation if they are in the interface of the TaskContex's I
> want to export over CAN (using commands() and ports()). I was hoping I
> could do the same thing with Events. The problem is that the objects
> stored in the EventService, returned by events(), are already
> implementations. So I can't just change them can I? Or are the shared
> pointers smart enough to handle this?

I'll have to look into this. You can use Event::operator= to assign a new
implementation before adding the event to the EventService (before
events()->addEvent( &e ) or after you get the Event (this completely removes
the old function then) and there is also an Event constructor which accepts
the implementation. You may change the implementation of an Event (about) at
any time. I don't fully understand your case yet though.

Do you need both local and remote delivery implementations of the Event ?

Peter

RE: RTT::Events

> >
> > void CLocalEventProxy::operator()()
> > {
> > if(m_El)
> > m_El->sendEvent(m_Id); //--> send a CAN message.
> > this->emit();
> > }
>
> Interesting, using a command for emiting events.
>
It is not a command, it is a plain c++ function.

>
> I'll have to look into this. You can use Event::operator= to
assign a
> new
> implementation before adding the event to the EventService (before
> events()->addEvent( &e ) or after you get the Event (this completely
> removes
> the old function then) and there is also an Event constructor which
> accepts
> the implementation. You may change the implementation of an Event
(about)
> at
> any time. I don't fully understand your case yet though.
>
Ok, I'll try to clarify.

For real-time communication between components on different platforms I
use a CAN network. Platform A has Component1 with its peer a proxy of
Component2, platform B just has a server jacket for Component2 and a
actual Component2. A proxy is a lightweight equivalent of a component
that just forwards the Command/Ports/Events to/from the CAN network. The
server jacket is pretty much the same as a Proxy except that it is
constructed in run-time. The server jacket inspects a component and
creates access points for the Commands/Ports/Events to the CAN network.
In the end the Proxy and server jacket connect Component1 and Component2
as if they where on the same platform.

It is in the server jacket I'm in trouble. I can get the events of
Component2 but I have to change their implementation in run-time!

> Do you need both local and remote delivery implementations of the
Event ?
>
Yes, I think I do. Lets say there are three components, two on one
platform a third on a second platform. A component on the first platform
emits an Event both other components are interested in. Then the Event
should be emitted on both platforms.

Sander.

RTT::Events

On Monday 14 May 2007 14:13:27 Vandenbroucke Sander wrote:
> Ok, I'll try to clarify.
>
> For real-time communication between components on different platforms I
> use a CAN network. Platform A has Component1 with its peer a proxy of
> Component2, platform B just has a server jacket for Component2 and a
> actual Component2. A proxy is a lightweight equivalent of a component
> that just forwards the Command/Ports/Events to/from the CAN network. The
> server jacket is pretty much the same as a Proxy except that it is
> constructed in run-time. The server jacket inspects a component and
> creates access points for the Commands/Ports/Events to the CAN network.
> In the end the Proxy and server jacket connect Component1 and Component2
> as if they where on the same platform.
>
> It is in the server jacket I'm in trouble. I can get the events of
> Component2 but I have to change their implementation in run-time!

So if a component gets served, its events should start broadcasting on your
CAN bus, but if not, it should only broadcast locally.

Doesn't this resemble DataPorts ? Or don't you publish/push data port changes
on your bus (only pull model) ?

The only solution I see for now is to initialise your served component's
events with an implementation that always tries to publish the event on the
CAN bus, in fact, the Proxy implementation.

The broadcast nature of ports and events cause this problem and it can only be
solved by installing an implementation which does the broadcast locally and
on the network.

Peter

RE: RTT::Events

>
> Indeed. You only changed the local pointer, nothing in the
EventService.
> You
> can 'hack' around this by doing:
>
> if((EvntVoid =
> boost::dynamic_pointer_cast
> (EvntImpl))!=0)
> {
> // first remove the old event
> Tc->events()->remove( (*i) );
> //Now change its implementation.
> EvntVoid = EventProxy(Tc->getName(), (*i));
> // Install new event.
> Tc->events()->addEvent( EvntVoid );
> }
>
> This solution removes any previously added event handler though.
>

Is there any way to copy them?

Sander.

RE: RTT::Events

Quoting Vandenbroucke Sander <Sander [dot] Vandenbroucke [..] ...>:
>>
>> This solution removes any previously added event handler though.
>>
>
> Is there any way to copy them?
>

That was a though question :-) Technically, the 'connections' list can
be copied into the new implementation as long as the new implementation
uses the same connection type. But the current class is not foreseen on
this scenario. First, when you delete the old implementation, it
destroys all the existing connections. Second, the connection list is a
protected member, thus another implementation can not access it. Third,
each connection object holds a pointer to its event implementation,
which must be changed as well when the implementation changes. The
easiest solution would be to clone() each connection of the connection
list into a new event and provide clone() with the pointer to the new
implementation.

All these issues can be solved by adding the appropriate member
functions, but I don't know if you can wait until RTT 1.4.0 :-)

If this is urgent, I can see if I can figure out a quick patch and test case.

Peter

RTT::Events

On Monday 17 November 2008 10:35:54 Vandenbroucke Sander wrote:
> > > I can leave this check out?
> >
> > It looks like you can (the callback lock-free list is thread-safe).
>
> But we
>
> > need to unit test to be sure.
> >
> > Peter
>
> Could you test this?

I wrote a unit test which exposes your bug. With removing the 'emitting' flag,
the code crashes, so it appears to be not that simple. I'm trying to resurrect
the rt_list implementation which could do without this flag, but I didn't have
much success yet. (see attachment)

Peter

RE: RTT::Events

> So if a component gets served, its events should start broadcasting on
> your
> CAN bus, but if not, it should only broadcast locally.
>
Yes.

> Doesn't this resemble DataPorts ?
Yes, but changing the implementation afterwards for DataPorts is easy.

>Or don't you publish/push data port
> changes
> on your bus (only pull model) ?
>
Nope, it't push/pull.

> The only solution I see for now is to initialise your served
component's
> events with an implementation that always tries to publish the event
on
> the
> CAN bus, in fact, the Proxy implementation.
>
After goofing around with the EventService and changing implementation
(which didn't work) I tend to agree.

I tried:
boost::shared_ptr EvntImpl =
Tc->events()->getEvent((*i)); //-> (*i) is a name of an
Event.

boost::shared_ptr > EvntVoid;
boost::shared_ptr > EvntVU32;
if((EvntVoid =
boost::dynamic_pointer_cast
>(EvntImpl))!=0)
{
//Now change its implementation.
EvntImpl = EventProxy(Tc->getName(), (*i));
}
But this seems to leave the original implementation in place for the
Event object in my served component.

> The broadcast nature of ports and events cause this problem and it can
> only be
> solved by installing an implementation which does the broadcast
locally
> and
> on the network.
>
Indeed. I'll try that tomorrow.

Sander.

RTT::Events

On Monday 14 May 2007 16:48:15 Vandenbroucke Sander wrote:
>
> After goofing around with the EventService and changing implementation
> (which didn't work) I tend to agree.
>
> I tried:
> boost::shared_ptr EvntImpl =
> Tc->events()->getEvent((*i)); //-> (*i) is a name of an
> Event.
>
> boost::shared_ptr > EvntVoid;
> boost::shared_ptr > EvntVU32;
> if((EvntVoid =
> boost::dynamic_pointer_cast
>
> >(EvntImpl))!=0)
>
> {
> //Now change its implementation.
> EvntImpl = EventProxy(Tc->getName(), (*i));
> }
> But this seems to leave the original implementation in place for the
> Event object in my served component.

Indeed. You only changed the local pointer, nothing in the EventService. You
can 'hack' around this by doing:

if((EvntVoid =
boost::dynamic_pointer_cast
(EvntImpl))!=0)
{
// first remove the old event
Tc->events()->remove( (*i) );
//Now change its implementation.
EvntVoid = EventProxy(Tc->getName(), (*i));
// Install new event.
Tc->events()->addEvent( EvntVoid );
}

This solution removes any previously added event handler though.

Peter