comp.lang.ada
 help / color / mirror / Atom feed
* Memory Leak
@ 2006-01-03 16:15 markp
  2006-01-03 18:06 ` Jeffrey R. Carter
  0 siblings, 1 reply; 7+ messages in thread
From: markp @ 2006-01-03 16:15 UTC (permalink / raw)


We are experiencing a memory leak in out GNAT Ada program that we
cannot explain. We've narrowed it down to our generic queue package as
the culprit. However, all the memory in the package is allocated at
instantiation. I've attached the source code and if anybody can see
something, it would be greatly appreciated! The data types passed in
during the instantiation are variant records. Lastly, does GNAT provide
any queuing sevices?

Thank you.

generic

-------------------------------------------------------------------------
   --
   -- Generic Formal Parameters
   --

-------------------------------------------------------------------------

   -- The data type for the Message Queue
   type Data_Type is private;

   -- The number of entries in the Message Queue
   Message_Queue_Depth : in Integer;

   Queue_Name : string;

package Generic_Message_Queues is



-----------------------------------------------------------------------
    --
    -- Type Definitions
    --

-----------------------------------------------------------------------

    -- Specifies the Priority Urgency of a message when
    -- a message is put into a Message Queue.

   type Priority_Urgency_Type is (Normal, Urgent);

   -- Indeces into both a high and low priority queue
   type Item_Count is new integer range 0 .. Message_Queue_Depth;
   type Item_Index is new integer range 1 .. Message_Queue_Depth;
   type Item_Array is array (Item_Index) of Data_Type;
   type Priority_Item_Count is new integer range 0 .. 10;
   type Priority_Item_Index is new integer range 1 .. 10;
   type Priority_Item_Array is array (Priority_Item_Index) of
Data_Type;

   protected type Queue_Type is

      -- put a data element into the buffer
      entry Send(Elem               : in Data_Type);

      -- put a data element into the High Priority Queue
      entry High_Priority_Send(Elem : in Data_Type);

      -- retrieve a data element from the buffer
      entry Receive(Elem: out Data_Type);

      -- return Count of number of items
      function Count return Integer;

      -- Clear queue
      procedure Flush;

   private
      Queue_Count          : Item_Count := 0;
      Out_Index            : Item_Index := 1;
      In_Index             : Item_Index := 1;
      Data                 : Item_Array;
      Priority_Queue_Count : Priority_Item_Count := 0;
      Priority_Out_Index   : Priority_Item_Index := 1;
      Priority_In_Index    : Priority_Item_Index := 1;
      Priority_Data        : Priority_Item_Array;
   end Queue_Type;

   -- Clear queue
   procedure Flush;

   -- put a data element into the buffer
   procedure Put(
      Data             : in Data_Type;
      Priority_Urgency : in Priority_Urgency_Type := Normal);

   -- retrieve a data element from the buffer
   procedure Get(
      Data             : out Data_Type);

   -- return Count of number of items
   function Count return Integer;

end Generic_Message_Queues;

package body Generic_Message_Queues is

   protected body Queue_Type is

      -- put a data element into the buffer
      entry Send(Elem: in Data_Type) when integer(Queue_Count) <
Message_Queue_Depth is
           -- block until there is room in the Queue
      begin
         Data(In_Index) := Elem;
         In_Index := In_Index mod Item_Index(Message_Queue_Depth) + 1;
         Queue_Count := Queue_Count + 1;
      end Send;

      -- put a data element into the High Priority Queue
      entry High_Priority_Send(Elem: Data_Type) when
integer(Priority_Queue_Count) < 10 is
           -- block until there is room in the Queue
      begin
         Priority_Data(Priority_In_Index) := Elem;
         Priority_In_Index := Priority_In_Index mod 10 + 1;
         Priority_Queue_Count := Priority_Queue_Count + 1;
      end High_Priority_Send;

      -- retrieve a data element from the buffer
      entry Receive(Elem: out Data_Type) when Queue_Count > 0 or else
Priority_Queue_Count > 0 is
           -- block until there is something in the Queue
      begin
         if Priority_Queue_Count > 0 then
            Elem := Priority_Data(Priority_Out_Index);
            Priority_Out_Index := Priority_Out_Index mod 10 + 1;
            Priority_Queue_Count := Priority_Queue_Count - 1;
         else
            Elem := Data(Out_Index);
            Out_Index := Out_Index mod Item_Index(Message_Queue_Depth)
+ 1;
            Queue_Count := Queue_Count - 1;
         end if;
      end Receive;

      -- Clear queue
      procedure Flush is
      begin

         Queue_Count          := 0;
         Out_Index            := 1;
         In_Index             := 1;
         Priority_Queue_Count := 0;
         Priority_Out_Index   := 1;
         Priority_In_Index    := 1;

      end Flush;

      -- return Count of number of items
      function Count return Integer is
      begin
         return(integer(Queue_Count));
      end Count;

   end Queue_Type;

   Queue : Queue_Type;

   -- Clear queue
   procedure Flush is
   begin
      Queue.Flush;
   end Flush;

   -- put a data element into the buffer
   procedure Put(
      Data             : in Data_Type;
      Priority_Urgency : in Priority_Urgency_Type := Normal) is
   begin

      if Priority_Urgency = Urgent then
         Queue.High_Priority_Send(
            Elem => Data);
      else
         Queue.Send(
            Elem => Data);
     end if;

   end Put;

   -- retrieve a data element from the buffer
   procedure Get(
      Data             : out Data_Type) is
   begin
      Queue.Receive(Elem => Data);
   end Get;

   -- return Count of number of items
   function Count return Integer is
   begin
      Return(Queue.Count);
   end Count;

end Generic_Message_Queues;




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

* Re: Memory Leak
  2006-01-03 16:15 Memory Leak markp
@ 2006-01-03 18:06 ` Jeffrey R. Carter
  2006-01-03 18:57   ` markp
  0 siblings, 1 reply; 7+ messages in thread
From: Jeffrey R. Carter @ 2006-01-03 18:06 UTC (permalink / raw)


markp wrote:
> We are experiencing a memory leak in out GNAT Ada program that we
> cannot explain. We've narrowed it down to our generic queue package as
> the culprit. However, all the memory in the package is allocated at
> instantiation. I've attached the source code and if anybody can see
> something, it would be greatly appreciated! The data types passed in
> during the instantiation are variant records. Lastly, does GNAT provide
> any queuing sevices?

This is a curious monster; it can't decide if it wants to be an ADT or an ASM, 
and queues with negative depths seem to be meaningful. However, there is nothing 
about it that would seem likely to cause a memory leak. It might have something 
to do with where and how it is instantiated, or perhaps the types used to 
instantiate it.

GNAT has GNAT.Bounded_Buffers, or you could use something from one of the many 
fine libraries of Ada components available, like 
PragmARC.Queue_Bounded_Blocking. They have more coherent designs and a better 
grasp of the issues involved in Ada concurrency.

-- 
Jeff Carter
"Nobody expects the Spanish Inquisition!"
Monty Python's Flying Circus
22



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

* Re: Memory Leak
  2006-01-03 18:06 ` Jeffrey R. Carter
