comp.lang.ada
 help / color / mirror / Atom feed
* Memory Access
@ 2011-11-07 20:09 awdorrin
  2011-11-07 21:26 ` Simon Wright
                   ` (3 more replies)
  0 siblings, 4 replies; 20+ messages in thread
From: awdorrin @ 2011-11-07 20:09 UTC (permalink / raw)


I am trying to migrate source code from an older AdaMulti compiler
than ran on Solaris to GNAT on Linux.

The original program makes use of shared memory and has structures
populated in C code that are accessed within Ada code.

The original developers used some AdaMulti 'features' that do not
appear to exist within GNAT to play some tricks on setting up a
pointer as an array of records.

For instance:

Config_Type is an Ada Record which matches a C struct.
A Dev_Table is used as an array of these Config_Type records.

The original code has the following statements:

type Dev_Table_Type is array (Device_Num_Type range <>) of
Config_Type;
type Dev_Table_Ptr_Type is access Dev_Table_Type;
Dev_Table := Dev_Table_Ptr_Type;
Bounds_Ptr : Global_Types.Int_Ptr_Type;

Then, in the Ada Procedure we have:

Dev_Data_Obj := Get_Object_Pointer( Dev_Data_Obj_Name );

Dev_Table := To_Dev_Table_Ptr( Get_UDP( Dev_Data_Obj) );

Bounds_Ptr := Dev_Table_Ptr_To_Int_Ptr( Dev_Table );
Bounds_Ptr.all := 1;

Bounds_Ptr := Int_To_Int_Ptr( Dev_Table_Ptr_To_Int( Dev_Table ) + 4);
Bounds_Ptr.all := Int32( Num_Devs_Cnst );

The To_Dev_Table_Ptr, Dev_Table_Ptr_To_Int_Ptr, Int_To_Int_Ptr are all
unchecked conversion methods.

I understand that the Bounds_Ptr is being used to assign array
constraints to the dope vector. But I'm guessing that GNAT doesn't
define these dope vectors using this sort of definition.

I haven't done much development in Ada, so I'm at a loss here. I'm
making the assumption that the way this code was implemented
(somewhere between 1992 and 98) was not really the right way to
approach this problem. But I'm not sure what method should be used,
and haven't had much luck the past few days searching the web and
newsgroups.

I would have thought I could have defined the Dev_Table differently,
perhaps:

Dev_Table : Dev_Table_Ptr_Type := new Dev_Table_Type( 1 ..
Num_Devs_Cnst );

If I knew the address of pointer at the time of declaration I figured
I could do:

for Dev_Table'Address use {address_of_memory_array} - but I won't know
that until run time, so I'm not sure how I can assign that properly.

I hope I'm making sense here - because I'm pretty confused about all
of this at the moment... :-)

Thanks
-Al




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

* Re: Memory Access
  2011-11-07 20:09 Memory Access awdorrin
@ 2011-11-07 21:26 ` Simon Wright
  2011-11-07 22:03 ` anon
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 20+ messages in thread
From: Simon Wright @ 2011-11-07 21:26 UTC (permalink / raw)


awdorrin <awdorrin@gmail.com> writes:

> I understand that the Bounds_Ptr is being used to assign array
> constraints to the dope vector. But I'm guessing that GNAT doesn't
> define these dope vectors using this sort of definition.

It probably does, just not quite the same!

> I haven't done much development in Ada, so I'm at a loss here. I'm
> making the assumption that the way this code was implemented
> (somewhere between 1992 and 98) was not really the right way to
> approach this problem. But I'm not sure what method should be used,
> and haven't had much luck the past few days searching the web and
> newsgroups.

I wonder whether Interfaces.C.Pointers would be appropriate?

http://www.adaic.org/resources/add_content/standards/05rm/html/RM-B-3-2.html



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

* Re: Memory Access
  2011-11-07 20:09 Memory Access awdorrin
  2011-11-07 21:26 ` Simon Wright
@ 2011-11-07 22:03 ` anon
  2011-11-07 22:21 ` Adam Beneschan
  2011-11-07 22:26 ` Niklas Holsti
  3 siblings, 0 replies; 20+ messages in thread
From: anon @ 2011-11-07 22:03 UTC (permalink / raw)


Normally, Address is used for interfacing other languages and 
Machine_Code programming. Under Ada the standard is to use the 
"Access" statements such as 

  Dev_0 := Dev_Table ( index ) 'Access ;

then use 
  Dev0.all to reference  Dev_Table ( index ) 'Access ;


The 

  for Dev_Table'Address use {address_of_memory_array}

is to assign a specific address to Dev_Table. Like setting the 
interrupt table to memory location zero.

  -- Interrupt_Vector_Type defined as either 32-bit or 64-bit
  --                       Interrupt record.

  Interrupt_Vector : Interrupt_Vector_Type ( 0 .. 255 ) ;
  for Interrupt_Vector'Address use System.Null_Address ;
  -- simplest way because Null_Address (GNAT) is define as Address 0.



