From: Warren on 4 Aug 2010 12:40 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
From: Dmitry A. Kazakov on 4 Aug 2010 13:14 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
From: Jeffrey Carter on 4 Aug 2010 14:46 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(a)netfront.net ---
From: Dmitry A. Kazakov on 4 Aug 2010 15:36 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
From: Simon Wright on 4 Aug 2010 15:46
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? |