comp.lang.ada
 help / color / mirror / Atom feed
* Passing Ada Proc as a C Function Pointer
@ 2010-08-04 16:40 Warren
  2010-08-04 17:14 ` Dmitry A. Kazakov
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Warren @ 2010-08-04 16:40 UTC (permalink / raw)


I some types defined as:

  type Thread_Context is private;
  type Stack_Area is new String;
  type Thread_Proc is access procedure;

and an Ada API function:

    procedure Thread_Start(Context : out Thread_Context; Proc :
Thread_Proc; Stack : out Stack_Area) is
        type C_Func_Ptr is access procedure;
        pragma Convention(Convention => C, Entity => C_Func_Ptr);

        procedure avr_thread_start(Context : System.Address;
                    Proc : C_Func_Ptr;
                    Stack : System.Address;
                    Size : Unsigned_16);
        pragma import(C,avr_thread_start,"avr_thread_start");

        Func : C_Func_Ptr := Proc.all'Access;
    begin

 
avr_thread_start(Context'Address,Func,Stack(Stack'First)'Address,Stack'Length);

    end Thread_Start;

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).

Is it vital that the Thread_Proc procedure also be declared as

pragma import(C,Proc) ?

I'd prefer not to, if possible.

There are no arguments passed-- I only need to launch the passed
Ada procedure from the C side (in a thread).

The avr_thread_start C routine is declared as:

void avr_thread_start(
  avr_thread_context* context,
  void (*fn)(void),
  uint8_t* stack,
  uint16_t stack_size
);

Warren



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-04 16:40 Warren
@ 2010-08-04 17:14 ` Dmitry A. Kazakov
  2010-08-05  0:24   ` Warren
  2010-08-04 18:46 ` Jeffrey Carter
  2010-08-04 19:46 ` Simon Wright
  2 siblings, 1 reply; 14+ messages in thread
From: Dmitry A. Kazakov @ 2010-08-04 17:14 UTC (permalink / raw)


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);

>   type Stack_Area is new String;

pragma Convention (C, Stack_Area);  -- Won't work with String

>   type Thread_Proc is access procedure;

pragma Convention (C, Thread_Proc);  -- Called from C
 
> and an Ada API function:
> 
>     procedure Thread_Start(Context : out Thread_Context;

Context : access Thread_Context;
    -- Prevent temp object, if the type is not limited

> Proc : Thread_Proc;
> Stack : out Stack_Area) is

Stack : access Stack_Area

>         procedure avr_thread_start(Context : System.Address;
>                     Proc : C_Func_Ptr;

Proc : Thread_Proc;

>                     Stack : System.Address;
>                     Size : Unsigned_16);
>         pragma import(C,avr_thread_start,"avr_thread_start");
> 
>         Func : C_Func_Ptr := Proc.all'Access;
>     begin
> 
> avr_thread_start(Context'Address,Func,Stack(Stack'First)'Address,Stack'Length);
> 
>     end Thread_Start;
> 
> 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.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-04 16:40 Warren
  2010-08-04 17:14 ` Dmitry A. Kazakov
@ 2010-08-04 18:46 ` Jeffrey Carter
  2010-08-04 19:36   ` Dmitry A. Kazakov
  2010-08-05  0:42   ` Warren
  2010-08-04 19:46 ` Simon Wright
  2 siblings, 2 replies; 14+ messages in thread
From: Jeffrey Carter @ 2010-08-04 18:46 UTC (permalink / raw)


