From: Simon Wright on
"Dmitry A. Kazakov" <mailbox(a)dmitry-kazakov.de> writes:

> On 30 Jan 2006 14:12:51 -0800, Rolf wrote:

>> - I don't know much about sockets (or better I don't remember much).
>> Does a waiting read (in the second task) block a write in the first
>> task?
>
> Usually not. Note that you must wait not for a socket read, but for a
> "variable-update" event from the middleware layer.

_Something_ has to wait for a socket read! If you're writing your own
'middleware' (lower layers, anyway) that will be you.

Windows is not wonderful for this sort of thing but I have not seen
problems of the sort you describe with a task blocked on the read
(input_t'Input) and other code (either another single task, or some
sort of mutex) for output_t'Output.

>> - what other hints can you give me?
>
> Never ever use UPD, avoid TCP_NO_DELAY with TCP/IP. The first is
> unreliable for your purpose, the second quickly brings the network
> down.

Probably best to avoid these (I guess that UPD was a typo for UDP) at
the start, but sometimes they are the appropriate solution. Not often,
maybe.
From: Rolf on
Stephen Leake wrote:
> "Rolf" <rolf.ebert_nospam_(a)gmx.net> writes:
>
> > In a stripped down version I can succesfully connect to the server
> > (using GNAT.Sockets) and either read the sensor data *or* write actor
> > data. The program is currently split in two tasks. One tasks contains
> > the application code and the actor communication (using
> > type_id'output(channel)). The second tasks gets started during program
> > initialisation. It reads the data from the socket via
> > type_id'input(channel) and provides the data to the application through
> > a protected object.
> >
> > The problem that I face is that the second task seems to starve the
> > first one. As soon as it is active, the application does not generate
> > debug output anymore.
>
> You need to set the priorities correctly,

Does that mean e.g. to set the main task to 10 and the second task to
5?

> and you need to ensure that
> there are no busy waits; the second task should be _suspended_ waiting
> on socket completions, not polling for them.

How would I do that? I have no explicit busy wait, I use

Var := Sensor_Cmd_T'Input (Channel);

If possible, I'd like to keep that easy way of data input and avoid
explicit conversion and read commands.

> > Some background info: gcc-3.4.4 on Windows XP.
>
> That may be a problem. I find the commercially supported GNAT to be
> less broken.

This is a hobby project.

> > Java for the world simulation.
>
> Yuck. I assume that's not by choice?

The world simulation already exists. I won't recode it in Ada. (and I
kind of like Java, too)

> > The simulator sends about 20 packages à 11bytes every 100ms. The
> > application sends typically 2-3 packages per second.
>
> That's certainly "reasonable rates"
>

That is almost nothing!

> > I have delay statements in both main loops (varied between 0.0 and
> > 0.2 seconds).
>
> You should _not_ need delay statements. Redesign to be waiting on
> socket completions.

How?

> Or, if you are designing to a cyclic execution, you can poll on the
> sockets, but just once per cycle. You can use
> GNAT.Sockets.Control_Socket for that.
>

I shall check that.

> > My questions:
> > - is that a reasonable tasking approach?
>
> In general, yes. But the details matter a lot.
>
> > - I don't know much about sockets (or better I don't remember
> > much). Does a waiting read (in the second task) block a write in the
> > first task?
>
> Not in Windows with GNAT 5.03a. gcc-3.4.4 on Cygwin may be different.

There is no real Ada compiler on Cygwin. I use the Windows
(mingw-based) gcc-3.4.4. I shall see if GNAT GPL 2005 gives different
results.

> > - how can I interrupt the waiting read task to force activity in the
> > main task?
>
> Depends on how it is waiting. If is in a GNAT.Sockets.Receive_Socket,
> you can't (short of shutting down the socket). So periodic polling
> might be better.

I suppose it waits in the Sensor_Cmd_T'Input (Channel) routine, but I
am not sure.

