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=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,13908470ad286d21 X-Google-Attributes: gid103376,public From: Tucker Taft Subject: Re: allowable protected-object subprogram-calls Date: 2000/02/07 Message-ID: <389EE258.1DB054F6@averstar.com> X-Deja-AN: 582680372 Content-Transfer-Encoding: 7bit References: <87l9ea$q4e$1@watserv3.uwaterloo.ca> X-Accept-Language: en Content-Type: text/plain; charset=us-ascii X-Complaints-To: usenet@inmet2.burl.averstar.com X-Trace: inmet2.burl.averstar.com 949936729 17953 141.199.8.164 (7 Feb 2000 15:18:49 GMT) Organization: AverStar (formerly Intermetrics) Burlington, MA USA Mime-Version: 1.0 NNTP-Posting-Date: 7 Feb 2000 15:18:49 GMT Newsgroups: comp.lang.ada Date: 2000-02-07T15:18:49+00:00 List-Id: "Peter A. Buhr" wrote: > > I am trying to determine the rules for which calls are allowed among protected > subprograms in a protected object. The problem is that the rules in the AARM > seem different from the results I get with GNAT, which means I am > misinterpreting the rules in the AARM or the implementation is wrong. I did > send a message to gnat, but was told to come to this newsgroup because my > question was of a general nature. > > I typed in the following program from the Ada 95 reference manual (p. 271) and > ran it under gnat. > > @clu[2]% uname -a > Linux clu.uwaterloo.ca 2.2.12-20 #1 Mon Sep 27 10:25:54 EDT 1999 i586 unknown > @clu[3]% cat test5.adb > procedure test5 is > protected type Some_Other_Protected_Type is > procedure Some_Op; > end Some_Other_Protected_Type; > > protected body Some_Other_Protected_Type is > procedure Some_Op is Begin null; end Some_Op; > end Some_Other_Protected_Type; > > protected type Pt is > procedure Op1; > procedure Op2; > end Pt; > > PO : Pt; > Other_Object : Some_Other_Protected_Type; > > protected body Pt is > procedure Op1 is Begin null; end Op1; > > procedure Op2 is > begin > Op1; -- An internal call > Pt.Op1; -- another internal call > PO.Op1; -- An external call. If the current instance is PO, then > -- this is a bounded error (see 9.5.1) > Other_Object.Some_Op; -- An external call > end Op2; > end Pt; > begin > PO.Op2; > end test5; > @clu[4]% gnatmake -v test5.adb > GNATMAKE 3.12p (19990629) Copyright 1995-1999 Free Software Foundation, Inc. > "test5.ali" being checked ... > gnatmake: "test5" up to date. > @clu[5]% ./test5 > @clu[6]% > > I was surprised not to get at least a warning for the call "PO.Op1" > (considering the subsequent warnings I received in the next example program.) Giving a warning on PO.Op1 would imply giving a warning any time the compiler sees an external call on an object of the same type as the current protected unit. This would seem a bit unfriendly. Of course, deciding which warnings are "helpful" is always a tough choice. > The AARM seems to allow implementors a choice: > > If the bounded error is detected, Program_Error is raised. If not detected, > the bounded error might result in deadlock or a (nested) protected action on > the same target object. AARM p. 273(17) > > and gnat chose to perform a nested protected action on the same target. > However, a programmer cannot reply on this implementation across compilers > given the potential choices. By calling it a "bounded error" we are saying that the program has an error, but the consequences are limited to those identified in the reference manual. This is to be distinguished from "erroneous" where essentially anything might happen, including the destruction of the universe as we know it... > The next test program I ran changes "Op1" from a procedure to an entry: > > @clu[3]% cat test5.adb > procedure test5 is > protected type Some_Other_Protected_Type is > procedure Some_Op; > end Some_Other_Protected_Type; > > protected body Some_Other_Protected_Type is > procedure Some_Op is Begin null; end Some_Op; > end Some_Other_Protected_Type; > > protected type Pt is > entry Op1; > procedure Op2; > end Pt; > > PO : Pt; > Other_Object : Some_Other_Protected_Type; > > protected body Pt is > entry Op1 when true is begin null; end OP1; > > procedure Op2 is > begin > Op1; -- An internal call > Pt.OP1; -- another internal call > PO.OP1; -- An external call. If the current instance is PO, then > -- this is a bounded error (see 9.5.1) These are all potentially blocking operations, because they are calls on *entries* rather than procedures. Hence, whether internal or external, they are (bounded) errors, and easy for the compiler to detect. > Other_Object.Some_Op; -- An external call > end Op2; > end Pt; > begin > PO.Op2; > end test5; > @clu[4]% gnatmake test5.adb > gnatgcc -c test5.adb > test5.adb:23:10: warning: potentially blocking operation in protected operation > test5.adb:24:12: warning: potentially blocking operation in protected operation > test5.adb:25:12: warning: potentially blocking operation in protected operation > gnatbind -x test5.ali > gnatlink test5.ali > > I don't understand the warning messages produced by the internal calls on lines > 23 and 24 because of the following: > > From within a protected action, an internal call on a protected subprogram, > or an external call on a protected subprogram with a different target object > is not considered a potentially blocking operation. AARM p. 273(22): As Robert Dewar pointed out, the critical issue is that an entry is considered a protected *operation* but is not included within the definition of a protected *subprogram*. For what it is worth, here are the warnings from my favorite Ada 95 front end: ... 75 procedure Op2 is 76 begin 77 Op1; -- An internal call * *****Warning: LRM:9.5.1(11) Calling an entry during a protected action is a ***** bounded error, Program_Error will be raised at run-time 78 Pt.OP1; -- another internal call * *****Warning: LRM:9.5.1(11) Calling an entry during a protected action is a ***** bounded error, Program_Error will be raised at run-time 79 PO.OP1; -- An external call. If the current instance is PO, then * *****Warning: LRM:9.5.1(11) Calling an entry during a protected action is a ***** bounded error, Program_Error will be raised at run-time 80 -- this is a bounded error (see 9.5.1) 81 Other_Object.Some_Op; -- An external call 82 end Op2; > I do understand the warning produced by the external call on line 25 as PO > could be the same target (which it is). Furthermore, when I run the program, it > deadlocks at line 23 on the first internal call to Op1. (I determined this by > adding additional print statements to the program.) I would have expected the > deadlock at line 25, when the external call attempts to re-acquire the > protected-object's mutex lock. > > So is there some other little clause or note in the Ada AARM that explains this > particular semantics or is the gnat-Ada implementation incorrect? I don't have > access to another Ada compiler to double check this behaviour. > > It seems to me that once a task has acquired mutual exclusion on a protected > object, it should be free to make internal calls to any of its subprograms. > That's how I read the "note" at p. 273(22). I also assume that since the > protected action is still in progress, an internal call to an entry subprogram > does not re-evaluated its guard, although there is no specific note to this > effect in the AARM (unless I missed it). > > I do not read this newsgroup, so please send any responses direction to me and > I will forward a summary to the newsgroup if some conclusion is reached. > Results from other Ada compilers would be appreciated. > > Dr. Peter A. Buhr > Dept. of Computer Science > University of Waterloo > 200 University Ave. West > Waterloo, Ontario > CANADA, N2L 3G1 -- -Tucker Taft stt@averstar.com http://www.averstar.com/~stt/ Technical Director, Distributed IT Solutions (www.averstar.com/tools) AverStar (formerly Intermetrics, Inc.) Burlington, MA USA