On 08/04/2010 09:40 AM, Warren wrote:
> I some types defined as:
>
>    type Thread_Context is private;
>    type Stack_Area is new String;
>    type Thread_Proc is access procedure;
>
> and an Ada API function:
>
>      procedure Thread_Start(Context : out Thread_Context; Proc :
> Thread_Proc; Stack : out Stack_Area) is
>          type C_Func_Ptr is access procedure;
>          pragma Convention(Convention =>  C, Entity =>  C_Func_Ptr);
>
>          procedure avr_thread_start(Context : System.Address;
>                      Proc : C_Func_Ptr;
>                      Stack : System.Address;
>                      Size : Unsigned_16);
>          pragma import(C,avr_thread_start,"avr_thread_start");
>
>          Func : C_Func_Ptr := Proc.all'Access;
>      begin
>
>
> avr_thread_start(Context'Address,Func,Stack(Stack'First)'Address,Stack'Length);
>
>      end Thread_Start;
>
> 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).
>
> Is it vital that the Thread_Proc procedure also be declared as
>
> pragma import(C,Proc) ?
>
> I'd prefer not to, if possible.
>
> There are no arguments passed-- I only need to launch the passed
> Ada procedure from the C side (in a thread).
>
> The avr_thread_start C routine is declared as:
>
> void avr_thread_start(
>    avr_thread_context* context,
>    void (*fn)(void),
>    uint8_t* stack,
>    uint16_t stack_size
> );

I'm presuming that you want Ada to call Thread_Start and not need to take 
special steps because Thread_Start calls some C. In that case, you should ignore 
most of what Kazakov said: The Ada-side declarations should not reflect the 
implementation.

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

  * in     uint8_t (uncommon)
  * in out uint8_t
  * out    uint8_t
  * in     array_of_uint8_t
  * in out array_of_uint8_t
  * out    array_of_uint8_t

I'll presume from your use of "out" that "context" and "stack" are "out", and 
from your use of "new String" that "stack" is an array.

Next, you need to use convention-C types for your C parameters. There is no 
guarantee that System.Address corresponds to a C pointer; if you're at all 
interested in compiler portability, you won't use it. You also won't use "new 
String" for the "uint8_t*" parameter.