@ 2006-01-03 18:57   ` markp
  2006-01-03 19:03     ` Martin Dowie
  2006-01-03 19:05     ` markp
  0 siblings, 2 replies; 7+ messages in thread
From: markp @ 2006-01-03 18:57 UTC (permalink / raw)


Jeff,

Thanks for the help. I tried the GNAT.Bounded_Buffers. It has the exact
same effect. I am not familiar with PragmARC.Queue_Bounded_Blocking.
How can I get my hands on the spec for that?

Thanks,

Mark




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

* Re: Memory Leak
  2006-01-03 18:57   ` markp
@ 2006-01-03 19:03     ` Martin Dowie
  2006-01-03 19:05     ` markp
  1 sibling, 0 replies; 7+ messages in thread
From: Martin Dowie @ 2006-01-03 19:03 UTC (permalink / raw)


markp wrote:
> Jeff,
> 
> Thanks for the help. I tried the GNAT.Bounded_Buffers. It has the exact
> same effect. I am not familiar with PragmARC.Queue_Bounded_Blocking.
> How can I get my hands on the spec for that?


www.google.com

http://home.earthlink.net/~jrcarter010/pragmarc.htm



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

* Re: Memory Leak
  2006-01-03 18:57   ` markp
  2006-01-03 19:03     ` Martin Dowie
