comp.lang.ada
 help / color / mirror / Atom feed
* Interfacing to C: big structures
@ 2008-02-25 21:17 Maciej Sobczak
  2008-02-25 23:26 ` Randy Brukardt
                   ` (5 more replies)
  0 siblings, 6 replies; 27+ messages in thread
From: Maciej Sobczak @ 2008-02-25 21:17 UTC (permalink / raw)


Hi,

Consider the C API that contains some structure S and a couple of
functions that operate on the state that is stored in the Struct. A
typical usage in C might be:

struct S s;

init(&s);
foo(&s);
bar(&s);
baz(&s);

Above, s is created with automatic storage duration.

How to interface to this from Ada? I see two options:

1. Write a simple wrapper that will create S on the heap and use the
pointer everywhere. This is easy, but imposes the use of dynamic
memory, which for some reasons I might want to avoid.
2. Create an Ada array of basic storage units of "appropriate size"
and pass its address to the C functions. The advantage of this
solution is that it does not impose any particular memory management
scheme, but the disadvantage is that it is potentially non-portable
(how to get the "appropriate size"?).

Would you suggest some other solution?

--
Maciej Sobczak * www.msobczak.com * www.inspirel.com



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

* Re: Interfacing to C: big structures
  2008-02-25 21:17 Interfacing to C: big structures Maciej Sobczak
  2008-02-25 23:26 ` Randy Brukardt
  2008-02-25 23:26 ` Randy Brukardt
@ 2008-02-25 23:26 ` Randy Brukardt
  2008-02-27 13:23   ` Maciej Sobczak
  2008-02-25 23:43 ` Robert A Duff
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 27+ messages in thread
From: Randy Brukardt @ 2008-02-25 23:26 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message
news:c48dc7da-6f04-4f0f-9a8f-e0acc371ee3c@o10g2000hsf.googlegroups.com...
> Consider the C API that contains some structure S and a couple of
> functions that operate on the state that is stored in the Struct. A
> typical usage in C might be:
...
> How to interface to this from Ada? I see two options:
>
> 1. Write a simple wrapper that will create S on the heap and use the
> pointer everywhere. This is easy, but imposes the use of dynamic
> memory, which for some reasons I might want to avoid.
> 2. Create an Ada array of basic storage units of "appropriate size"
> and pass its address to the C functions. The advantage of this
> solution is that it does not impose any particular memory management
> scheme, but the disadvantage is that it is potentially non-portable
> (how to get the "appropriate size"?).
>
> Would you suggest some other solution?

Use the Annex B interfacing facilities. The basic idea is to write the C
types in Ada, add the pragma Convention C to them, and let the Ada compiler
handle the rest. Is there some reason this doesn't work in this case?

                                         Randy.





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

* Re: Interfacing to C: big structures
  2008-02-25 21:17 Interfacing to C: big structures Maciej Sobczak
@ 2008-02-25 23:26 ` Randy Brukardt
  2008-02-25 23:26 ` Randy Brukardt
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 27+ messages in thread
From: Randy Brukardt @ 2008-02-25 23:26 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message
news:c48dc7da-6f04-4f0f-9a8f-e0acc371ee3c@o10g2000hsf.googlegroups.com...
> Consider the C API that contains some structure S and a couple of
> functions that operate on the state that is stored in the Struct. A
> typical usage in C might be:
...
> How to interface to this from Ada? I see two options:
>
> 1. Write a simple wrapper that will create S on the heap and use the
> pointer everywhere. This is easy, but imposes the use of dynamic
> memory, which for some reasons I might want to avoid.
> 2. Create an Ada array of basic storage units of "appropriate size"
> and pass its address to the C functions. The advantage of this
> solution is that it does not impose any particular memory management
> scheme, but the disadvantage is that it is potentially non-portable
> (how to get the "appropriate size"?).
>
> Would you suggest some other solution?

Use the Annex B interfacing facilities. The basic idea is to write the C
types in Ada, add the pragma Convention C to them, and let the Ada compiler
handle the rest. Is there some reason this doesn't work in this case?

                                         Randy.





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

* Re: Interfacing to C: big structures
  2008-02-25 21:17 Interfacing to C: big structures Maciej Sobczak
  2008-02-25 23:26 ` Randy Brukardt
@ 2008-02-25 23:26 ` Randy Brukardt
  2008-02-25 23:26 ` Randy Brukardt
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 27+ messages in thread
From: Randy Brukardt @ 2008-02-25 23:26 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message
news:c48dc7da-6f04-4f0f-9a8f-e0acc371ee3c@o10g2000hsf.googlegroups.com...
> Consider the C API that contains some structure S and a couple of
> functions that operate on the state that is stored in the Struct. A
> typical usage in C might be:
...
> How to interface to this from Ada? I see two options:
>
> 1. Write a simple wrapper that will create S on the heap and use the
> pointer everywhere. This is easy, but imposes the use of dynamic
> memory, which for some reasons I might want to avoid.
> 2. Create an Ada array of basic storage units of "appropriate size"
> and pass its address to the C functions. The advantage of this
> solution is that it does not impose any particular memory management
> scheme, but the disadvantage is that it is potentially non-portable
> (how to get the "appropriate size"?).
>
> Would you suggest some other solution?