In <f4a52e5d-2514-4713-a68d-877f09af7ec3@d17g2000yql.googlegroups.com>, awdorrin <awdorrin@gmail.com> writes:
>I am trying to migrate source code from an older AdaMulti compiler
>than ran on Solaris to GNAT on Linux.
>
>The original program makes use of shared memory and has structures
>populated in C code that are accessed within Ada code.
>
>The original developers used some AdaMulti 'features' that do not
>appear to exist within GNAT to play some tricks on setting up a
>pointer as an array of records.
>
>For instance:
>
>Config_Type is an Ada Record which matches a C struct.
>A Dev_Table is used as an array of these Config_Type records.
>
>The original code has the following statements:
>
>type Dev_Table_Type is array (Device_Num_Type range <>) of
>Config_Type;
>type Dev_Table_Ptr_Type is access Dev_Table_Type;
>Dev_Table := Dev_Table_Ptr_Type;
>Bounds_Ptr : Global_Types.Int_Ptr_Type;
>
>Then, in the Ada Procedure we have:
>
>Dev_Data_Obj := Get_Object_Pointer( Dev_Data_Obj_Name );
>
>Dev_Table := To_Dev_Table_Ptr( Get_UDP( Dev_Data_Obj) );
>
>Bounds_Ptr := Dev_Table_Ptr_To_Int_Ptr( Dev_Table );
>Bounds_Ptr.all := 1;
>
>Bounds_Ptr := Int_To_Int_Ptr( Dev_Table_Ptr_To_Int( Dev_Table ) + 4);
>Bounds_Ptr.all := Int32( Num_Devs_Cnst );
>
>The To_Dev_Table_Ptr, Dev_Table_Ptr_To_Int_Ptr, Int_To_Int_Ptr are all
>unchecked conversion methods.
>
>I understand that the Bounds_Ptr is being used to assign array
>constraints to the dope vector. But I'm guessing that GNAT doesn't
>define these dope vectors using this sort of definition.
>
>I haven't done much development in Ada, so I'm at a loss here. I'm
>making the assumption that the way this code was implemented
>(somewhere between 1992 and 98) was not really the right way to
>approach this problem. But I'm not sure what method should be used,
>and haven't had much luck the past few days searching the web and
>newsgroups.
>
>I would have thought I could have defined the Dev_Table differently,
>perhaps:
>
>Dev_Table : Dev_Table_Ptr_Type := new Dev_Table_Type( 1 ..
>Num_Devs_Cnst );
>
>If I knew the address of pointer at the time of declaration I figured
>I could do:
>
>for Dev_Table'Address use {address_of_memory_array} - but I won't know
>that until run time, so I'm not sure how I can assign that properly.
>
>I hope I'm making sense here - because I'm pretty confused about all
>of this at the moment... :-)
>
>Thanks
>-Al
>




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

* Re: Memory Access
  2011-11-07 20:09 Memory Access awdorrin
  2011-11-07 21:26 ` Simon Wright
  2011-11-07 22:03 ` anon
@ 2011-11-07 22:21 ` Adam Beneschan
  2011-11-07 22:42   ` Adam Beneschan
  2011-11-07 23:13   ` Simon Wright
  2011-11-07 22:26 ` Niklas Holsti
  3 siblings, 2 replies; 20+ messages in thread
From: Adam Beneschan @ 2011-11-07 22:21 UTC (permalink / raw)


On Nov 7, 12:09 pm, awdorrin <awdor...@gmail.com> wrote:

> I would have thought I could have defined the Dev_Table differently,
> perhaps:
>
> Dev_Table : Dev_Table_Ptr_Type := new Dev_Table_Type( 1 ..
> Num_Devs_Cnst );
>
> If I knew the address of pointer at the time of declaration I figured
> I could do:
>
> for Dev_Table'Address use {address_of_memory_array} - but I won't know
> that until run time, so I'm not sure how I can assign that properly.

I'm not 100% clear on what you're trying to do.  First of all, what
will you have at runtime: the address of the array (i.e. the address
of the first element of the array), or the address of a POINTER to the
array (i.e. the address of a word that contains the address of the
first element of the array)?  Your code above will declare Dev_Table
to be a pointer, and then the "for ... use" clause will tell it what
the address of the POINTER will be--not the address of the data in the
array.

I'm assuming that isn't what you want.

If you known the address of the array data, then something like this
will work even if you don't know the address until runtime:

    Data_Address : System.Address;
    ...
begin
    -- do some stuff that sets Data_Address to the address.  Or you
could make
    -- Data_Address be a parameter to a subroutine, or something
    -- Then:

    declare
       Dev_Table : Dev_Table_Type (1 .. Num_Devs_Cnst);
       for Dev_Table'Address use Data_Address;
    begin
       -- and you can use Dev_Table in here
    end;