So I'd do something like (untested):

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);

    subtype Stack_String is Stack_Area (Stack'range);

    type U8 is mod 2 ** 8;
    pragma Convention (C, U8);

    type U8_List is array (Stack'range) of U8;
    pragma Convention (C, U8_List);

    type U16 is mod 2 ** 16;
    pragma Convention (C, U16);

    procedure AVR_Thread_Start (Context :    out C_Context;
                                Proc    : access procedure;
                                Stack   :    out U8_List;
                                Size    : in     U16);
    pragma Import (C, AVR_Thread_Start, "avr_thread_start");

    Local_Context : C_Context;
    Local_Stack   : U8_List;

    -- function To_Thread_Context (From : C_Context) return Thread_Context;
    --
    -- function To_Stack_Area (From : U8_List) return Stack_String;
    -- Implementations left as exercises for the reader.
begin -- Thread_Start
    AVR_Thread_Start (Context => Local_Context,
                      Proc    => Local_Proc'access,
                      Stack   => Local_Stack,
                      Size    => Local_Stack'Length);
    Context := To_Thread_Context (Local_Context);
    Stack   := To_Stack_Area (Local_Stack);
end Thread_Start;

Ada will pass Stack as a "U8*" pointing to the first component and Context as an 
appropriate pointer; see ARM B.3.

Local_Context and Local_Stack give us convention-C objects to pass; Local_Proc a 
convention-C procedure that C may call.

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.

Are Context and Stack really needed outside Thread_Start?

-- 
Jeff Carter
"Ah, go away or I'll kill ya."
Never Give a Sucker an Even Break
100

--- news://freenews.netfront.net/ - complaints: news@netfront.net ---



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-04 18:46 ` Jeffrey Carter
@ 2010-08-04 19:36   ` Dmitry A. Kazakov
  2010-08-05  0:42   ` Warren
  1 sibling, 0 replies; 14+ messages in thread
From: Dmitry A. Kazakov @ 2010-08-04 19:36 UTC (permalink / raw)


On Wed, 04 Aug 2010 11:46:56 -0700, Jeffrey Carter wrote:

> procedure Thread_Proc :    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 am not sure if this works everywhere. The problem is that Local_Proc
refers to a local variable Proc (formal parameter of Thread_Start). This
needs some special techniques on the compiler side to become C-conform,
e.g. a trampoline.

Local_Proc should be moved out of Thread_Proc.

Then a copy of Proc is created in the scope of. That would be not task safe
without a protected object around the copy of Proc.

Another way could be passing a copy of Proc on Thread_Context.

But IMO there is nothing with putting C conventions on Ada callbacks. All
bindings I know, use it without hesitation.

> Are Context and Stack really needed outside Thread_Start?

In any case they need to be collected upon thread completion. Therefore
they must come from outside (unless Thread_Proc could free them, which is
unlikely).

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-04 16:40 Warren
  2010-08-04 17:14 ` Dmitry A. Kazakov
  2010-08-04 18:46 ` Jeffrey Carter
@ 2010-08-04 19:46 ` Simon Wright
  2010-08-05  0:45   ` Warren
  2 siblings, 1 reply; 14+ messages in thread
From: Simon Wright @ 2010-08-04 19:46 UTC (permalink / raw)


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.

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

There may be a pragma to prevent secondary stack usage?



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-04 17:14 ` Dmitry A. Kazakov
@ 2010-08-05  0:24   ` Warren
  0 siblings, 0 replies; 14+ messages in thread
From: Warren @ 2010-08-05  0:24 UTC (permalink / raw)


On Aug 4, 1:14 pm, "Dmitry A. Kazakov" <mail...@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



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-04 18:46 ` Jeffrey Carter
  2010-08-04 19:36   ` Dmitry A. Kazakov
@ 2010-08-05  0:42   ` Warren
  2010-08-05  0:55     ` Warren
  1 sibling, 1 reply; 14+ messages in thread
From: Warren @ 2010-08-05  0:42 UTC (permalink / raw)


On Aug 4, 2:46 pm, Jeffrey Carter <spam.jrcarter....@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



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-04 19:46 ` Simon Wright
@ 2010-08-05  0:45   ` Warren
  2010-08-05  7:33     ` Rolf
  0 siblings, 1 reply; 14+ messages in thread
From: Warren @ 2010-08-05  0:45 UTC (permalink / raw)


On Aug 4, 3:46 pm, Simon Wright <si...@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




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-05  0:42   ` Warren
@ 2010-08-05  0:55     ` Warren
  0 siblings, 0 replies; 14+ messages in thread
From: Warren @ 2010-08-05  0:55 UTC (permalink / raw)


On Aug 4, 8:42 pm, Warren <ve3...@gmail.com> wrote:
..
> 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.

Crap! That won't work either because the thread starting up
doesn't know its own context object location.  At least with
the current avr_threads API ;-)

I was trying to avoid modifying the avr_thread code. What it
really needs is a user_data parameter.

Hmmmm...

It seems it boils down to 3 choices:

1) Have the starting thread signal the called thread, when it has
"launched".
2) Add a "avr_get_current_thread" routine to return the current
context object.
3) Add a "avr_start_ada_thread" function, which provides the context
object as one of the local_proc arguments. The it can thunk with a
call to context.ada_access_ptr.all;

Only #1 works without changing the avr_threads C library.  Maybe I'll
try that approach first.

Warren



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-05  0:45   ` Warren
@ 2010-08-05  7:33     ` Rolf
  2010-08-05 20:50       ` Simon Wright
  0 siblings, 1 reply; 14+ messages in thread
From: Rolf @ 2010-08-05  7:33 UTC (permalink / raw)


On 5 Aug., 02:45, Warren <ve3...@gmail.com> wrote:
> On Aug 4, 3:46 pm, Simon Wright <si...@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



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
@ 2010-08-05 14:31 Warren
  2010-08-05 15:37 ` Warren
  0 siblings, 1 reply; 14+ messages in thread
From: Warren @ 2010-08-05 14:31 UTC (permalink / raw)


On Aug 5, 3:33 am, Rolf <rolf.ebert_nosp...@gmx.net> wrote:
> On 5 Aug., 02:45, Warren <ve3...@gmail.com> wrote:
>
> > On Aug 4, 3:46 pm, Simon Wright <si...@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




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-05 14:31 Passing Ada Proc as a C Function Pointer Warren
@ 2010-08-05 15:37 ` Warren
  2010-08-05 16:51   ` Warren
  0 siblings, 1 reply; 14+ messages in thread
