From: Warren on
On Aug 4, 1:14 pm, "Dmitry A. Kazakov" <mail...(a)dmitry-kazakov.de>
wrote:
> On Wed, 4 Aug 2010 09:40:29 -0700 (PDT), Warren wrote:
> > I some types defined as:
>
> >   type Thread_Context is private;
>
> pragma Convention (C, Thread_Context);

Let's not worry about the arguments. The WinAVR or even AVR-GCC
is very gnat specific. System.Address is all I need where argument
pointers are required.

> > Because this part of the Ada code is not working, I'm suspicious that
> > the passed function pointer is incorrect (I have an all-C thread
> > example working).
>
> You have to pass a pointer to a procedure of C convention. You also must
> ensure that other parameters aren't passed by copy.

The only problem to be solved is the function pointer for the C
code (ignoring portability of course). The C side is going to
set up its stack and registers and then invoke the Ada side. I
have this working in pure C, but when I try to launch an Ada
thread, things seem to fall apart.

Warren
From: Warren on
On Aug 4, 2:46 pm, Jeffrey Carter <spam.jrcarter....(a)spam.not.acm.org>
wrote:
> On 08/04/2010 09:40 AM, Warren wrote:

> > and an Ada API function:
>
> >      procedure Thread_Start(Context : out Thread_Context; Proc :
> > Thread_Proc; Stack : out Stack_Area) is
....
> > Is it vital that the Thread_Proc procedure also be declared as
>
> > pragma import(C,Proc) ?

Actually, I had meant to say here:

> > pragma EXPORT(C,Proc) ?

> > I'd prefer not to, if possible.

> I'm presuming that you want Ada to call Thread_Start and not need to take
> special steps because Thread_Start calls some C.

Yes, that is correct. This is to become a thick binding in WinAVR to
provide some limited threading capability.

> The 1st step is to translate the C side into something meaningful. "uint8_t*"
> can mean a host of things:

I'm not worried about the data args - for AVR it is sufficient that
I use System.Address. This is very gnat specific code.

> procedure Thread_Start(Context :    out Thread_Context;
>                         Proc    : in     Thread_Proc;
>                         Stack   :    out Stack_Area)
> is
>     type C_Context is ...;
>     -- Something C-compatible that corresponds to the C
>     -- definition of avr_thread_context, using only
>     -- convention-C components.
>     pragma Convention (C, C_Context);
>
>     procedure Local_Proc is
>        -- null;
>     begin -- Local_Proc
>        Proc.all;
>     end Local_Proc;
>     pragma Convention (C, Local_Proc);
...
> I presume Thread_Context is not opaque and its contents are accessed on the Ada
> side. Otherwise you may be able to get away with a convention-C pointer to
> Thread_Context.

It is opaque, and all I need to pass is a pointer (System.Address is
sufficient for this). I just need to be careful that I allocate
sufficient space to it.

> Are Context and Stack really needed outside Thread_Start?

Oh yes- that's where the thread state and saved registers go,
(in Context) when there is a thread switch etc. The data area
Stack is the allocated RAM you're going to give as the thread's
stack. So once the thread launches, this area must not move
or get re-used, because the thread will be stomping through it.

The Local_Proc idea is intriguing, but the problem is that the
calling procedure (Thread_Start) may have returned before that
new thread actually gets started. However, it has suggested
a couple of ideas.

If the Thread_Start were to wait for the new thread to signal
an event, then the Thread_Start could suspend until the new
thread starts. The downside is the added complexity.

OTOH, I could create a Thread_Context that is larger than what
the C routines expect. The Ada side will always be the one
setting aside the Context and Stack space. So I suppose I could
stuff an Ada procedure access (ptr) in it, and have a
C convention proc (in Ada) invoke that, acting as the
trampoline. It just wastes a little more space but is
simple to do.

I was hoping there was a more elegant gnat solution though.

Warren
From: Warren on
On Aug 4, 3:46 pm, Simon Wright <si...(a)pushface.org> wrote:
> I would be a bit worried about Thread_Proc's *Ada* environment. There's
> this thing called the Secondary Stack, used for - for example - string
> catenation; and it's not set up here.

Yikes, that could be a problem. I vaguely remember something about
a "secondary stack". I'm going to need to research this.

