RTT 2.0 & requiring condition variable support from the OS

I'm pick-axing through the new method call/send/collect implementation. I'll
resume shortly what this is about. When your component implements a function
(aka service or operation) it can indicate if it has to be executed in the
clients thread (old method behavior) or its own thread (old command behavior).
This is a decision the component writers keeps for himself, the caller of this
function can not see this difference, and multiple components may choose
differently. What the caller can decide is that when he invokes such an
operation, to do this synchronously or asynchronously. This translates to
these two cases:


// user of component function 'setParam':
Method<Result(double)> setParam = ... ;
// block for result, which is a user type:
Result result = setParam.call(3.0); // may be abbrev. to setParam(3.0)

// do not block:
Result result2;
SendHandle<Result(double)> handle;
handle = setParam.send(3.0);

// some time later, collect the return value:
SendStatus ss1 = handle.collect( result2 ); // blocks
// or:
SendStatus ss2 = handle.collectIfDone( result2 ); // polls.
// a third variant with a timeout is possible too:
SendStatus ss2 = handle.collect_timed( result2, timeout );//blocks w/ timeout


A fourth option is to call a call-back when the function was executed:

// one callback function for all calls to the method:
setParam.callback( &function );
setParam.send( 3.0 );
// function(Result r) will be called when setParam completed.


While this is a simple and may I say, intuitive, API, the implementation
requires way more from the OS in comparison to the 1.x functionality we offer.
More specifically, for in-process communication, we require condition variables
to implement call(), collect() and collect_timed(). There will be one
condition variable and one mutex for each ExecutionEngine to mediate the race
conditions that may occur when concurrently calling collect() while executing
the component's operation that was 'send'.

LXRT, Xenomai, GNU/Linux support this, Windows XP/2003 seems not to, but the
boost::thread library seems to have a way to work around that, since it offers
condition variables on Windows too.

An OS that does not support condition variables would allow applications only
to call send(), collectIfDone() and callback() in case of asynchronous
operations. call(), collect() and collect_timed() could be 'emulated' by a
periodically polling implementation though.

I didn't forsee this requirement when proposing the above API. I think the API
justifies such a requirement on the RTOS, but I wanted to give any opposing
views the opportunity to speak before settings things in stone.

Peter

RTT 2.0 & requiring condition variable support from the OS

On Mon, Jan 11, 2010 at 11:32:07AM +0100, Peter Soetens wrote:
> I'm pick-axing through the new method call/send/collect implementation. I'll
> resume shortly what this is about. When your component implements a function
> (aka service or operation) it can indicate if it has to be executed in the
> clients thread (old method behavior) or its own thread (old command behavior).

What exactly is done with this information? Is used to limit the
"modes" in which the operation is allowed to be used?

> This is a decision the component writers keeps for himself, the caller of this
> function can not see this difference, and multiple components may choose
> differently. What the caller can decide is that when he invokes such an
> operation, to do this synchronously or asynchronously. This translates to
> these two cases:

So if I execute and operation and the offering Component has indicated
it can not be executed in this mode, the call fails?

> 
> // user of component function 'setParam':
> Method<Result(double)> setParam = ... ;
> // block for result, which is a user type:
> Result result = setParam.call(3.0); // may be abbrev. to setParam(3.0)
> 
> // do not block:
> Result result2;
> SendHandle<Result(double)> handle;
> handle = setParam.send(3.0);
> 
> // some time later, collect the return value:
> SendStatus ss1 = handle.collect( result2 ); // blocks
> // or:
> SendStatus ss2 = handle.collectIfDone( result2 ); // polls.
> // a third variant with a timeout is possible too:
> SendStatus ss2 = handle.collect_timed( result2, timeout );//blocks w/ timeout
>

I like it!

> A fourth option is to call a call-back when the function was executed:
> 
> // one callback function for all calls to the method:
> setParam.callback( &function );
> setParam.send( 3.0 );
> // function(Result r) will be called when setParam completed.
>

Why make the callback an "obscure" C level function and not an
exported Operation? That would allow to direct the callback to
somewhere else, although I don't know if that would be a good idea...

> While this is a simple and may I say, intuitive, API, the implementation
> requires way more from the OS in comparison to the 1.x functionality we offer.
> More specifically, for in-process communication, we require condition variables
> to implement call(), collect() and collect_timed(). There will be one
> condition variable and one mutex for each ExecutionEngine to mediate the race
> conditions that may occur when concurrently calling collect() while executing
> the component's operation that was 'send'.
>
> LXRT, Xenomai, GNU/Linux support this, Windows XP/2003 seems not to, but the
> boost::thread library seems to have a way to work around that, since it offers
> condition variables on Windows too.
>
> An OS that does not support condition variables would allow applications only
> to call send(), collectIfDone() and callback() in case of asynchronous
> operations. call(), collect() and collect_timed() could be 'emulated' by a
> periodically polling implementation though.
>
> I didn't forsee this requirement when proposing the above API. I think the API
> justifies such a requirement on the RTOS, but I wanted to give any opposing
> views the opportunity to speak before settings things in stone.

So all currently supported OS either offer the functionality or you
have an workaround. So where's the problem? Or do have you a
particular not-yet-supported OS in mind which has condition variables?

Markus

RTT 2.0 & requiring condition variable support from the OS

On Monday 11 January 2010 13:27:05 Markus Klotzbuecher wrote:
> On Mon, Jan 11, 2010 at 11:32:07AM +0100, Peter Soetens wrote:
> > I'm pick-axing through the new method call/send/collect implementation.
> > I'll resume shortly what this is about. When your component implements a
> > function (aka service or operation) it can indicate if it has to be
> > executed in the clients thread (old method behavior) or its own thread
> > (old command behavior).
>
> What exactly is done with this information? Is used to limit the
> "modes" in which the operation is allowed to be used?