Use the Annex B interfacing facilities. The basic idea is to write the C
types in Ada, add the pragma Convention C to them, and let the Ada compiler
handle the rest. Is there some reason this doesn't work in this case?

                                         Randy.





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

* Re: Interfacing to C: big structures
  2008-02-25 21:17 Interfacing to C: big structures Maciej Sobczak
                   ` (2 preceding siblings ...)
  2008-02-25 23:26 ` Randy Brukardt
@ 2008-02-25 23:43 ` Robert A Duff
  2008-02-26 13:53   ` Stephen Leake
  2008-02-26  2:36 ` Steve
  2008-02-26 12:00 ` Alex R. Mosteo
  5 siblings, 1 reply; 27+ messages in thread
From: Robert A Duff @ 2008-02-25 23:43 UTC (permalink / raw)


Maciej Sobczak <see.my.homepage@gmail.com> writes:

> Consider the C API that contains some structure S and a couple of
> functions that operate on the state that is stored in the Struct. A
> typical usage in C might be:
>
> struct S s;
>
> init(&s);
> foo(&s);
> bar(&s);
> baz(&s);
>
> Above, s is created with automatic storage duration.
>
> How to interface to this from Ada? I see two options:

Something like:

    type S is record ... end record;
    pragma Convention (C, S);
    
    X : aliased S;
    init (X'Access); -- or possibly 'Unchecked_Access
    foo (X'Access); -- or ...

Best to avoid heap management when you can.

- Bob



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

* Re: Interfacing to C: big structures
  2008-02-25 21:17 Interfacing to C: big structures Maciej Sobczak
                   ` (3 preceding siblings ...)
  2008-02-25 23:43 ` Robert A Duff
@ 2008-02-26  2:36 ` Steve
  2008-02-26 12:00 ` Alex R. Mosteo
  5 siblings, 0 replies; 27+ messages in thread
From: Steve @ 2008-02-26  2:36 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:c48dc7da-6f04-4f0f-9a8f-e0acc371ee3c@o10g2000hsf.googlegroups.com...
> Hi,
>
> Consider the C API that contains some structure S and a couple of
> functions that operate on the state that is stored in the Struct. A
> typical usage in C might be:
>
> struct S s;
>
> init(&s);
> foo(&s);
> bar(&s);
> baz(&s);
>
> Above, s is created with automatic storage duration.
>
> How to interface to this from Ada? I see two options:

I don't understand what you mean by "How to interface to this from Ada?":

  Do you want to be able to perform additional operations on struct S using 
Ada code?

    swizzle(&s);

  Where "swizzle" is an Ada procedure?

  Or are you asking for something different?

Regards,
Steve
(The Duck)

>
> 1. Write a simple wrapper that will create S on the heap and use the
> pointer everywhere. This is easy, but imposes the use of dynamic
> memory, which for some reasons I might want to avoid.
> 2. Create an Ada array of basic storage units of "appropriate size"
> and pass its address to the C functions. The advantage of this
> solution is that it does not impose any particular memory management
> scheme, but the disadvantage is that it is potentially non-portable
> (how to get the "appropriate size"?).
>
> Would you suggest some other solution?
>
> --
> Maciej Sobczak * www.msobczak.com * www.inspirel.com 





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

* Re: Interfacing to C: big structures
  2008-02-25 21:17 Interfacing to C: big structures Maciej Sobczak
                   ` (4 preceding siblings ...)
  2008-02-26  2:36 ` Steve
@ 2008-02-26 12:00 ` Alex R. Mosteo
  2008-02-26 14:05   ` Robert A Duff
  2008-02-26 17:35   ` Adam Beneschan
  5 siblings, 2 replies; 27+ messages in thread
From: Alex R. Mosteo @ 2008-02-26 12:00 UTC (permalink / raw)


Maciej Sobczak wrote:
> Hi,
> 
> Consider the C API that contains some structure S and a couple of
> functions that operate on the state that is stored in the Struct. A
> typical usage in C might be:
> 
> struct S s;
> 
> init(&s);
> foo(&s);
> bar(&s);
> baz(&s);
> 
> Above, s is created with automatic storage duration.
> 
> How to interface to this from Ada? I see two options:
> 
> 1. Write a simple wrapper that will create S on the heap and use the
> pointer everywhere. This is easy, but imposes the use of dynamic
> memory, which for some reasons I might want to avoid.
> 2. Create an Ada array of basic storage units of "appropriate size"
> and pass its address to the C functions. The advantage of this
> solution is that it does not impose any particular memory management
> scheme, but the disadvantage is that it is potentially non-portable
> (how to get the "appropriate size"?).
> 
> Would you suggest some other solution?

I have used this trick for types in C that I don't want to replicate in
Ada with pragma convention C, and that adds the bonus of being always in
sync with the C part, even if it changes, by means of a single
recompiling. You can see examples of use in my ada-player binding [1]:

The following is not compiled, there may be mistakes. Hope you get the idea.

1. Create a C helper file with

size_t size_of_S(void) { return sizeof (struct S); };

and a corresponding helper binding in Ada:

function Size_Of_S return Interfaces.C.Size_T;
pragma Import (Size_Of_S, "size_of_S");

2. Create an Ada type as

type S is new Ada.Streams.Stream_Element_Array
                (1 .. Stream_Offset (Size_Of_S));
pragma Pack (S); -- Not sure if this is even needed.

Note that this type gets its size at elaboration time, and thus this is
what fixes this type if the C corresponding struct changes.

3. Use the S Ada type through binding functions to the C functions. In
practice, you have a byte receptacle in the Ada side, and that's all.
You retain the use in the stack and through the C API. I find this very
practical for well-designed C libraries where all usage is through
functions with client-opaque types, since it requires zero maintenance
if the C type changes.

[1] http://sourceforge.net/projects/ada-player



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

* Re: Interfacing to C: big structures
  2008-02-25 23:43 ` Robert A Duff
@ 2008-02-26 13:53   ` Stephen Leake
  2008-02-26 21:12     ` Randy Brukardt
  0 siblings, 1 reply; 27+ messages in thread
From: Stephen Leake @ 2008-02-26 13:53 UTC (permalink / raw)


Robert A Duff <bobduff@shell01.TheWorld.com> writes:

> Maciej Sobczak <see.my.homepage@gmail.com> writes:
>
>> Consider the C API that contains some structure S and a couple of
>> functions that operate on the state that is stored in the Struct. A
>> typical usage in C might be:
>>
>> struct S s;
>>
>> init(&s);
>> foo(&s);
>> bar(&s);
>> baz(&s);
>>
>> Above, s is created with automatic storage duration.
>>
>> How to interface to this from Ada? I see two options:
>
> Something like:
>
>     type S is record ... end record;
>     pragma Convention (C, S);
>     
>     X : aliased S;
>     init (X'Access); -- or possibly 'Unchecked_Access
>     foo (X'Access); -- or ...

Why not:

procedure Init (X : in out S);
procedure Foo (X : in out S);

begin
    init (X);
    foo (X);
end;

-- 
-- Stephe



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

* Re: Interfacing to C: big structures
  2008-02-26 12:00 ` Alex R. Mosteo
@ 2008-02-26 14:05   ` Robert A Duff
  2008-02-26 15:19     ` Alex R. Mosteo
  2008-02-26 17:35   ` Adam Beneschan
  1 sibling, 1 reply; 27+ messages in thread
From: Robert A Duff @ 2008-02-26 14:05 UTC (permalink / raw)


"Alex R. Mosteo" <amosteo@unizar.es> writes:

> 2. Create an Ada type as
>
> type S is new Ada.Streams.Stream_Element_Array
>                 (1 .. Stream_Offset (Size_Of_S));
> pragma Pack (S); -- Not sure if this is even needed.
>
> Note that this type gets its size at elaboration time, and thus this is
> what fixes this type if the C corresponding struct changes.

Nice trick.

But I think you need to make sure the alignment is correct.

- Bob



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

* Re: Interfacing to C: big structures
  2008-02-26 14:05   ` Robert A Duff
@ 2008-02-26 15:19     ` Alex R. Mosteo
  2008-02-26 15:33       ` Robert A Duff
  0 siblings, 1 reply; 27+ messages in thread
From: Alex R. Mosteo @ 2008-02-26 15:19 UTC (permalink / raw)


Robert A Duff wrote:
> "Alex R. Mosteo" <amosteo@unizar.es> writes:
> 
>> 2. Create an Ada type as
>>
>> type S is new Ada.Streams.Stream_Element_Array
>>                 (1 .. Stream_Offset (Size_Of_S));
>> pragma Pack (S); -- Not sure if this is even needed.
>>
>> Note that this type gets its size at elaboration time, and thus this is
>> what fixes this type if the C corresponding struct changes.
> 
> Nice trick.
> 
> But I think you need to make sure the alignment is correct.

I'm out of my expertise here, but why it's that necessary? In the end
you're passing S address to the C subprograms and I don't see how
alignment may have influence (but, again, I don't know about this).



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

* Re: Interfacing to C: big structures
  2008-02-26 15:19     ` Alex R. Mosteo
@ 2008-02-26 15:33       ` Robert A Duff
  2008-02-26 16:21         ` Alex R. Mosteo
  0 siblings, 1 reply; 27+ messages in thread
From: Robert A Duff @ 2008-02-26 15:33 UTC (permalink / raw)


"Alex R. Mosteo" <amosteo@unizar.es> writes:

> Robert A Duff wrote:
>> "Alex R. Mosteo" <amosteo@unizar.es> writes:
>> 
>>> 2. Create an Ada type as
>>>
>>> type S is new Ada.Streams.Stream_Element_Array
>>>                 (1 .. Stream_Offset (Size_Of_S));
>>> pragma Pack (S); -- Not sure if this is even needed.
>>>
>>> Note that this type gets its size at elaboration time, and thus this is
>>> what fixes this type if the C corresponding struct changes.
>> 
>> Nice trick.
>> 
>> But I think you need to make sure the alignment is correct.
>
> I'm out of my expertise here, but why it's that necessary? In the end
> you're passing S address to the C subprograms and I don't see how
> alignment may have influence (but, again, I don't know about this).

Suppose the C struct contains a double, and suppose the C compiler
therefore insists that all objects be allocated on an 8-byte boundary.
On some machines, failure to do so will cause the program to
crash; on others, it will cause the program to be slow.

But the Ada compiler thinks it's an array of bytes,
so S'Alignment will probably be 1, so the compiler
can allocate objects at an improperly-aligned address.

    type T is
        record
            Flag : Boolean;
            X : S;
        end record;

- Bob



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

* Re: Interfacing to C: big structures
  2008-02-26 15:33       ` Robert A Duff
@ 2008-02-26 16:21         ` Alex R. Mosteo
  2008-02-27  1:28           ` Robert A Duff
  0 siblings, 1 reply; 27+ messages in thread
From: Alex R. Mosteo @ 2008-02-26 16:21 UTC (permalink / raw)


Robert A Duff wrote:
> "Alex R. Mosteo" <amosteo@unizar.es> writes:
> 
>> Robert A Duff wrote:
>>> "Alex R. Mosteo" <amosteo@unizar.es> writes:
>>>
>>>> 2. Create an Ada type as
>>>>
>>>> type S is new Ada.Streams.Stream_Element_Array
>>>>                 (1 .. Stream_Offset (Size_Of_S));
>>>> pragma Pack (S); -- Not sure if this is even needed.
>>>>
>>>> Note that this type gets its size at elaboration time, and thus this is
>>>> what fixes this type if the C corresponding struct changes.
>>> Nice trick.
>>>
>>> But I think you need to make sure the alignment is correct.
>> I'm out of my expertise here, but why it's that necessary? In the end
>> you're passing S address to the C subprograms and I don't see how
>> alignment may have influence (but, again, I don't know about this).
> 
> Suppose the C struct contains a double, and suppose the C compiler
> therefore insists that all objects be allocated on an 8-byte boundary.
> On some machines, failure to do so will cause the program to
> crash; on others, it will cause the program to be slow.
> 
> But the Ada compiler thinks it's an array of bytes,
> so S'Alignment will probably be 1, so the compiler
> can allocate objects at an improperly-aligned address.
> 
>     type T is
>         record
>             Flag : Boolean;
>             X : S;
>         end record;
> 
> - Bob

I see. So, for example, let's say there's this C function:

void init (struct S *s) {...};

and you pass the Ada array address to it.

It may crash/ill-behave, if the C code takes for granted that the s
pointer is, say, 8-aligned, and some C generated code within "init"
depends on this assumption.

It may be slow, otherwise, if no such assumption exists.

I'm missing some other possibilities?

And, finally, is adding an alignment clause enough to solve this issue?
If so, how do you query the alignment of a C datatype?

(Could a conservative approach be to force the Ada side type to be
max-aligned for the architecture?)



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

* Re: Interfacing to C: big structures
  2008-02-26 12:00 ` Alex R. Mosteo
  2008-02-26 14:05   ` Robert A Duff
@ 2008-02-26 17:35   ` Adam Beneschan
  2008-02-26 19:47     ` Simon Wright
  2008-02-27  1:37     ` Robert A Duff
  1 sibling, 2 replies; 27+ messages in thread
From: Adam Beneschan @ 2008-02-26 17:35 UTC (permalink / raw)


On Feb 26, 4:00 am, "Alex R. Mosteo" <amos...@unizar.es> wrote:
> Maciej Sobczak wrote:
> > Hi,
>
> > Consider the C API that contains some structure S and a couple of
> > functions that operate on the state that is stored in the Struct. A
> > typical usage in C might be:
>
> > struct S s;
>
> > init(&s);
> > foo(&s);
> > bar(&s);
> > baz(&s);
>
> > Above, s is created with automatic storage duration.
>
> > How to interface to this from Ada? I see two options:
>
> > 1. Write a simple wrapper that will create S on the heap and use the
> > pointer everywhere. This is easy, but imposes the use of dynamic
> > memory, which for some reasons I might want to avoid.
> > 2. Create an Ada array of basic storage units of "appropriate size"
> > and pass its address to the C functions. The advantage of this
> > solution is that it does not impose any particular memory management
> > scheme, but the disadvantage is that it is potentially non-portable
> > (how to get the "appropriate size"?).
>
> > Would you suggest some other solution?
>
> I have used this trick for types in C that I don't want to replicate in
> Ada with pragma convention C, and that adds the bonus of being always in
> sync with the C part, even if it changes, by means of a single
> recompiling. You can see examples of use in my ada-player binding [1]:
>
> The following is not compiled, there may be mistakes. Hope you get the idea.
>
> 1. Create a C helper file with
>
> size_t size_of_S(void) { return sizeof (struct S); };
>
> and a corresponding helper binding in Ada:
>
> function Size_Of_S return Interfaces.C.Size_T;
> pragma Import (Size_Of_S, "size_of_S");
>
> 2. Create an Ada type as
>
> type S is new Ada.Streams.Stream_Element_Array
>                 (1 .. Stream_Offset (Size_Of_S));
> pragma Pack (S); -- Not sure if this is even needed.
>
> Note that this type gets its size at elaboration time, and thus this is
> what fixes this type if the C corresponding struct changes.
>
> 3. Use the S Ada type through binding functions to the C functions. In
> practice, you have a byte receptacle in the Ada side, and that's all.
> You retain the use in the stack and through the C API. I find this very
> practical for well-designed C libraries where all usage is through
> functions with client-opaque types, since it requires zero maintenance
> if the C type changes.

I thought of something like this, but Maciej said something about
wanting to avoid dynamic memory, and it seems that you're defining a
type whose size isn't going to be known until runtime, and therefore
if you declare an Ada variable of that type, it will have to be
allocated dynamically in some way.  Maybe the particular way it would
be done is acceptable to Maciej, though (a local variable could be
allocated simply by moving the stack pointer, depending on the
implementation).  Anyway, this seems like the best way to do things if
it isn't unacceptable for that reason.

                                 -- Adam






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

* Re: Interfacing to C: big structures
  2008-02-26 17:35   ` Adam Beneschan
@ 2008-02-26 19:47     ` Simon Wright
  2008-02-26 21:14       ` Randy Brukardt
  2008-02-27 17:12       ` Adam Beneschan
  2008-02-27  1:37     ` Robert A Duff
  1 sibling, 2 replies; 27+ messages in thread
From: Simon Wright @ 2008-02-26 19:47 UTC (permalink / raw)


Adam Beneschan <adam@irvine.com> writes:

> I thought of something like this, but Maciej said something about
> wanting to avoid dynamic memory, and it seems that you're defining a
> type whose size isn't going to be known until runtime, and therefore
> if you declare an Ada variable of that type, it will have to be
> allocated dynamically in some way.

That was the cunning trick: the size is known at *elaboration* time!

procedure Main_Program is
  type T is Ada.Streams.Stream_Element_Array (1 .. Size_Returned_From_C);
  V : aliased T; 



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

* Re: Interfacing to C: big structures
  2008-02-26 13:53   ` Stephen Leake
@ 2008-02-26 21:12     ` Randy Brukardt
  0 siblings, 0 replies; 27+ messages in thread
From: Randy Brukardt @ 2008-02-26 21:12 UTC (permalink / raw)


"Stephen Leake" <stephen_leake@stephe-leake.org> wrote in message
news:uhcfvvn79.fsf@stephe-leake.org...
> Robert A Duff <bobduff@shell01.TheWorld.com> writes:
> > Something like:
> >
> >     type S is record ... end record;
> >     pragma Convention (C, S);
> >
> >     X : aliased S;
> >     init (X'Access); -- or possibly 'Unchecked_Access
> >     foo (X'Access); -- or ...
>
> Why not:
>
> procedure Init (X : in out S);
> procedure Foo (X : in out S);
>
> begin
>     init (X);
>     foo (X);
> end;


I agree; there is no good reason to use access type here (at least with the
example given).

                       Randy.





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

* Re: Interfacing to C: big structures
  2008-02-26 19:47     ` Simon Wright
@ 2008-02-26 21:14       ` Randy Brukardt
  2008-02-27  1:40         ` Robert A Duff
  2008-02-27 17:12       ` Adam Beneschan
  1 sibling, 1 reply; 27+ messages in thread
From: Randy Brukardt @ 2008-02-26 21:14 UTC (permalink / raw)


"Simon Wright" <simon.j.wright@mac.com> wrote in message
news:m27igr4i0b.fsf@mac.com...
> Adam Beneschan <adam@irvine.com> writes:
>
> > I thought of something like this, but Maciej said something about
> > wanting to avoid dynamic memory, and it seems that you're defining a
> > type whose size isn't going to be known until runtime, and therefore
> > if you declare an Ada variable of that type, it will have to be
> > allocated dynamically in some way.
>
> That was the cunning trick: the size is known at *elaboration* time!
>
> procedure Main_Program is
>   type T is Ada.Streams.Stream_Element_Array (1 .. Size_Returned_From_C);
>   V : aliased T;

But at least some compilers will allocate V on the heap (under the covers,
of course) because the size of the object is not know at compile-time.
Janus/Ada works this way, for instance. For high-integrity applications,
that's still unacceptable.

But the OP didn't provide enough information to know if this is acceptable
to him or not.

                                          Randy.





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

* Re: Interfacing to C: big structures
  2008-02-26 16:21         ` Alex R. Mosteo
@ 2008-02-27  1:28           ` Robert A Duff
  2008-03-10  1:38             ` David Thompson
  0 siblings, 1 reply; 27+ messages in thread
From: Robert A Duff @ 2008-02-27  1:28 UTC (permalink / raw)


"Alex R. Mosteo" <amosteo@unizar.es> writes:

> I see. So, for example, let's say there's this C function:
>
> void init (struct S *s) {...};
>
> and you pass the Ada array address to it.
>
> It may crash/ill-behave, if the C code takes for granted that the s
> pointer is, say, 8-aligned, and some C generated code within "init"
> depends on this assumption.
>
> It may be slow, otherwise, if no such assumption exists.

Right.  The crash vs. slow issue is defined by the hardware,
in practise.  x86 machines tolerate unaligned refs (slowly)
whereas RISC machines tend to trap on unaligned refs.

> I'm missing some other possibilities?

No, I don't think you're missing anything.

> And, finally, is adding an alignment clause enough to solve this issue?
> If so, how do you query the alignment of a C datatype?

I'm not a C expert, but I don't think there's any easy way.

> (Could a conservative approach be to force the Ada side type to be
> max-aligned for the architecture?)

Yes.  Probably "for S'Alignment use Long_Float'Alignment" will work OK
on most machines.  Is there a cleaner way to do that?

- Bob



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

* Re: Interfacing to C: big structures
  2008-02-26 17:35   ` Adam Beneschan
  2008-02-26 19:47     ` Simon Wright
@ 2008-02-27  1:37     ` Robert A Duff
  2008-02-27 13:49       ` Maciej Sobczak
  1 sibling, 1 reply; 27+ messages in thread
From: Robert A Duff @ 2008-02-27  1:37 UTC (permalink / raw)


Adam Beneschan <adam@irvine.com> writes:

> I thought of something like this, but Maciej said something about
> wanting to avoid dynamic memory,...

I think Maciej is trying to avoid heap allocation, because then you have
to worry about deallocation.  But dynamic-sized allocation on the stack
should be OK in that regard.  If you don't like the dynamic size (it
does introduce some inefficiency), then you could do this:

S_Size : constant := 24; -- or whatever you know it is
pragma Assert (S_Size = Size_Of_S);
type S is new Ada.Streams.Stream_Element_Array (1 .. S_Size);
for S'Alignment use ...;

Now the Ada compiler knows the right size statically.
If the C code changes, you have to change 24 to something else,
but at least you get notified to do so (the simplest testing
will fail on the Assert).

- Bob



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

* Re: Interfacing to C: big structures
  2008-02-26 21:14       ` Randy Brukardt
@ 2008-02-27  1:40         ` Robert A Duff
  0 siblings, 0 replies; 27+ messages in thread
From: Robert A Duff @ 2008-02-27  1:40 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> "Simon Wright" <simon.j.wright@mac.com> wrote in message
> news:m27igr4i0b.fsf@mac.com...
>> Adam Beneschan <adam@irvine.com> writes:
>>
>> > I thought of something like this, but Maciej said something about
>> > wanting to avoid dynamic memory, and it seems that you're defining a
>> > type whose size isn't going to be known until runtime, and therefore
>> > if you declare an Ada variable of that type, it will have to be
>> > allocated dynamically in some way.
>>
>> That was the cunning trick: the size is known at *elaboration* time!
>>
>> procedure Main_Program is
>>   type T is Ada.Streams.Stream_Element_Array (1 .. Size_Returned_From_C);
>>   V : aliased T;
>
> But at least some compilers will allocate V on the heap (under the covers,
> of course) because the size of the object is not know at compile-time.

I the compiler does that, I presume it would (under the covers)
deallocate the heap object on leaving the relevant scope.

> Janus/Ada works this way, for instance. For high-integrity applications,
> that's still unacceptable.
>
> But the OP didn't provide enough information to know if this is acceptable
> to him or not.

Indeed.

- Bob



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

* Re: Interfacing to C: big structures
  2008-02-25 23:26 ` Randy Brukardt
@ 2008-02-27 13:23   ` Maciej Sobczak
  0 siblings, 0 replies; 27+ messages in thread
From: Maciej Sobczak @ 2008-02-27 13:23 UTC (permalink / raw)


On 26 Lut, 00:26, "Randy Brukardt" <ra...@rrsoftware.com> wrote:

> Use the Annex B interfacing facilities. The basic idea is to write the C
> types in Ada, add the pragma Convention C to them, and let the Ada compiler
> handle the rest. Is there some reason this doesn't work in this case?

The reason is that I don't care about the internals (data fields and
their layout) of the given structure. The only thing that matters for
me is the set of functions that accept a pointer to "something". I
have problems with mapping this "something" without reverse
engineering it.

--
Maciej Sobczak * www.msobczak.com * www.inspirel.com



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

* Re: Interfacing to C: big structures
  2008-02-27  1:37     ` Robert A Duff
@ 2008-02-27 13:49       ` Maciej Sobczak
  0 siblings, 0 replies; 27+ messages in thread
From: Maciej Sobczak @ 2008-02-27 13:49 UTC (permalink / raw)


On 27 Lut, 02:37, Robert A Duff <bobd...@shell01.TheWorld.com> wrote:

> I think Maciej is trying to avoid heap allocation, because then you have
> to worry about deallocation.

This might not be the only reason. Another one might be to fulfill the
constraints of high-integrity system.

> But dynamic-sized allocation on the stack
> should be OK in that regard.  If you don't like the dynamic size (it
> does introduce some inefficiency), then you could do this:
>
> S_Size : constant := 24; -- or whatever you know it is
> pragma Assert (S_Size = Size_Of_S);
> type S is new Ada.Streams.Stream_Element_Array (1 .. S_Size);
> for S'Alignment use ...;

Yes, this is one of the possibilities.
It can be improved with a script that is executed at build time that
gets the sizeof(S) in C and copies it verbatim to the Ada source file
(it can be a separate source file for exactly this purpose). This way
both consistency and compile-time "constness" can be achieved.

Such a script can be actually part of some bigger activity that
gathers system-specific information. See autotools for example.

--
Maciej Sobczak * www.msobczak.com * www.inspirel.com



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

* Re: Interfacing to C: big structures
  2008-02-26 19:47     ` Simon Wright
  2008-02-26 21:14       ` Randy Brukardt
@ 2008-02-27 17:12       ` Adam Beneschan
  2008-02-27 20:37         ` Simon Wright
  2008-02-28 11:30         ` Alex R. Mosteo
  1 sibling, 2 replies; 27+ messages in thread
From: Adam Beneschan @ 2008-02-27 17:12 UTC (permalink / raw)


On Feb 26, 11:47 am, Simon Wright <simon.j.wri...@mac.com> wrote:
> Adam Beneschan <a...@irvine.com> writes:
> > I thought of something like this, but Maciej said something about
> > wanting to avoid dynamic memory, and it seems that you're defining a
> > type whose size isn't going to be known until runtime, and therefore
> > if you declare an Ada variable of that type, it will have to be
> > allocated dynamically in some way.
>
> That was the cunning trick: the size is known at *elaboration* time!

Isn't that part of "runtime"?  I'm not sure I get your point.  In the
typical compile/link/execute model, as I understand it, the function
that returns the size isn't going to be "called" by the linker, and
probably not by the loader when the program is executed; so the
function will be called when the program starts executing, which means
that any objects of that type can't be allocated until after execution
starts, which means "dynamic allocation" more or less by definition.
However, as others have pointed out, it's not clear exactly what kinds
of dynamic allocation need to be avoided here, and which ones might be
OK.

                             -- Adam

>
> procedure Main_Program is
>   type T is Ada.Streams.Stream_Element_Array (1 .. Size_Returned_From_C);
>   V : aliased T;




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

* Re: Interfacing to C: big structures
  2008-02-27 17:12       ` Adam Beneschan
@ 2008-02-27 20:37         ` Simon Wright
  2008-02-28 11:30         ` Alex R. Mosteo
  1 sibling, 0 replies; 27+ messages in thread
From: Simon Wright @ 2008-02-27 20:37 UTC (permalink / raw)


Adam Beneschan <adam@irvine.com> writes:

> Isn't that part of "runtime"?  I'm not sure I get your point.

Um, thinking about it from that point of view, you are all quite
right, of course.

When I've had/heard of restrictions, it's only ever been in
environments where it was the use of the word 'new' that was frowned
upon rather than the actual allocation of memory after execution
startup. Even there it seems reasonable to fight for the right to do
explicit one-off startup allocations - no risk of fragmentation if the
memory's never freed.



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

* Re: Interfacing to C: big structures
  2008-02-27 17:12       ` Adam Beneschan
  2008-02-27 20:37         ` Simon Wright
@ 2008-02-28 11:30         ` Alex R. Mosteo
  2008-02-28 15:53           ` Robert A Duff
  1 sibling, 1 reply; 27+ messages in thread
From: Alex R. Mosteo @ 2008-02-28 11:30 UTC (permalink / raw)


Adam Beneschan wrote:
> On Feb 26, 11:47 am, Simon Wright <simon.j.wri...@mac.com> wrote:
>> Adam Beneschan <a...@irvine.com> writes:
>>> I thought of something like this, but Maciej said something about
>>> wanting to avoid dynamic memory, and it seems that you're defining a
>>> type whose size isn't going to be known until runtime, and therefore
>>> if you declare an Ada variable of that type, it will have to be
>>> allocated dynamically in some way.
>> That was the cunning trick: the size is known at *elaboration* time!
> 
> Isn't that part of "runtime"?  I'm not sure I get your point.  In the
> typical compile/link/execute model, as I understand it, the function
> that returns the size isn't going to be "called" by the linker, and
> probably not by the loader when the program is executed; so the
> function will be called when the program starts executing, which means
> that any objects of that type can't be allocated until after execution
> starts, which means "dynamic allocation" more or less by definition.
> However, as others have pointed out, it's not clear exactly what kinds
> of dynamic allocation need to be avoided here, and which ones might be
> OK.

Actually I would have expected these types to be allocated in the stack.
I likened them to indefinite types, but certainly the maximum size of
some indefinite types may be known at compile time, so this set them
apart and I was simplifying too much. Besides, at least one
implementation, as Randy Brukardt said, uses the heap for them. Even if
it's the compiler doing the management, this may be a no-go in some real
time environments.

Using the heap may be easier for an implementation; another question is
if it is still doable in the stack. I wonder what gnat does. Is the
secondary gnat stack considered a kind of heap? Is this what gnat uses?
Are there pragma Restrictions that could clarify this? Just throwing
questions in the air.

I guess that if my proposal is deemed unacceptable, one can neither use
anymore things like

type T (Len : Natural) is record
   Name   : String (1 .. Len);
   Others : Whatever;
   -- ...
end record;

?



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

* Re: Interfacing to C: big structures
  2008-02-28 11:30         ` Alex R. Mosteo
@ 2008-02-28 15:53           ` Robert A Duff
  2008-02-29 10:45             ` Alex R. Mosteo
  0 siblings, 1 reply; 27+ messages in thread
From: Robert A Duff @ 2008-02-28 15:53 UTC (permalink / raw)


"Alex R. Mosteo" <amosteo@unizar.es> writes:

> Actually I would have expected these types to be allocated in the stack.

Me, too.

> I likened them to indefinite types, but certainly the maximum size of
> some indefinite types may be known at compile time, so this set them
> apart and I was simplifying too much. Besides, at least one
> implementation, as Randy Brukardt said, uses the heap for them. Even if
> it's the compiler doing the management, this may be a no-go in some real
> time environments.
>
> Using the heap may be easier for an implementation; ...

Yes.

>...another question is
> if it is still doable in the stack.

Yes, it is doable.

>...I wonder what gnat does.

Puts it on the primary stack.

>...Is the
> secondary gnat stack considered a kind of heap?

No.  It's a stack.

>...Is this what gnat uses?

No.  The secondary stack is for objects of unknown size that
are returned as function results.  I think GNAT also uses
it in some other cases, such as records containing
controlled parts.

> Are there pragma Restrictions that could clarify this?

You can say:

    pragma Restrictions (No_Implicit_Heap_Allocations);

>...Just throwing
> questions in the air.
>
> I guess that if my proposal is deemed unacceptable, one can neither use
> anymore things like
>
> type T (Len : Natural) is record
>    Name   : String (1 .. Len);
>    Others : Whatever;
>    -- ...
> end record;

There are certainly cases where the above should not be used with
"Len => <dynamic expression>", because it prevents you from
calculating the maximum stack size for each task.  Or, you can
calculate it, but the answer is "the size of the address space",
which isn't very useful.

It might be OK if you change Natural to a range 1..100.

- Bob



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

* Re: Interfacing to C: big structures
  2008-02-28 15:53           ` Robert A Duff
@ 2008-02-29 10:45             ` Alex R. Mosteo
  0 siblings, 0 replies; 27+ messages in thread
From: Alex R. Mosteo @ 2008-02-29 10:45 UTC (permalink / raw)


Robert A Duff wrote:
> "Alex R. Mosteo" <amosteo@unizar.es> writes:
> 
>> Actually I would have expected these types to be allocated in the stack.
> 
> Me, too.
> 
>> I likened them to indefinite types, but certainly the maximum size of
>> some indefinite types may be known at compile time, so this set them
>> apart and I was simplifying too much. Besides, at least one
>> implementation, as Randy Brukardt said, uses the heap for them. Even if
>> it's the compiler doing the management, this may be a no-go in some real
>> time environments.
>>
>> Using the heap may be easier for an implementation; ...
> 
> Yes.
> 
>> ...another question is
>> if it is still doable in the stack.
> 
> Yes, it is doable.
> 
>> ...I wonder what gnat does.
> 
> Puts it on the primary stack.
> 
>> ...Is the
>> secondary gnat stack considered a kind of heap?
> 
> No.  It's a stack.
> 
>> ...Is this what gnat uses?
> 
> No.  The secondary stack is for objects of unknown size that
> are returned as function results.  I think GNAT also uses
> it in some other cases, such as records containing
> controlled parts.
> 
>> Are there pragma Restrictions that could clarify this?
> 
> You can say:
> 
>     pragma Restrictions (No_Implicit_Heap_Allocations);
> 
>> ...Just throwing
>> questions in the air.
>>
>> I guess that if my proposal is deemed unacceptable, one can neither use
>> anymore things like
>>
>> type T (Len : Natural) is record
>>    Name   : String (1 .. Len);
>>    Others : Whatever;
>>    -- ...
>> end record;
> 
> There are certainly cases where the above should not be used with
> "Len => <dynamic expression>", because it prevents you from
> calculating the maximum stack size for each task.  Or, you can
> calculate it, but the answer is "the size of the address space",
> which isn't very useful.
> 
> It might be OK if you change Natural to a range 1..100.

Thanks for that great a deal of information!



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

* Re: Interfacing to C: big structures
  2008-02-27  1:28           ` Robert A Duff
@ 2008-03-10  1:38             ` David Thompson
  0 siblings, 0 replies; 27+ messages in thread
From: David Thompson @ 2008-03-10  1:38 UTC (permalink / raw)


On Tue, 26 Feb 2008 20:28:48 -0500, Robert A Duff
<bobduff@shell01.TheWorld.com> wrote:

> "Alex R. Mosteo" <amosteo@unizar.es> writes:

> > And, finally, is adding an alignment clause enough to solve this issue?
> > If so, how do you query the alignment of a C datatype?
> 
> I'm not a C expert, but I don't think there's any easy way.
> 
Easy is a matter of opinion, and not very elegant, but possible:

#include <stddef.h> 
struct S { whatever };
size_t /* or other u-int type */ Alignment_for_S (void)
{
  struct trick { char x; S y; } /* type only no instance */;
  return offsetof (struct trick, y);
}

This isn't guaranteed to be minimal, but it is sufficient.

- formerly david.thompson1 || achar(64) || worldnet.att.net



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

end of thread, other threads:[~2008-03-10  1:38 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-25 21:17 Interfacing to C: big structures Maciej Sobczak
2008-02-25 23:26 ` Randy Brukardt
2008-02-25 23:26 ` Randy Brukardt
2008-02-25 23:26 ` Randy Brukardt
2008-02-27 13:23   ` Maciej Sobczak
2008-02-25 23:43 ` Robert A Duff
2008-02-26 13:53   ` Stephen Leake
2008-02-26 21:12     ` Randy Brukardt
2008-02-26  2:36 ` Steve
2008-02-26 12:00 ` Alex R. Mosteo
2008-02-26 14:05   ` Robert A Duff
2008-02-26 15:19     ` Alex R. Mosteo
2008-02-26 15:33       ` Robert A Duff
2008-02-26 16:21         ` Alex R. Mosteo
2008-02-27  1:28           ` Robert A Duff
2008-03-10  1:38             ` David Thompson
2008-02-26 17:35   ` Adam Beneschan
2008-02-26 19:47     ` Simon Wright
2008-02-26 21:14       ` Randy Brukardt
2008-02-27  1:40         ` Robert A Duff
2008-02-27 17:12       ` Adam Beneschan
2008-02-27 20:37         ` Simon Wright
2008-02-28 11:30         ` Alex R. Mosteo
2008-02-28 15:53           ` Robert A Duff
2008-02-29 10:45             ` Alex R. Mosteo
2008-02-27  1:37     ` Robert A Duff
2008-02-27 13:49       ` Maciej Sobczak

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