comp.lang.ada
 help / color / mirror / Atom feed
From: Jeffrey Carter <spam.jrcarter.not@spam.not.acm.org>
Subject: Re: Passing Ada Proc as a C Function Pointer
Date: Wed, 04 Aug 2010 11:46:56 -0700
Date: 2010-08-04T11:46:56-07:00	[thread overview]
Message-ID: <i3ccj1$2bnh$1@adenine.netfront.net> (raw)
In-Reply-To: <bc887840-ef75-405a-8019-8e44552a92d3@i28g2000yqa.googlegroups.com>

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



  parent reply	other threads:[~2010-08-04 18:46 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-08-04 16:40 Passing Ada Proc as a C Function Pointer Warren
2010-08-04 17:14 ` Dmitry A. Kazakov
2010-08-05  0:24   ` Warren
2010-08-04 18:46 ` Jeffrey Carter [this message]
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
  -- strict thread matches above, loose matches on Subject: below --
2010-08-05 14:31 Warren
2010-08-05 15:37 ` Warren
2010-08-05 16:51   ` Warren
replies disabled

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