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 Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: "Alejandro R. Mosteo" Newsgroups: comp.lang.ada Subject: Re: controlled constant_reference type? Date: Wed, 14 Mar 2018 11:49:40 +0100 Organization: A noiseless patient Spider Message-ID: References: <977b6908-e955-45de-8315-2902f1a1f1c8@googlegroups.com> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Injection-Date: Wed, 14 Mar 2018 10:49:40 -0000 (UTC) Injection-Info: reader02.eternal-september.org; posting-host="d9c81ffc92c810d34615660dafe802d2"; logging-data="12401"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/Js0QYw7c/2B0p9FMFco08" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.6.0 In-Reply-To: <977b6908-e955-45de-8315-2902f1a1f1c8@googlegroups.com> Content-Language: en-US Cancel-Lock: sha1:DettunhB/TFUxcXguFesg1J3oJo= Xref: reader02.eternal-september.org comp.lang.ada:50967 Date: 2018-03-14T11:49:40+01:00 List-Id: 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 >