From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=unavailable autolearn_force=no version=3.4.4 X-Received: by 10.107.150.82 with SMTP id y79mr1720372iod.107.1521017723648; Wed, 14 Mar 2018 01:55:23 -0700 (PDT) X-Received: by 10.157.3.237 with SMTP id f100mr208399otf.6.1521017723486; Wed, 14 Mar 2018 01:55:23 -0700 (PDT) Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!feeder.eternal-september.org!news.unit0.net!peer03.am4!peer.am4.highwinds-media.com!peer02.iad!feed-me.highwinds-media.com!news.highwinds-media.com!r195-v6no112070itc.0!news-out.google.com!a25-v6ni427itj.0!nntp.google.com!r195-v6no112064itc.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: comp.lang.ada Date: Wed, 14 Mar 2018 01:55:23 -0700 (PDT) Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=76.218.37.33; posting-account=W2gdXQoAAADxIuhBWhPFjUps3wUp4RhQ NNTP-Posting-Host: 76.218.37.33 User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: <977b6908-e955-45de-8315-2902f1a1f1c8@googlegroups.com> Subject: controlled constant_reference type? From: Stephen Leake Injection-Date: Wed, 14 Mar 2018 08:55:23 +0000 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Received-Bytes: 4609 X-Received-Body-CRC: 257684614 Xref: reader02.eternal-september.org comp.lang.ada:50965 Date: 2018-03-14T01:55:23-07:00 List-Id: I'm trying to create a protected vector container, that automatically provi= des task-safe access. I'm having trouble with GNAT GPL 2017 not finalizing a read lock object, an= d 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 =3D> Constant_Reference, Variable_Indexing =3D> Variable_Reference, Iterator_Element =3D> 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 attem= pt -- to upgrade. function Any_Readers_Or_Writers return Boolean; private Readers : Integer :=3D 0; Writer : Boolean :=3D 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 :=3D False; -- Enforce Initialize called only once (sometimes it's hard to tell -- if Initialize will be called automatically). Finalized : Boolean :=3D 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 :=3D Tree.Terminals (K.Terminal).Byte_Region; begin ... end; Tree.Terminals is a Protected vector; when Child_Byte_Region is set, a temp= orary Constant_Reference_Type object is created; it should live only as lon= g 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 wi= th low optimizations for debugging), Finalize only once. This leaves the Tr= ee.Terminals Guard locked with Readers =3D 1. Even after the block exits, Guard is still locked. I have a similar problem with an Iterator; it locks the Guard while the loo= p is executing, but leaves it locked when the loop exits. Should this work, or is there something about Constant_Indexing that forbid= s Controlled (in which case there ought to be a compile time error)? -- Stephe