comp.lang.ada
 help / color / mirror / Atom feed
From: Stephen Leake <stephen_leake@stephe-leake.org>
Subject: controlled constant_reference type?
Date: Wed, 14 Mar 2018 01:55:23 -0700 (PDT)
Date: 2018-03-14T01:55:23-07:00	[thread overview]
Message-ID: <977b6908-e955-45de-8315-2902f1a1f1c8@googlegroups.com> (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

             reply	other threads:[~2018-03-14  8:55 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-14  8:55 Stephen Leake [this message]
2018-03-14 10:49 ` controlled constant_reference type? Alejandro R. Mosteo
2018-03-14 22:46 ` Randy Brukardt
replies disabled

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