comp.lang.ada
 help / color / mirror / Atom feed
* controlled constant_reference type?
@ 2018-03-14  8:55 Stephen Leake
  2018-03-14 10:49 ` Alejandro R. Mosteo
  2018-03-14 22:46 ` Randy Brukardt
  0 siblings, 2 replies; 3+ messages in thread
From: Stephen Leake @ 2018-03-14  8:55 UTC (permalink / raw)


I'm trying to create a protected vector container, that automatically provides task-safe access.

I'm having trouble with GNAT GPL 2017 not finalizing a read lock object, and I'm wondering if this is a compiler error.

Summary of the code in package gen_vectors-gen_protected:

   type Vector is new Ada.Finalization.Controlled with private
   with
      Constant_Indexing => Constant_Reference,
      Variable_Indexing => Variable_Reference,
      Iterator_Element  => Element_Type;


   protected type Guard is

      entry Acquire_Read;
      --  Available when there is no writer.

      procedure Release_Read;

      entry Acquire_Write;
      --  Available when there are no readers, and no writer.

      procedure Release_Write;

      --  It is tempting to provide an operation "update_read_to_write", so
      --  we spend as little time as possible with a write lock. But that
      --  leads to deadlock, if two tasks aquire read lock, then both attempt
      --  to upgrade.

      function Any_Readers_Or_Writers return Boolean;

   private
      Readers : Integer := 0;
      Writer  : Boolean := False;
   end Guard;

   type Vector is new Ada.Finalization.Controlled with record
      Super : Gen_Unbounded_Definite_Vectors.Vector;

      Guard : Guard_Access;
      --  We use an access type here for two reasons:
      --  1 - it allows Vector to be non-limited
      --  2 - it allows writing to Guard when the Vector object is 'in'.
   end record;

   type Read_Lock_Type (Container : not null access constant Vector)
     is new Ada.Finalization.Controlled with
   record
      Initialized : Boolean := False;
      --  Enforce Initialize called only once (sometimes it's hard to tell
      --  if Initialize will be called automatically).

      Finalized : Boolean := False;
      --  Finalize can be called more than once; don't release the guard
      --  more than once.
   end record;

   overriding procedure Initialize (Lock : in out Read_Lock_Type);
   --  Acquire read lock.

   overriding procedure Adjust (Lock : in out Read_Lock_Type);
   --  Acquire read lock again, since both copies will be Finalized.

   overriding procedure Finalize (Lock : in out Read_Lock_Type);
   --  Release read lock.

   type Constant_Reference_Type
     (Element   : not null access constant Element_Type;
      Container : not null access constant Vector)
     is record
      Lock : Read_Lock_Type (Container);
   end record;

Now, when I use Constant_Reference in a client package:

declare
   K : Syntax_Trees.Node renames Children (I);
   Child_Byte_Region : constant Buffer_Region :=
      Tree.Terminals (K.Terminal).Byte_Region;
begin
   ...
end;

Tree.Terminals is a Protected vector; when Child_Byte_Region is set, a temporary Constant_Reference_Type object is created; it should live only as long as needed to copy the data to Child_Byte_Region. However, Read_Lock_Type Initialize is called twice (once for an intermediate copy; I'm compiling with low optimizations for debugging), Finalize only once. This leaves the Tree.Terminals Guard locked with Readers = 1.

Even after the block exits, Guard is still locked.

I have a similar problem with an Iterator; it locks the Guard while the loop is executing, but leaves it locked when the loop exits.

Should this work, or is there something about Constant_Indexing that forbids Controlled (in which case there ought to be a compile time error)?

-- Stephe

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

* Re: controlled constant_reference type?
  2018-03-14  8:55 controlled constant_reference type? Stephen Leake
@ 2018-03-14 10:49 ` Alejandro R. Mosteo
  2018-03-14 22:46 ` Randy Brukardt
  1 sibling, 0 replies; 3+ messages in thread
From: Alejandro R. Mosteo @ 2018-03-14 10:49 UTC (permalink / raw)


I've not analyzed your post in detail (sorry) but I've experienced and 
reported memory leaks due to missing calls to Finalize in the past. 
These were fixed for GPL 2017 though. Also in relation to creating 
references.

My test cases are here, in case you find anything relatable:

https://github.com/mosteo/gnat-gpl-bugs/blob/master/src/fixed/holder_leak.adb
https://github.com/mosteo/gnat-gpl-bugs/blob/master/src/fixed/refleak.adb

Not directly helpful, I'm afraid... Just saying that it might indeed be 
the compiler's fault (when I was a naïve youngling I blamed many times 
the compiler (Turbo Pascal) and it was always my fault. Growing up it 
was a shock to discover that compilers really are buggy too; I still 
can't totally shake the feeling).

Good hunting,
Álex.

On 14/03/18 09:55, Stephen Leake wrote:
> I'm trying to create a protected vector container, that automatically provides task-safe access.
> 
> I'm having trouble with GNAT GPL 2017 not finalizing a read lock object, and I'm wondering if this is a compiler error.
> 
> Summary of the code in package gen_vectors-gen_protected:
> 
>     type Vector is new Ada.Finalization.Controlled with private
>     with
>        Constant_Indexing => Constant_Reference,
>        Variable_Indexing => Variable_Reference,
>        Iterator_Element  => Element_Type;
> 
> 
>     protected type Guard is
> 
>        entry Acquire_Read;
>        --  Available when there is no writer.
> 
>        procedure Release_Read;
> 
>        entry Acquire_Write;
>        --  Available when there are no readers, and no writer.
> 
>        procedure Release_Write;
> 
>        --  It is tempting to provide an operation "update_read_to_write", so
>        --  we spend as little time as possible with a write lock. But that
>        --  leads to deadlock, if two tasks aquire read lock, then both attempt
>        --  to upgrade.
> 
>        function Any_Readers_Or_Writers return Boolean;
> 
>     private
>        Readers : Integer := 0;
>        Writer  : Boolean := False;
>     end Guard;
> 
>     type Vector is new Ada.Finalization.Controlled with record
>        Super : Gen_Unbounded_Definite_Vectors.Vector;
> 
>        Guard : Guard_Access;
>        --  We use an access type here for two reasons:
>        --  1 - it allows Vector to be non-limited
>        --  2 - it allows writing to Guard when the Vector object is 'in'.
>     end record;
> 
>     type Read_Lock_Type (Container : not null access constant Vector)
>       is new Ada.Finalization.Controlled with
>     record
>        Initialized : Boolean := False;
>        --  Enforce Initialize called only once (sometimes it's hard to tell
>        --  if Initialize will be called automatically).
> 
>        Finalized : Boolean := False;
>        --  Finalize can be called more than once; don't release the guard
>        --  more than once.
>     end record;
> 
>     overriding procedure Initialize (Lock : in out Read_Lock_Type);
>     --  Acquire read lock.
> 
>     overriding procedure Adjust (Lock : in out Read_Lock_Type);
>     --  Acquire read lock again, since both copies will be Finalized.
> 
>     overriding procedure Finalize (Lock : in out Read_Lock_Type);
>     --  Release read lock.
> 
>     type Constant_Reference_Type
>       (Element   : not null access constant Element_Type;
>        Container : not null access constant Vector)
>       is record
>        Lock : Read_Lock_Type (Container);
>     end record;
> 
> Now, when I use Constant_Reference in a client package:
> 
> declare
>     K : Syntax_Trees.Node renames Children (I);
>     Child_Byte_Region : constant Buffer_Region :=
>        Tree.Terminals (K.Terminal).Byte_Region;
> begin
>     ...
> end;
> 
> Tree.Terminals is a Protected vector; when Child_Byte_Region is set, a temporary Constant_Reference_Type object is created; it should live only as long as needed to copy the data to Child_Byte_Region. However, Read_Lock_Type Initialize is called twice (once for an intermediate copy; I'm compiling with low optimizations for debugging), Finalize only once. This leaves the Tree.Terminals Guard locked with Readers = 1.
> 
> Even after the block exits, Guard is still locked.
> 
> I have a similar problem with an Iterator; it locks the Guard while the loop is executing, but leaves it locked when the loop exits.
> 
> Should this work, or is there something about Constant_Indexing that forbids Controlled (in which case there ought to be a compile time error)?
> 
> -- Stephe
> 

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

* Re: controlled constant_reference type?
  2018-03-14  8:55 controlled constant_reference type? Stephen Leake
  2018-03-14 10:49 ` Alejandro R. Mosteo
@ 2018-03-14 22:46 ` Randy Brukardt
  1 sibling, 0 replies; 3+ messages in thread
From: Randy Brukardt @ 2018-03-14 22:46 UTC (permalink / raw)


>"Stephen Leake" <stephen_leake@stephe-leake.org> wrote in message 
>news:977b6908-e955-45de-8315-2902f1a1f1c8@googlegroups.com...
>I'm trying to create a protected vector container, that automatically 
>provides task-safe access.
>
>I'm having trouble with GNAT GPL 2017 not finalizing a read lock object,
>and I'm wondering if this is a compiler error.

It's hard to say without doing a complete debug of your code, and I don't 
have time or energy to do that.

An object of a limited controlled type has pretty canonical semantics, and 
there really aren't many optimizations that can be done (mostly just 
omitting temporary objects).

OTOH, an object of a nonlimited controlled type has rather squishy 
semantics, and there are many allowable optimizations.

However, the basic rule of (aggregates + Initialize calls + Adjust calls) = 
Finalize calls is supposed to be true regardless of what optimizations are 
made or not made.

Still, it's a common programming error to forget that aggregates don't call 
Initialize (the assumption is that they completely initialize the object) or 
to forget to take Adjust into account when assignments (like function 
returns) are involved. So I'd check those first, and if those are properly 
accounted for, then it's most likely a compiler bug.

                                  Randy.



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

end of thread, other threads:[~2018-03-14 22:46 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-14  8:55 controlled constant_reference type? Stephen Leake
2018-03-14 10:49 ` Alejandro R. Mosteo
2018-03-14 22:46 ` Randy Brukardt

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