@ 2006-01-03 19:05     ` markp
  2006-01-04  4:46       ` Jeffrey R. Carter
  2006-01-05 21:12       ` Ludovic Brenta
  1 sibling, 2 replies; 7+ messages in thread
From: markp @ 2006-01-03 19:05 UTC (permalink / raw)


A couple of more things I should mention: I am running this under
Windows, not Linux. Also, I instantiate this queue package in a package
body that contains a task body. Here's how it's instantiated/used:

with Generic_Message_Queues; pragma Elaborate (Generic_Message_Queues);
with text_io;
with Ada.Exceptions;
package body Process_Data is

   type Queue_Messages_Type is (
      Small_Msg,
      Large_Msg);

   type Queue_Msg(Msg : Queue_Messages_Type := Small_Msg) is
      record
        case Msg is
            when Small_Msg =>
               Small_Msg_Data   : Interface_Types.Small_Msg_Type;
            when Large_Msg =>
               Large_Msg_Data   : Interface_Types.Large_Msg_Type;
         end case;
      end record;

   -- Queue definition
   package My_Queue is new Generic_Message_Queues(
      Data_Type           => Queue_Msg,
      Message_Queue_Depth => 100,
      Queue_Name          => "Process Task Queue");

   task Processing_Task is
      entry Start;
      pragma storage_size(12_048_000);
      pragma priority(15);
   end Processing_Task;

   task body Processing_Task is

      Queue_Data       : Queue_Msg;
      Small_Msg_Data   : Interface_Types.Small_Msg_Type;
      Large_Msg_Data   : Interface_Types.Large_Msg_Type;

   begin

      loop

         Accept Start;

         loop

            -- Pend for data on queue - this is a blocking call
            My_Queue.Get(
               Data         => Queue_Data);

            case Queue_Data.Msg is

               when Small_Msg =>

                  Small_Msg_Data := Queue_Data.Small_Msg_Data;
                  text_io.put_line("Received Small Msg");

               when Large_Msg =>

                  Large_Msg_Data := Queue_Data.Large_Msg_Data;
                  text_io.put_line("Received Large Msg");

            end case;

         end loop;

      end loop;

   exception

      when Current_Exception : others =>
        text_io.put_line("Unhandled
"&Ada.Exceptions.exception_information(
                             Current_Exception));

   end Processing_Task;

   procedure Start is
   begin
      Processing_Task.Start;
   end Start;

   procedure Process_Small_Msg(
      Msg : in Interface_Types.Small_Msg_Type) is

   begin

      My_Queue.Put(
         Data             => (
            Msg             => Small_Msg,
            Small_Msg_Data  => Msg),
         Priority_Urgency   => My_Queue.Normal);

   end Process_Small_Msg;

   procedure Process_Large_Msg(
      Msg : in Interface_Types.Large_Msg_Type) is


   begin

      My_Queue.Put(
         Data             => (
            Msg             => Large_Msg,
            Large_Msg_Data  => Msg),
         Priority_Urgency   => My_Queue.Normal);
         
   end Process_Large_Msg;

end Process_Data;




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

* Re: Memory Leak
  2006-01-03 19:05     ` markp
@ 2006-01-04  4:46       ` Jeffrey R. Carter
  2006-01-05 21:12       ` Ludovic Brenta
  1 sibling, 0 replies; 7+ messages in thread
From: Jeffrey R. Carter @ 2006-01-04  4:46 UTC (permalink / raw)


I see that Dowie beat me to telling you where to find the PragmAda Reusable 
Components.

markp wrote:

>    type Queue_Messages_Type is (
>       Small_Msg,
>       Large_Msg);
> 
>    type Queue_Msg(Msg : Queue_Messages_Type := Small_Msg) is
>       record
>         case Msg is
>             when Small_Msg =>
>                Small_Msg_Data   : Interface_Types.Small_Msg_Type;
>             when Large_Msg =>
>                Large_Msg_Data   : Interface_Types.Large_Msg_Type;
>          end case;
>       end record;

Still nothing obvious. What are the definitions of (Small|Large)_Msg_Type, 
including all definitions they depend on?

-- 
Jeff Carter
"C's solution to this [variable-sized arrays] has real problems,
and people who are complaining about safety definitely have a point."
Dennis Ritchie
25



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

* Re: Memory Leak
  2006-01-03 19:05     ` markp
  2006-01-04  4:46       ` Jeffrey R. Carter
@ 2006-01-05 21:12       ` Ludovic Brenta
  1 sibling, 0 replies; 7+ messages in thread
From: Ludovic Brenta @ 2006-01-05 21:12 UTC (permalink / raw)


"markp" <markwork66@yahoo.com> writes:

> A couple of more things I should mention: I am running this under
> Windows, not Linux.

I like it when people start assuming Linux is the rule and Windows the
exception :)

Sorry, I have no advice to offer.  Just chuckling.

-- 
Ludovic Brenta.



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

end of thread, other threads:[~2006-01-05 21:12 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-01-03 16:15 Memory Leak markp
2006-01-03 18:06 ` Jeffrey R. Carter
2006-01-03 18:57   ` markp
2006-01-03 19:03     ` Martin Dowie
2006-01-03 19:05     ` markp
2006-01-04  4:46       ` Jeffrey R. Carter
2006-01-05 21:12       ` Ludovic Brenta

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