> I think you'll be OK so long as you restrain yourself! Twiddling LEDs
> should be OK.

Well LED twiddling is just the "hello world" test. I hope to do
a lot more than that, down the road!

> There may be a pragma to prevent secondary stack usage?

I'm all ears! ;-)

Warren

From: Rolf on
On 5 Aug., 02:45, Warren <ve3...(a)gmail.com> wrote:
> On Aug 4, 3:46 pm, Simon Wright <si...(a)pushface.org> wrote:
>
> > I would be a bit worried about Thread_Proc's *Ada* environment. There's
> > this thing called the Secondary Stack, used for - for example - string
> > catenation; and it's not set up here.
>
> Yikes, that could be a problem. I vaguely remember something about
> a "secondary stack".  I'm going to need to research this.

The current version of AVR-Ada does not support the secondary stack.
It is required for returning unconstrained objects from functions.
Using unconstrained arrays already consumes so much of the valuable
RAM that I never felt the need to support returning these objects from
functions.

BTW, GNAT-AVR (GPL 2010) from Adacore supports the secondary stack
(and some other Ada features currently missing in AVR-Ada).

> > I think you'll be OK so long as you restrain yourself! Twiddling LEDs
> > should be OK.

You can write quite complex programs without returning unconstrained
objects!

>
> Well LED twiddling is just the "hello world" test.  I hope to do
> a lot more than that, down the road!
>
> > There may be a pragma to prevent secondary stack usage?
>
> I'm all ears! ;-)

pragma Restrictions (No_Secondary_Stack);

It is already active if you use AVR-Ada. See the file gnat.adc

Rolf
From: Warren on
On Aug 5, 3:33 am, Rolf <rolf.ebert_nosp...(a)gmx.net> wrote:
> On 5 Aug., 02:45, Warren <ve3...(a)gmail.com> wrote:
>
> > On Aug 4, 3:46 pm, Simon Wright <si...(a)pushface.org> wrote:
>
> > > I would be a bit worried about Thread_Proc's *Ada* environment. There's
> > > this thing called the Secondary Stack, used for - for example - string
> > > catenation; and it's not set up here.
>
> > Yikes, that could be a problem. I vaguely remember something about
> > a "secondary stack".  I'm going to need to research this.
>
> The current version of AVR-Ada does not support the secondary stack.
> It is required for returning unconstrained objects from functions.
> Using unconstrained arrays already consumes so much of the valuable
> RAM that I never felt the need to support returning these objects from
> functions.

Thanks Rolf!

If I hard code the call to the Ada proc from the start thread in the
C code, the threaded code works great now (in Ada!) So I just got to
work out this business of the C function pointer.

The other issue I have is to sort out the declaration of the Context
object in Ada. If I declare the context in C, things go well.

Attempting to get the C_Context_Type declared correctly is proving
to be a challenge. Here is what I have:

-- typedef enum {
-- ats_normal,
-- ats_wait,
-- ats_clear = 0x40,
-- ats_tick = 0x80
-- } __attribute__((packed)) avr_thread_state;
--
-- typedef struct avr_thread_context {
-- volatile avr_thread_state state;
-- uint8_t* stack_ptr;
-- volatile struct avr_thread_context* next;
-- volatile int16_t timeout;
-- volatile void* waiting_for;
-- volatile struct avr_thread_context* next_waiting;
-- volatile struct avr_thread_context* prev_waiting;
-- } avr_thread_context;

type C_Context_Type is
record
State : Unsigned_16;
Stack_Pointer : System.Address;
Next : System.Address;
Timeout : Unsigned_16;
Waiting_For : System.Address;
Next_Waiting : System.Address;
Prev_Waiting : System.Address;
end record;

pragma Convention(C,C_Context_Type);
pragma Pack(C_Context_Type);
for C_Context_Type'Size use 16;

Keep in mind I am NOT interested in using the members of
C_Context_Type, but simply trying to set aside storage
that would match the C declaration (in bytes). I've
also tried declaring arrays, but I get a similar
experience (dope vectors etc. balloon the space).

When I compile the above, I get the complaint:

avr_threads.ads:58:33: size for "C_Context_Type" too small, minimum
allowed is 112

112 bytes - yikers! How do I get this right?

Warren