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=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!news.eternal-september.org!news.eternal-september.org!feeder.eternal-september.org!aioe.org!.POSTED!not-for-mail From: "Dmitry A. Kazakov" Newsgroups: comp.lang.ada Subject: Re: Reference counting and idempotent finalize Date: Wed, 11 Sep 2013 14:12:51 +0200 Organization: cbb software GmbH Message-ID: <5rbmj2y8ml2b$.e0ygtir1g3mt$.dlg@40tude.net> References: Reply-To: mailbox@dmitry-kazakov.de NNTP-Posting-Host: IenaDxMXK2hi7fvYcb+MlQ.user.speranza.aioe.org Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Complaints-To: abuse@aioe.org User-Agent: 40tude_Dialog/2.0.15.1 X-Notice: Filtered by postfilter v. 0.8.2 Xref: news.eternal-september.org comp.lang.ada:17155 Date: 2013-09-11T14:12:51+02:00 List-Id: On Wed, 11 Sep 2013 10:45:37 +0000 (UTC), Natasha Kerensikova wrote: > Anyway, my naive implementation looks like that: > > procedure Finalize (Self : in out Reference) is > begin > Release (Self.Access_Value); > end Finalize; > > procedure Release (Access_Value : in out Access_To_Actual_Data) is > begin > if Access_Value /= null then > Access_Value.all.Counter := Access_Value.all.Counter - 1; > > if Access_Value.all.Counter = 0 then > Unchecked_Deallocation_Instance (Access_Value); > else > Access_Value := null; > end if; > end if; > end Release; > > For the reference, I used explicit dereference because in the real code > the parameter is not called Access_Value and is not obviously an access, > so I thought it clearer that way. And the procedure Release is used > because Finalize feels "special" so I don't want to call it myself. > > As far as I can see, Access_Value = null could be post condition for > Release, and unless the code flow is interrupted by an exception, that > looks extremely idempotent to me. Am I missing something here? > > I neglected the possibility of exceptional flow interruption because I > felt that an exception in Finalize triggers the end of the world (the > same way I've felt for a long time the idempotency requirement). Now > having done the research, 7.6.1(13) doesn't really mention the world > ending, that looks quite close to it, doesn't it? > > Am I missing something on the exception part? Or is my implementation > good enough? It looks OK, but do not forget Adjust. Also you might wish add a check against negative reference count. You could make an alternative version for debug scenario which keeps track of all changes of the reference count dumping them on errors. GNAT stack trace is handy for that. Do not trust reference counting, it is an endless source of many hideous errors even if the implementation of is correct. Tracing for the latest exception when in Finalize (GNAT functionality) is extremely helpful as well, because upon error propagation you get a snowball of cascading exceptions hiding the original problem. Always kill any exceptions in Finalize and do an emergency tracing in the handler. Yet another version is likely needed for tasking, that is when the reference objects are used concurrently, so that the reference count is updated concurrently. You will need a protected object to handle increments and decrements and careful design preventing concurrent increments when the count reached 0. One possible implementation can be found here: http://www.dmitry-kazakov.de/ada/components.htm#Objects_etc -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de