Not at all. The operation can be used in all cases (send/call). It is used to
choose an implementation that relays the client call to the actual function.

>
> > This is a decision the component writers keeps for himself, the caller of
> > this function can not see this difference, and multiple components may
> > choose differently. What the caller can decide is that when he invokes
> > such an operation, to do this synchronously or asynchronously. This
> > translates to these two cases:
>
> So if I execute and operation and the offering Component has indicated
> it can not be executed in this mode, the call fails?

No. it's not a restriction, it's a policy. When the component indicates
'client thread', call() will relay directly to the operation's function. If
the component states 'own thread', call() will boil down to an internal send()
and a collect(). In the case of 'client thread' and send(), a third thread
needs to be assigned that will execute the operation on behalf of the
component.

>
> > 
> > // user of component function 'setParam':
> > Method<Result(double)> setParam = ... ;
> > // block for result, which is a user type:
> > Result result = setParam.call(3.0); // may be abbrev. to setParam(3.0)
> >
> > // do not block:
> > Result result2;
> > SendHandle<Result(double)> handle;
> > handle = setParam.send(3.0);
> >
> > // some time later, collect the return value:
> > SendStatus ss1 = handle.collect( result2 ); // blocks
> > // or:
> > SendStatus ss2 = handle.collectIfDone( result2 ); // polls.
> > // a third variant with a timeout is possible too:
> > SendStatus ss2 = handle.collect_timed( result2, timeout );//blocks w/
> > timeout
>
> I like it!
>
> > A fourth option is to call a call-back when the function was executed:
> > 
> > // one callback function for all calls to the method:
> > setParam.callback( &function );
> > setParam.send( 3.0 );
> > // function(Result r) will be called when setParam completed.
> >
>
> Why make the callback an "obscure" C level function and not an
> exported Operation? That would allow to direct the callback to
> somewhere else, although I don't know if that would be a good idea...

The callback is very likely to be a boost::function object which can store any
callable, not just a C function. We can add overloads or utility functions
that convert some generic functor into boost::function.

>
> > While this is a simple and may I say, intuitive, API, the implementation
> > requires way more from the OS in comparison to the 1.x functionality we
> > offer. More specifically, for in-process communication, we require
> > condition variables to implement call(), collect() and collect_timed().
> > There will be one condition variable and one mutex for each
> > ExecutionEngine to mediate the race conditions that may occur when
> > concurrently calling collect() while executing the component's operation
> > that was 'send'.
> >
> > LXRT, Xenomai, GNU/Linux support this, Windows XP/2003 seems not to, but
> > the boost::thread library seems to have a way to work around that, since
> > it offers condition variables on Windows too.
> >
> > An OS that does not support condition variables would allow applications
> > only to call send(), collectIfDone() and callback() in case of
> > asynchronous operations. call(), collect() and collect_timed() could be
> > 'emulated' by a periodically polling implementation though.
> >
> > I didn't forsee this requirement when proposing the above API. I think
> > the API justifies such a requirement on the RTOS, but I wanted to give
> > any opposing views the opportunity to speak before settings things in
> > stone.
>
> So all currently supported OS either offer the functionality or you
> have an workaround. So where's the problem? Or do have you a
> particular not-yet-supported OS in mind which has condition variables?

I didn't check ecos, and can't tell for users using in-house developed
rtos'es.

Peter

RTT 2.0 & requiring condition variable support from the OS

On Mon, Jan 11, 2010 at 03:41:07PM +0100, Peter Soetens wrote:
> On Monday 11 January 2010 13:27:05 Markus Klotzbuecher wrote:
> > On Mon, Jan 11, 2010 at 11:32:07AM +0100, Peter Soetens wrote:
> > > I'm pick-axing through the new method call/send/collect implementation.
> > > I'll resume shortly what this is about. When your component implements a
> > > function (aka service or operation) it can indicate if it has to be
> > > executed in the clients thread (old method behavior) or its own thread
> > > (old command behavior).
> >
> > What exactly is done with this information? Is used to limit the
> > "modes" in which the operation is allowed to be used?
>
> Not at all. The operation can be used in all cases (send/call). It is used to
> choose an implementation that relays the client call to the actual function.

I see.

> >
> > > This is a decision the component writers keeps for himself, the caller of
> > > this function can not see this difference, and multiple components may
> > > choose differently. What the caller can decide is that when he invokes
> > > such an operation, to do this synchronously or asynchronously. This
> > > translates to these two cases:
> >
> > So if I execute and operation and the offering Component has indicated
> > it can not be executed in this mode, the call fails?
>
> No. it's not a restriction, it's a policy. When the component indicates
> 'client thread', call() will relay directly to the operation's function. If
> the component states 'own thread', call() will boil down to an internal send()
> and a collect(). In the case of 'client thread' and send(), a third thread
> needs to be assigned that will execute the operation on behalf of the
> component.

So which thread is used is defined by the component which offers the
operation the side and the blocking/non blocking behaviour (naturally)
by the caller. Isn't the first rather a deployment parameter? I'm a
bit in doubt if a component developer can decide that at that time.

Markus

RTT 2.0 & requiring condition variable support from the OS

[...]
>> So all currently supported OS either offer the functionality or you
>> have an workaround. So where's the problem? Or do have you a
>> particular not-yet-supported OS in mind which has condition variables?
>
> I didn't check ecos, and can't tell for users using in-house developed
> rtos'es.

<http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man3/pthread.3.html>
<http://ecos.sourceware.org/docs-3.0/ref/kernel-condition-variables.html>

k