This will work whether Num_Devs_Cnst is known at compile time or not.
(The _Cnst makes it look like it's a constant that's known at compile
time.  But it doesn't need to be.)

You can use Dev_Table inside the begin..end block, and you can pass it
as a parameter to subroutines that take an unconstrained
Dev_Table_Type parameter.  However, I don't think there's a portable
way to declare a Dev_Table_Ptr_Type, which is an access to an
unconstrained array, and set it up so that it points to an array at
Data_Address with bounds 1 and Num_Dev_Cnst.  The Ada language
restricts this because I don't think it's possible to make this work
in every implementation, depending on how access-to-unconstrained-
array types are implemented.  Hopefully you won't need the pointer
type, and the example I gave is good enough for you to use.

                              -- Adam





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

* Re: Memory Access
  2011-11-07 20:09 Memory Access awdorrin
                   ` (2 preceding siblings ...)
  2011-11-07 22:21 ` Adam Beneschan
@ 2011-11-07 22:26 ` Niklas Holsti
  2011-11-07 22:53   ` Adam Beneschan
  3 siblings, 1 reply; 20+ messages in thread
From: Niklas Holsti @ 2011-11-07 22:26 UTC (permalink / raw)


On 11-11-07 21:09 , awdorrin wrote:
> I am trying to migrate source code from an older AdaMulti compiler
> than ran on Solaris to GNAT on Linux.
>
> The original program makes use of shared memory and has structures
> populated in C code that are accessed within Ada code.

By "shared memory", do you mean the "System V" inter-process 
communication mechanism that involves kernel calls to map shared memory 
areas into the address space of a process? Or do you mean just some 
variables within one and the same process and address space that are 
shared (accessed) by different threads, in different languages, but 
within the same process and same address space?

Are the structures (variables) defined (that is, allocated) in C code 
and imported into the Ada code, or vice versa?

Are they statically allocated or dynamically allocated?

How are the variables passed between the C code and the Ada code? As 
parameters in subprogram calls, or through some kind of global pointers 
or addresses?

> The original developers used some AdaMulti 'features' that do not
> appear to exist within GNAT to play some tricks on setting up a
> pointer as an array of records.
>
> For instance:
>
> Config_Type is an Ada Record which matches a C struct.
> A Dev_Table is used as an array of these Config_Type records.
>
> The original code has the following statements:
>
> type Dev_Table_Type is array (Device_Num_Type range<>) of
> Config_Type;
> type Dev_Table_Ptr_Type is access Dev_Table_Type;
> Dev_Table := Dev_Table_Ptr_Type;
> Bounds_Ptr : Global_Types.Int_Ptr_Type;
>
> Then, in the Ada Procedure we have:
>
> Dev_Data_Obj := Get_Object_Pointer( Dev_Data_Obj_Name );

What is Dev_Data_Obj_Name?
What is Get_Object_Pointer?
What is Dev_Data_Obj?

>
> Dev_Table := To_Dev_Table_Ptr( Get_UDP( Dev_Data_Obj) );

What is Get_UDP?

>
> Bounds_Ptr := Dev_Table_Ptr_To_Int_Ptr( Dev_Table );
> Bounds_Ptr.all := 1;
>
> Bounds_Ptr := Int_To_Int_Ptr( Dev_Table_Ptr_To_Int( Dev_Table ) + 4);
> Bounds_Ptr.all := Int32( Num_Devs_Cnst );

What is Num_Devs_Cnst? Is it a static (compile-time) constant, or a 
dynamically computed variable?

>
> The To_Dev_Table_Ptr, Dev_Table_Ptr_To_Int_Ptr, Int_To_Int_Ptr are all
> unchecked conversion methods.

Such conversions beween access types and other types should be avoided 
(as unportable). Current Ada has better facilities (see 
System.Address_To_Access_Conversions, if my memory serves; can't look it 
up, sorry, my mobile net connection is too puny).

>
> I understand that the Bounds_Ptr is being used to assign array
> constraints to the dope vector.

That looks likely, from the code above.

> But I'm guessing that GNAT doesn't
> define these dope vectors using this sort of definition.

Whatever kind of dope vectors GNAT has, one should not access them 
through such low-level and unportable tricks.

>
> I'm
> making the assumption that the way this code was implemented
> (somewhere between 1992 and 98) was not really the right way to
> approach this problem.

I fully agree with that.

> But I'm not sure what method should be used,
> and haven't had much luck the past few days searching the web and
> newsgroups.
>
> I would have thought I could have defined the Dev_Table differently,
> perhaps:
>
> Dev_Table : Dev_Table_Ptr_Type := new Dev_Table_Type( 1 ..
> Num_Devs_Cnst );
>
> If I knew the address of pointer at the time of declaration I figured
> I could do:
>
> for Dev_Table'Address use {address_of_memory_array} - but I won't know
> that until run time, so I'm not sure how I can assign that properly.
>
> I hope I'm making sense here - because I'm pretty confused about all
> of this at the moment... :-)

I think you are on the right track, or tracks, but the solution depends 
on the answers to my questions above.

While waiting for the answers: I hope you are already using pragma 
Convention to tell the Ada compiler to lay out the Ada record types and 
array types following the C conventions.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .



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

* Re: Memory Access
  2011-11-07 22:21 ` Adam Beneschan
@ 2011-11-07 22:42   ` Adam Beneschan
  2011-11-07 23:13   ` Simon Wright
  1 sibling, 0 replies; 20+ messages in thread
From: Adam Beneschan @ 2011-11-07 22:42 UTC (permalink / raw)


On Nov 7, 2:21 pm, Adam Beneschan <a...@irvine.com> wrote:
>
> If you known the address of the array data, then something like this
> will work even if you don't know the address until runtime:
>
>     Data_Address : System.Address;
>     ...
> begin
>     -- do some stuff that sets Data_Address to the address.  Or you
>     -- could make
>     -- Data_Address be a parameter to a subroutine, or something
>     -- Then:
>
>     declare
>        Dev_Table : Dev_Table_Type (1 .. Num_Devs_Cnst);
>        for Dev_Table'Address use Data_Address;
>     begin
>        -- and you can use Dev_Table in here
>     end;
>
> This will work whether Num_Devs_Cnst is known at compile time or not.
> (The _Cnst makes it look like it's a constant that's known at compile
> time.  But it doesn't need to be.)

An alternative, if you don't want to use an Address clause:

with System.Address_To_Access_Conversions;

...
   Data_Address : System.Address;
begin
   -- set Data_Address to something as above
   declare
      subtype Constrained_Dev_Table is Dev_Table_Type (1 ..
Num_Devs_Cnst);
      package Dev_Table_Pointer is new
         System.Address_To_Access_Conversions (Constrained_Dev_Table);
      Dev_Table : Dev_Table_Pointer.Object_Pointer :=
         Dev_Table_Pointer.To_Pointer (Data_Address);
   begin
      ...
   end;

Dev_Table is now declared as an access (pointer) to a constrained
array subtype, rather than an array, but you should still be able to
use it in the same way.  This method still won't let you create a
Dev_Table_Ptr_Type that points to the array, though.

                       -- Adam



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

* Re: Memory Access
  2011-11-07 22:26 ` Niklas Holsti
