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
next 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