> > - what other hints can you give me?
>
> Get an AdaCore support contract.
>
In a professional environment certainly, but not here ...

Rolf

From: Rolf on

tmoran(a)acm.org wrote:
> But it seems to me that if the object is to use TCP to emulate hardware,
> one should design for that hardware and do whatever is needed with UDP or
> TCP to make the best emulation. Is the intended hardware going to be
> polled or generate interrupts or Windows messages or what?

The real sensor hardware will be directly connected to the I/O pins of
the mcu. I think that counts as polling. The application code simply
reads variables from the h/w abstraction layer.

From: Stephen Leake on
"Rolf" <rolf.ebert_nospam_(a)gmx.net> writes:

> Stephen Leake wrote:
>> "Rolf" <rolf.ebert_nospam_(a)gmx.net> writes:
>>
>> > In a stripped down version I can succesfully connect to the server
>> > (using GNAT.Sockets) and either read the sensor data *or* write actor
>> > data. The program is currently split in two tasks. One tasks contains
>> > the application code and the actor communication (using
>> > type_id'output(channel)). The second tasks gets started during program
>> > initialisation. It reads the data from the socket via
>> > type_id'input(channel) and provides the data to the application through
>> > a protected object.
>> >
>> > The problem that I face is that the second task seems to starve the
>> > first one. As soon as it is active, the application does not generate
>> > debug output anymore.
>>
>> You need to set the priorities correctly,
>
> Does that mean e.g. to set the main task to 10 and the second task to
> 5?

Well, I don't know, since I don't know the details of your project.
But it is likely that one should have a higher priority than the
other. The default is for all tasks to have the same priority.

>> and you need to ensure that
>> there are no busy waits; the second task should be _suspended_ waiting
>> on socket completions, not polling for them.
>
> How would I do that? I have no explicit busy wait, I use
>
> Var := Sensor_Cmd_T'Input (Channel);
>
> If possible, I'd like to keep that easy way of data input and avoid
> explicit conversion and read commands.

Hmm. I don't know how this maps to Read_Socket commands. I would guess
that it waits for the number of Stream_Elements in Sensor_Cmd_T to be
available. But it might wait longer than that, especially if
Sensor_Cmd_T is unconstrained.

You could do a Read_Socket into a Stream_Array, and then do 'Input
from that. That would make it clearer when the task is suspended.

>> > Some background info: gcc-3.4.4 on Windows XP.
>>
>> That may be a problem. I find the commercially supported GNAT to be
>> less broken.
>
> This is a hobby project.

Ok.

>> > - how can I interrupt the waiting read task to force activity in the
>> > main task?
>>
>> Depends on how it is waiting. If is in a GNAT.Sockets.Receive_Socket,
>> you can't (short of shutting down the socket). So periodic polling
>> might be better.
>
> I suppose it waits in the Sensor_Cmd_T'Input (Channel) routine, but I
> am not sure.

There is an option that expands tasking constructs into lower-level
Ada code, and outputs the source. That may help here, to show what is
going on.

--
-- Stephe
From: Stephen Leake on
"Rolf" <rolf.ebert_nospam_(a)gmx.net> writes:

> tmoran(a)acm.org wrote:
>> But it seems to me that if the object is to use TCP to emulate hardware,
>> one should design for that hardware and do whatever is needed with UDP or
>> TCP to make the best emulation. Is the intended hardware going to be
>> polled or generate interrupts or Windows messages or what?
>
> The real sensor hardware will be directly connected to the I/O pins of
> the mcu. I think that counts as polling. The application code simply
> reads variables from the h/w abstraction layer.

How do those "variables" get set?

Does one of the IO pins generate an interrupt, that triggers the h/w
abstraction layer "read all pins" function?

Or is the h/w abstraction layer a cyclic executor, driven by a clock?

How does the application know when to read the variables? By a clock,
or some interrupt/event from the h/w abstraction layer?

--
-- Stephe