@ 2011-11-07 22:53   ` Adam Beneschan
  0 siblings, 0 replies; 20+ messages in thread
From: Adam Beneschan @ 2011-11-07 22:53 UTC (permalink / raw)


On Nov 7, 2:26 pm, Niklas Holsti <niklas.hol...@tidorum.invalid>
wrote:
>
> While waiting for the answers: I hope you are already using pragma
> Convention to tell the Ada compiler to lay out the Ada record types and
> array types following the C conventions.

Or using record representation clauses and other attributes such as
'Component_Size to specify all that.  If the Dev_ in the names means
that the types involved are related to some kind of memory-mapped
devices, then the layouts of the record and array types are defined by
the hardware and not by the C language or C compiler, so using
Convention(C) on such types seems like the wrong approach.

                         -- Adam




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

* Re: Memory Access
  2011-11-07 22:21 ` Adam Beneschan
  2011-11-07 22:42   ` Adam Beneschan
@ 2011-11-07 23:13   ` Simon Wright
  2011-11-07 23:32     ` Adam Beneschan
  1 sibling, 1 reply; 20+ messages in thread
From: Simon Wright @ 2011-11-07 23:13 UTC (permalink / raw)


Adam Beneschan <adam@irvine.com> writes:

>     declare
>        Dev_Table : Dev_Table_Type (1 .. Num_Devs_Cnst);
>        for Dev_Table'Address use Data_Address;
>     begin
>        -- and you can use Dev_Table in here
>     end;

One thing to be wary of here is that Dev_Table might contain initialised
components.

   type Integer_P is access all integer;
   type Rec is record
      I : Integer_P;
   end record;
   R : Rec;
   for R'Address use ...;

may well get R.I initialised to null.

I don't know whether it's a GNAT convention, but the way to avoid this
in GNAT is to add

   pragma Import (Ada, R);


The other thing is, you could declare an array type as large as you like
- in a package body - and provide access subprograms, something like

with Ada.Text_IO; use Ada.Text_IO;
with System;
procedure Devs is

   type Config_Type is record
      Name : String (1 .. 4);
      Size : Natural;
   end record;
   pragma Convention (C, Config_Type);

   Max_Devices : constant := 1024;
   type Device_Index is range 1 .. Max_Devices;

   type Dev_Table_Type is array (Device_Index range <>) of Config_Type;
   pragma Convention (C, Dev_Table_Type);

   --  Set up at initialization
   Dev_Table_Address : System.Address;
   Number_Of_Devices : Device_Index;

   procedure Set_Size (For_Device : Device_Index; To : Natural) is
      Dev_Table : Dev_Table_Type (1 .. Number_Of_Devices);
      for Dev_Table'Address use Dev_Table_Address;
      pragma Import (Ada, Dev_Table);
   begin
      Dev_Table (For_Device).Size := To;
   end Set_Size;

   function Name (Of_Device : Device_Index) return String is
      Dev_Table : Dev_Table_Type (1 .. Number_Of_Devices);
      for Dev_Table'Address use Dev_Table_Address;
      pragma Import (Ada, Dev_Table);
   begin
      return Dev_Table (Of_Device).Name;
   end Name;

   Devs : Dev_Table_Type (1 .. 2) :=
     (("aaaa", 21),
      ("bbbb", 42));

begin
   Dev_Table_Address := Devs'Address;
   Number_Of_Devices := Devs'Length;

   Put_Line (Name (Of_Device => 2));
   Put_Line (Name (Of_Device => 3));  -- raises Constraint_Error
end Devs;



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

* Re: Memory Access
  2011-11-07 23:13   ` Simon Wright
@ 2011-11-07 23:32     ` Adam Beneschan
  2011-11-08 12:22       ` awdorrin
  2011-11-08 12:44       ` Simon Wright
  0 siblings, 2 replies; 20+ messages in thread
From: Adam Beneschan @ 2011-11-07 23:32 UTC (permalink / raw)


On Nov 7, 3:13 pm, Simon Wright <si...@pushface.org> wrote:
> Adam Beneschan <a...@irvine.com> writes:
> >     declare
> >        Dev_Table : Dev_Table_Type (1 .. Num_Devs_Cnst);
> >        for Dev_Table'Address use Data_Address;
> >     begin
> >        -- and you can use Dev_Table in here
> >     end;
>
> One thing to be wary of here is that Dev_Table might contain initialised
> components.
>
>    type Integer_P is access all integer;
>    type Rec is record
>       I : Integer_P;
>    end record;
>    R : Rec;
>    for R'Address use ...;
>
> may well get R.I initialised to null.
>
> I don't know whether it's a GNAT convention, but the way to avoid this
> in GNAT is to add
>
>    pragma Import (Ada, R);

Yes, I forgot that; my example above should include pragma Import
(Ada, Dev_Table).  I think this is in the RM.  It isn't GNAT-specific.

                           -- Adam



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

* Re: Memory Access
  2011-11-07 23:32     ` Adam Beneschan
@ 2011-11-08 12:22       ` awdorrin
  2011-11-08 16:00         ` Adam Beneschan
  2011-11-08 16:10         ` awdorrin
  2011-11-08 12:44       ` Simon Wright
  1 sibling, 2 replies; 20+ messages in thread
From: awdorrin @ 2011-11-08 12:22 UTC (permalink / raw)


Thanks for the responses everyone - it will take me a little while to
go through these and make sure I understand everything.

To answer some questions and clarify things a bit: The original code
was written in Ada83, which is probably why this code was implemented
like this in the first place. We have Ada95 capable compilers
available on both platforms. My primary goal is to get this code
functional on Linux under GNAT but the secondary goal would be to
determine a replacement method that would work on both platforms.

I simplified the example I presented above. There is another Ada
Package called 'DataManager' which holds common data structures. The
Get_Object_Pointer and Get_UDP calls are from the DataManager package.

During elaboration of the package that this code is in (RDevice) a
configuration file is read which determines the number of devices that
need to be held in the Dev_Table, this value is set in Num_Devs_Cnst.
A call is made to the DataManager to allocate the memory needed from a
larger memory segment which was previously obtained through a malloc
of several MB. This memory segment is referred to as a 'Unique Data'
area, so the UDP stands for 'Unique Data Pointer.

All of these manipulations are trying to overlay the memory reserved
in the DataManager into the RDevice's Dev_Table so that the RDevice
package can read a data file and populate the records in Dev_Table.

I had originally thought that I could use a declare section and the
for 'Address notation to link the memory (as Adam suggested) - but the
problem with this code is that the Dev_Table is defined as a global
variable within the package and I don't know the memory address until
run time.

I'm not sure if, since Dev_Table is defined as a Dev_Table_Ptr_Type,
which is access of Dev_Table_Type (which is the unconstrained array)
if I could use a declare segment with a for'Address clause on another
temporary variable of Dev_Table_Ptr_Type, and assign that to the
Dev_Table.
Something like:

declare
  tempDevTable : Dev_Table_Ptr_Type := new Dev_Table_Type( 1 ..
Num_Devs_Cnst );
  for tempDevTable'Address use Dev_Data_Obj;
begin
  Dev_Table := tempDevTable;
end

I'm thinking this would not work - too used to C pointers I suppose
where it doesn't matter. ;)

Thanks



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

* Re: Memory Access
  2011-11-07 23:32     ` Adam Beneschan
  2011-11-08 12:22       ` awdorrin
@ 2011-11-08 12:44       ` Simon Wright
  1 sibling, 0 replies; 20+ messages in thread
From: Simon Wright @ 2011-11-08 12:44 UTC (permalink / raw)


Adam Beneschan <adam@irvine.com> writes:

> On Nov 7, 3:13 pm, Simon Wright <si...@pushface.org> wrote:
>> Adam Beneschan <a...@irvine.com> writes:
>> >     declare
>> >        Dev_Table : Dev_Table_Type (1 .. Num_Devs_Cnst);
>> >        for Dev_Table'Address use Data_Address;
>> >     begin
>> >        -- and you can use Dev_Table in here
>> >     end;
>>
>> One thing to be wary of here is that Dev_Table might contain initialised
>> components.
>>
>>    type Integer_P is access all integer;
>>    type Rec is record
>>       I : Integer_P;
>>    end record;
>>    R : Rec;
>>    for R'Address use ...;
>>
>> may well get R.I initialised to null.
>>
>> I don't know whether it's a GNAT convention, but the way to avoid this
>> in GNAT is to add
>>
>>    pragma Import (Ada, R);
>
> Yes, I forgot that; my example above should include pragma Import
> (Ada, Dev_Table).  I think this is in the RM.  It isn't GNAT-specific.

ARM05 B.1(38) - http://www.adaic.org/resources/add_content/standards/05aarm/html/AA-B-1.html#I7050



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

* Re: Memory Access
  2011-11-08 12:22       ` awdorrin