From: Warren @ 2010-08-05 15:37 UTC (permalink / raw)


On Aug 5, 10:31 am, Warren <ve3...@gmail.com> wrote:
> On Aug 5, 3:33 am, Rolf <rolf.ebert_nosp...@gmx.net> wrote:
..
> 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

Arg!!!!  Arg!!!!

I keep thinking in terms of bytes - not BITS!!  No wonder!

Warren



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-05 15:37 ` Warren
@ 2010-08-05 16:51   ` Warren
  0 siblings, 0 replies; 14+ messages in thread
From: Warren @ 2010-08-05 16:51 UTC (permalink / raw)


On Aug 5, 11:37 am, Warren <ve3...@gmail.com> wrote:
> Arg!!!!  Arg!!!!
>
> I keep thinking in terms of bytes - not BITS!!  No wonder!
>
> Warren

At long last-- it works!!!!

I ended up creating a C routine for the launch:

void
avr_thread_start_ada(
  avr_thread_context* context,
  uint8_t* stack,
  uint16_t stack_size) {
        extern void thread_thunk(void);  /* Ada in C convention */

        avr_thread_start(context,thread_thunk,stack,stack_size);
}

which is called by Start_Thread in Ada. This then invokes the usual
avr_thread_start(), which then launches the Ada (in C convention)
routine Thread_Thunk:

    procedure Thread_Thunk;
    pragma export(C,Thread_Thunk,"thread_thunk");

    procedure Thread_Thunk is
        Context : Thread_Context_Ptr := Get_Context;
    begin
        Context.Ada_Proc.all;  -- Start Ada code in new thread
    end Thread_Thunk;

There was an undocumented AVR_Threads routine in the include file
that allowed me to pick up the active context, which is used by
Ada routine binding Get_Context.

The context object turned out to be tricky because the C context
object needed to be "struct aligned", which appears to be 64-bit.
So a little work on that fixed it. I also rolled the stack into
the object as a variant record, for user convenience:

    type Thread_Context(Stack_Size : Unsigned_16) is
        record
            C_Context :     aliased C_Context_Type;
            Ada_Proc :      Thread_Proc;
            Stack :         aliased Stack_Type(1..Stack_Size);
        end record;

    for Thread_Context use
        record
            C_Context       at  0 range 0 .. 16 * 8 -1;     -- Must be
first to be 64-bit aligned
            Stack_Size      at 16 range 0 .. 15;            -- Moved
here - non critical
            Ada_Proc        at 18 range 0 .. 15;            -- Non
critical placement
        --  Stack           at 20 range 0 .. Stack_Size * 8 - 1;
        end record;

Thanks to everyone for their comments and ideas.

Warren



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Passing Ada Proc as a C Function Pointer
  2010-08-05  7:33     ` Rolf
@ 2010-08-05 20:50       ` Simon Wright
  0 siblings, 0 replies; 14+ messages in thread
From: Simon Wright @ 2010-08-05 20:50 UTC (permalink / raw)


Rolf <rolf.ebert_nospam_@gmx.net> writes:

>> > 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

One fewer thing to worry about, then!



^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2010-08-05 20:50 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-05 14:31 Passing Ada Proc as a C Function Pointer Warren
2010-08-05 15:37 ` Warren
2010-08-05 16:51   ` Warren
  -- strict thread matches above, loose matches on Subject: below --
2010-08-04 16:40 Warren
2010-08-04 17:14 ` Dmitry A. Kazakov
2010-08-05  0:24   ` Warren
2010-08-04 18:46 ` Jeffrey Carter
2010-08-04 19:36   ` Dmitry A. Kazakov
2010-08-05  0:42   ` Warren
2010-08-05  0:55     ` Warren
2010-08-04 19:46 ` Simon Wright
2010-08-05  0:45   ` Warren
2010-08-05  7:33     ` Rolf
2010-08-05 20:50       ` Simon Wright

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox