Search code examples
adaunchecked-conversion

Mapping chunk of shared memory for reading/writing in Ada


I have a chunk (1024 bytes) of shared memory between two processes for which I have an address pointing to. I want to copy some data to this shared memory, and read it on the other process. Coming from a C background, it seems easiest to map a record to this address, and then write to the record, but it does not seem to be copying correctly.

Currently, I am trying to convert the pointer to a pointer-to-record type using an Unchecked Conversion, and copy to the record, but I am seeing differences in the data when I compare the original payload with the one received in the second process.

Is this the proper way of doing this?:

type Payload_Array_Type is array (1..255) of Integer_32;

type Common_Buffer_Type is
  record
    Size : Integer_32;
    Payload : Payload_Array_Type;
  end record;

type Common_Buffer_Ptr_Type is access Common_Buffer_Type;

function Convert_Common_Memory_Ptr is new Unchecked_Conversion (
    Source => System.Address,
    Target => Common_Buffer_Ptr_Type);

Common_Memory_Ptr : System.Address;

procedure Copy_To_Common_Buffer
(
    Size : Integer_32;
    Payload : Payload_Array_Type
) is
    Common_Buffer_Ptr : Common_Buffer_Ptr_Type;
begin
    Common_Buffer_Ptr := Convert_Common_Memory_Ptr(Common_Memory_Ptr);
    Common_Buffer_Ptr.Size := Size;
    Common_Buffer_Ptr.Payload(1..255) := Payload(1..255);    
end Copy_To_Common_Buffer;

Solution

  • I would try to do it this way:

    procedure Payload is 
    
       type Payload_Array_Type is array (1..255) of Integer_32;
    
       type Common_Buffer_Type is record
          Size : Integer_32;
          Payload : Payload_Array_Type;
       end record;
       for Common_Buffer_Type use record -- representation clause should be common to both processes
          Size    at 0 range 0 .. 31;
          Payload at 0 range 32 .. 1023;
       end record;
       for Common_Buffer_Type'Size use 1024; -- check this is also used in the other process.
    
       type Common_Buffer_Ptr_Type is access Common_Buffer_Type;
    
       Common_Memory_Ptr : System.Address; -- assuming this is where the shared object resides with a real address, possibly make it constant
    
       procedure Copy_To_Common_Buffer (Size    : in Integer_32;
                        Payload : in Payload_Array_Type) is
          Common_Buffer : Common_Buffer_Type;
          for Common_Buffer'Address use Common_Memory_Ptr; -- address overlay
       begin
          Common_Buffer := (Size => Size,
                Payload => Payload);
       end Copy_To_Common_Buffer;
    
    begin
    
       Copy_To_Common_Buffer (9,(others => 876));
    
    end Payload;
    

    The type definitions should be common to the two processes, and note I've used a representation clause to specify where the components go.

    I've used an address overlay to specify the location of where I'm writing, and written the whole record in one go.

    Also look up usage of pragma volatile as @Brian Drummond suggests.