@ 2011-11-08 16:00         ` Adam Beneschan
  2011-11-08 17:46           ` awdorrin
  2011-11-08 16:10         ` awdorrin
  1 sibling, 1 reply; 20+ messages in thread
From: Adam Beneschan @ 2011-11-08 16:00 UTC (permalink / raw)


On Nov 8, 4:22 am, awdorrin <awdor...@gmail.com> wrote:
> Something like:
>
> declare
>   tempDevTable : Dev_Table_Ptr_Type := new Dev_Table_Type( 1 ..
> Num_Devs_Cnst );
>   for tempDevTable'Address use Dev_Data_Obj;
> begin
>   Dev_Table := tempDevTable;
> end
>
> I'm thinking this would not work - too used to C pointers I suppose
> where it doesn't matter. ;)

You're right: this would *not* work.

Here's what the above code would do.  tempDevTable is a pointer
object, which may be one word or three words (or something else)
depending on the implementation.  This pointer *object* would be
located at Dev_Data_Obj---not the pointed-to data.  The "new"
operation causes the program to allocate memory from a storage pool.
The memory it allocates will be enough to hold Num_Devs_Cnst objects
of type Config_Type.  The point here is that the "new" always means to
allocate memory from a storage pool; you can't use an 'Address clause
to change the meaning of "new" to something else, which is what I
think you were trying to do.

You're saying that Dev_Table is a global access to an unconstrained
array, and it sounds to me like you're trying to get Dev_Table to
point to some arbitrary address that isn't known until runtime.
Unfortunately, I don't think there's a portable way to do that in Ada
(because the implementation of unconstrained arrays differs between
implementations).  In fact, there may not be a good way to do it at
all in GNAT, even non-portably.

A possibility is to make Dev_Table an access to a *constrained*
array.  If Num_Devs_Cnst is a constant that is known at compile time,
you could declare

  subtype Constrained_Dev_Table is Dev_Table_Type (1 ..
Num_Devs_Cnst);
  type Dev_Table_Ptr_Type is access all Constrained_Dev_Table;

and now there are a couple ways to make Dev_Table_Ptr_Type point to
what you want.  Here's one, based on an example I gave earlier:

   with System.Address_To_Access_Conversions;

then declare the following **globally** (not inside a subprogram):

   package Dev_Table_Pointer is new
         System.Address_To_Access_Conversions
(Constrained_Dev_Table);

and now, to make Dev_Table point to the data at address Dev_Data_Obj:

   Dev_Table := Dev_Table_Ptr_Type (Dev_Table_Pointer.To_Pointer
(Dev_Data_Obj));

If Num_Devs_Cnst isn't known at compile time, you could still declare
a constrained array type:

  subtype Constrained_Dev_Table is Dev_Table_Type (1 .. Integer'Last);

and do the same as above.  But then you have to do extra work to make
sure that you don't later access a Dev_Table element outside the range
1 .. Num_Devs_Cnst.  One way is that whenever you want to work with
Dev_Table:

  declare
     Actual_Dev_Table : Dev_Table_Type renames Dev_Table (1 ..
Num_Devs_Cnst);
        -- or Dev_Table.all (1 .. Num_Devs_Cnst), which means the same
thing
  begin
     --
     Something := Actual_Dev_Table (NNN).Something;
        -- will raise Constraint_Error if NNN is out of range 1 ..
Num_Devs_Cnst
  end;

Hope this helps.

                        -- Adam




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

* Re: Memory Access
  2011-11-08 12:22       ` awdorrin
  2011-11-08 16:00         ` Adam Beneschan
@ 2011-11-08 16:10         ` awdorrin
  2011-11-08 18:33           ` Simon Wright
  1 sibling, 1 reply; 20+ messages in thread
From: awdorrin @ 2011-11-08 16:10 UTC (permalink / raw)


I think I have myself rather confused at the moment with all of
this...

Reviewing the code more - I now have a different understanding of what
Dev_Table is meant to be.

I think that Dev_Table is supposed to be an array of
Dev_Table_Ptr_Type (an array of pointer addresses) that point to the
Dev_Table_Type array of Config_Type records.

Stepping through the code with GDB has shed some light, although not a
solution to my problem, quite yet.

The problem I'm running into is a SegFault when the code tries to
assign a value read from the data file.

  Dev_Table(Dev_Num).Dev_Name := Current_Dev_Name;

GDB cannot resolve what Dev_Table(Dev_Num) is - I'm thinking because
it and Ada isn't seeing Dev_Table as an array of pointers.

Showing my ignorance/lack of familiarity with the Ada language here I
think... :)




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

* Re: Memory Access
  2011-11-08 16:00         ` Adam Beneschan
@ 2011-11-08 17:46           ` awdorrin
  2011-11-08 20:11             ` Adam Beneschan
  0 siblings, 1 reply; 20+ messages in thread
From: awdorrin @ 2011-11-08 17:46 UTC (permalink / raw)


On Nov 8, 11:00 am, Adam Beneschan <a...@irvine.com> wrote:
>
> You're saying that Dev_Table is a global access to an unconstrained
> array, and it sounds to me like you're trying to get Dev_Table to
> point to some arbitrary address that isn't known until runtime.
> Unfortunately, I don't think there's a portable way to do that in Ada
> (because the implementation of unconstrained arrays differs between
> implementations).  In fact, there may not be a good way to do it at
> all in GNAT, even non-portably.
>
> A possibility is to make Dev_Table an access to a *constrained*
> array.  If Num_Devs_Cnst is a constant that is known at compile time,
> you could declare
>
>   subtype Constrained_Dev_Table is Dev_Table_Type (1 ..
> Num_Devs_Cnst);
>   type Dev_Table_Ptr_Type is access all Constrained_Dev_Table;
>
> and now there are a couple ways to make Dev_Table_Ptr_Type point to
> what you want.  Here's one, based on an example I gave earlier:
>
>    with System.Address_To_Access_Conversions;
>
> then declare the following **globally** (not inside a subprogram):
>
>    package Dev_Table_Pointer is new
>          System.Address_To_Access_Conversions
> (Constrained_Dev_Table);
>
> and now, to make Dev_Table point to the data at address Dev_Data_Obj:
>
>    Dev_Table := Dev_Table_Ptr_Type (Dev_Table_Pointer.To_Pointer
> (Dev_Data_Obj));
>
> If Num_Devs_Cnst isn't known at compile time, you could still declare
> a constrained array type:
>
>   subtype Constrained_Dev_Table is Dev_Table_Type (1 .. Integer'Last);
>
> and do the same as above.  But then you have to do extra work to make
> sure that you don't later access a Dev_Table element outside the range
> 1 .. Num_Devs_Cnst.  One way is that whenever you want to work with
> Dev_Table:
>
>   declare
>      Actual_Dev_Table : Dev_Table_Type renames Dev_Table (1 ..
> Num_Devs_Cnst);
>         -- or Dev_Table.all (1 .. Num_Devs_Cnst), which means the same
> thing
>   begin
>      --
>      Something := Actual_Dev_Table (NNN).Something;
>         -- will raise Constraint_Error if NNN is out of range 1 ..
> Num_Devs_Cnst
>   end;
>
> Hope this helps.
>
>                         -- Adam


Adam, Thanks - I tried your suggestion and it looks like it may be
working. At least the code is no longer SegFaulting ;)

Now I just have to try to understand what is actually going on with
those commands.

I'm assuming that the subtype is setting the bounds on the array. so
that the Dev_Table_Ptr_Type is now able to see the elements.
The Dev_Table_Pointer.To_Pointer is mapping the address to an access
type.
I'm not quite sure I understand why the package definition for
Dev_Table_Pointer is needed - and why
System.Address_To_Access_Conversions cannot be used directly... i'm
guessing its due to Ada type checking?

Thanks!



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

* Re: Memory Access
  2011-11-08 16:10         ` awdorrin
@ 2011-11-08 18:33           ` Simon Wright
  2011-11-08 18:34             ` Simon Wright
  2011-11-08 20:18             ` awdorrin
  0 siblings, 2 replies; 20+ messages in thread
From: Simon Wright @ 2011-11-08 18:33 UTC (permalink / raw)


awdorrin <awdorrin@gmail.com> writes:

> I think I have myself rather confused at the moment with all of
> this...
>
> Reviewing the code more - I now have a different understanding of what
> Dev_Table is meant to be.
>
> I think that Dev_Table is supposed to be an array of
> Dev_Table_Ptr_Type (an array of pointer addresses) that point to the
> Dev_Table_Type array of Config_Type records.

Yuo said:
   The original code has the following statements:

   type Dev_Table_Type is array (Device_Num_Type range <>) of Config_Type;
   type Dev_Table_Ptr_Type is access Dev_Table_Type;
   Dev_Table := Dev_Table_Ptr_Type;
   Bounds_Ptr : Global_Types.Int_Ptr_Type;

which looks pretty clear to me! If that's what the original compiler
worked with, then .... oh. It can't possibly be what the original
compiler worked with; just look at

   Dev_Table := Dev_Table_Ptr_Type;

.... perhaps the '=' is a typo?

Assuming it is, then Dev_Table is a pointer to an array of Config_Types.

> Stepping through the code with GDB has shed some light, although not a
> solution to my problem, quite yet.
>
> The problem I'm running into is a SegFault when the code tries to
> assign a value read from the data file.
>
>   Dev_Table(Dev_Num).Dev_Name := Current_Dev_Name;
>
> GDB cannot resolve what Dev_Table(Dev_Num) is - I'm thinking because
> it and Ada isn't seeing Dev_Table as an array of pointers.

GDB doesn't always understand things completely.

Dev_Table(Dev_Num) is an implicit dereference of the pointer Dev_Table,
which desgnates the Dev_Num'th element of the array or Config_Types; and
.Dev_Name is the record component of that element. It could have been
written

   Dev_Table.all(Dev_Num).Dev_Name := Current_Dev_Name;

In passing, I see someone with a C background was responsible for the
naming conventions. Why Dev_Name? just Name would have done
perfectly. Oh well, the least of your worries, I'm sure!



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

* Re: Memory Access
  2011-11-08 18:33           ` Simon Wright
@ 2011-11-08 18:34             ` Simon Wright
  2011-11-08 20:18             ` awdorrin
  1 sibling, 0 replies; 20+ messages in thread
From: Simon Wright @ 2011-11-08 18:34 UTC (permalink / raw)


Simon Wright <simon@pushface.org> writes:

> Yuo said:

Sorry, "You" of course, don't know who Yuo is ...



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

* Re: Memory Access
  2011-11-08 17:46           ` awdorrin
@ 2011-11-08 20:11             ` Adam Beneschan
  2011-11-08 20:24               ` awdorrin
  0 siblings, 1 reply; 20+ messages in thread
From: Adam Beneschan @ 2011-11-08 20:11 UTC (permalink / raw)


On Nov 8, 9:46 am, awdorrin <awdor...@gmail.com> wrote:
>
> Now I just have to try to understand what is actually going on with
> those commands.
>
> I'm assuming that the subtype is setting the bounds on the array. so
> that the Dev_Table_Ptr_Type is now able to see the elements.

Something like that.  The subtype declaration says that every object
of that subtype has those bounds.  This also means that for any object
X of type Dev_Table_Ptr_Type, X.all has those bounds too.  The reason
that's important is because the bounds don't have to be stored
somewhere else.  If you have an access-to-an-unconstrained array, then
for any object X with that access type, the bounds have to be stored
somewhere along with X.  The problem is that it's left up to the
implementation just how to store those bounds.  It looks like AdaMulti
makes X a three-word object containing a data address, the lower
bound, and the upper bound; while GNAT stores them differently.


> The Dev_Table_Pointer.To_Pointer is mapping the address to an access
> type.
> I'm not quite sure I understand why the package definition for
> Dev_Table_Pointer is needed - and why
> System.Address_To_Access_Conversions cannot be used directly... i'm
> guessing its due to Ada type checking?

System.Address_To_Access_Conversions is a generic package.  You can't
use a generic package directly; you have to instantiate it.  In this
case, you have to instantiate it with a type.  And yes, I think that
this needs to be a generic because of type checking; Ada doesn't have
the equivalent of a (void *) that you can typecast willy-nilly between
other pointer types and screw yourself up royally.

                        -- Adam



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

* Re: Memory Access
  2011-11-08 18:33           ` Simon Wright
  2011-11-08 18:34             ` Simon Wright
@ 2011-11-08 20:18             ` awdorrin
  1 sibling, 0 replies; 20+ messages in thread
From: awdorrin @ 2011-11-08 20:18 UTC (permalink / raw)


On Nov 8, 1:33 pm, Simon Wright <si...@pushface.org> wrote:

> which looks pretty clear to me! If that's what the original compiler
> worked with, then .... oh. It can't possibly be what the original
> compiler worked with; just look at
>
>    Dev_Table := Dev_Table_Ptr_Type;
>
> .... perhaps the '=' is a typo?

Yes - that was a typo on my part! :)



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

* Re: Memory Access
  2011-11-08 20:11             ` Adam Beneschan
@ 2011-11-08 20:24               ` awdorrin
  2011-11-09 14:42                 ` awdorrin
  0 siblings, 1 reply; 20+ messages in thread
From: awdorrin @ 2011-11-08 20:24 UTC (permalink / raw)


Adam - thanks that makes sense.

I found 10 locations throughout the code that were doing this. I was
able to adapt 6 of them using this approach, however the others look a
bit different, so I'm going to have to dig a little deeper so I
understand whats going on.

Really do appreciate the assistance, I've been spinning my wheels on
this for over a week now.

-Al






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

* Re: Memory Access
  2011-11-08 20:24               ` awdorrin
@ 2011-11-09 14:42                 ` awdorrin
  0 siblings, 0 replies; 20+ messages in thread
From: awdorrin @ 2011-11-09 14:42 UTC (permalink / raw)


I have two of these array manipulations left to resolve, but these
ones are done differently, and I don't think I can use the same
approach as above... at least I'm not sure how I could.

Defined in another package's spec file is the following:

type DAM_Table_Type is array (INT32 range <>) of
G_DataMgr.Node_Ptr_Type;
type BAM_Table_Type is array (INT32 range <>) of BAM_Record_Type;

type DAM_Table_Ptr_Type is access DAM_Table_Type;
type BAM_Table_Ptr_Type is access BAM_Table_Type;

Then there is a record defined as:

type Device_UD_Type is
  record
    ... other elements ...
    First_MsgId : INT32;
    Last_MsgId  : INT32;
    ... more elements ...
    DAM_Table_Ptr : DAM_Table_Ptr_Type;
    BAM_Table_Ptr : BAM_Table_Ptr_Type;
  end record;

Then in another package there is a procedure that does the following:

--DevUDP is the pointer to the device unique data area (the Dev_Table
mentioned previously) which is of record type Device_UD_Type;

Size := (1 + DevUDP.all.Last_MsgId - DevUDP.all.First_MsgId) *
(Node_Ptr_Type'Size / 8); -- number of bytes needed

DevUDP.all.DAM_Table_Ptr :=
Addr_To_DAM_Table_Ptr( G_DataMgr.Allocate_User_Data( Size + 8 ) );

-- here is where the dope vectors are set in the old code

DevUDP.all.DAM_Table_Ptr.all := (others => NULL); -- initialize the
table

-- after here is where the table gets populated
-- The DAM_Table_Ptr is accessed like:
DevUDP.all.DAM_Table_Ptr.all( MsgId ) := Msg;

Best I can tell is that the size isn't known until runtime - its not
like the previous cases.
The Allocate_User_Data gives a section of memory previously obtained
from a shmget() call from the C code.

The same problem exists as previously, how to point the access type to
a specific location in memory.
I just don't think I know where I can define a constrained array
subtype, since this time, the number of elements isn't known at
elaboration time.

There isn't a way I could define the subtype using: range
DevUDP.all.First_MsgId .. DevUDP.all.Last_MsgId, is there?
(Assuming no since these would be uninitialized/zero.)

Coming from a C background - I still don't quite understand why this
is so hard to do in Ada, point an access pointer to a memory segment.
I guess it all comes back to their defining an unconstrained array and
then wanting to set the bounds.
Too bad you can't just set the bound manually...

Been reading through my Ada books and feel like I'm still missing
something in all of this. :-/



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

end of thread, other threads:[~2011-11-09 14:44 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-07 20:09 Memory Access awdorrin
2011-11-07 21:26 ` Simon Wright
2011-11-07 22:03 ` anon
2011-11-07 22:21 ` Adam Beneschan
2011-11-07 22:42   ` Adam Beneschan
2011-11-07 23:13   ` Simon Wright
2011-11-07 23:32     ` Adam Beneschan
2011-11-08 12:22       ` awdorrin
2011-11-08 16:00         ` Adam Beneschan
2011-11-08 17:46           ` awdorrin
2011-11-08 20:11             ` Adam Beneschan
2011-11-08 20:24               ` awdorrin
2011-11-09 14:42                 ` awdorrin
2011-11-08 16:10         ` awdorrin
2011-11-08 18:33           ` Simon Wright
2011-11-08 18:34             ` Simon Wright
2011-11-08 20:18             ` awdorrin
2011-11-08 12:44       ` Simon Wright
2011-11-07 22:26 ` Niklas Holsti
2011-11-07 22:53   ` Adam Beneschan

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