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 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 1108a1,2c6139ce13be9980 X-Google-Attributes: gid1108a1,public X-Google-Thread: fac41,2c6139ce13be9980 X-Google-Attributes: gidfac41,public X-Google-Thread: f43e6,2c6139ce13be9980 X-Google-Attributes: gidf43e6,public X-Google-Thread: 103376,3d3f20d31be1c33a X-Google-Attributes: gid103376,public From: Ken Garlington Subject: Re: Safety-critical development in Ada and Eiffel Date: 1997/08/15 Message-ID: <33F526A9.23E5@flash.net> X-Deja-AN: 264461727 References: Organization: Flashnet Communications, http://www.flash.net Reply-To: Ken.Garlington@computer.org Newsgroups: comp.object,comp.software-eng,comp.lang.ada,comp.lang.eiffel Date: 1997-08-15T00:00:00+00:00 List-Id: Don Harrison wrote: > > ::Or are you saying it can be interrupted, just that no other thread > ::can access the objects referenced in the parameter list (or any objects > ::referenced in _their_ parameter lists? )? > : > :Correct. > > I need to clarify this. Unless the default duelling status of the objects > involved changes as a result of calls to class CONCURRENCY (retain, yield, > wait_turn, demand, insist), a thread will not be interrupted and (in theory) > no other thread can access the objects in the parameter list of the operation > being called. This makes no sense, given your last post. If no other thread can interrupt, how is a duel initiated? > > On protected types: > > Ken Garlington wrote: > > :> ::can requeue requests, > :> > :> I wrote: > :> ... The problem in Ada which "requeue" is designed to deal > :> with doesn't arise in SCOOP because successive calls to the same separate > :> object are atomic. That is, the object doesn't get unlocked between calls. > > This means that, under SCOOP, locking is operation-based rather than > object-based. Protected types, in contrast, have object-based locking. This > means that a calling thread issuing two consecutive calls to a protected > object cannot be guaranteed that no other thread will update the protected > object between the calls. > > If I understand correctly, requeues are a means of getting around this problem > by allowing the callee (the protected object) to issue extra calls (on behalf > of the calling thread) while it is still locked. I think this scheme is > deficient for a couple of reasons: > > 1) It doesn't fix the underlying problem - the lack of atomicity inherent in > object-based locking. As such, it's a workaround rather than a mechanism > that should exist in its own right. > > 2) It's undesirable from a modelling perspective: > > a) It's incorrect for a caller to be making calls to itself *on behalf > of the caller*. > > b) It introduces undesirable interdependencies between entries - for example, > the blocking abstraction on P. 9-16 of the Ada95 Rationale. > > Under SCOOP, inherently autonomous operations remain autonomous in > accordance with sound design (read "OO principles"). Actually, it promotes OO principles, since the reasons for the requeue are often due to the internal implementation of the protected object, and thus can be hidden from the caller. > One thing I'm curious about is where the requeued call gets placed on the > entry queue. I guess it must be placed on the head, rather than the tail, > for this to work. Is that the case? All queues are generally FIFO. Note that the requeued call doesn't have to be on the _same_ queue. "The entry queuing policy controls selection among queued calls both for task and protected entry queues. The default entry queuing policy is to select calls on a given entry queue in order of arrival. If calls from two or more queues are simultaneously eligible for selection, the default entry queuing policy does not specify which queue is serviced first. Other entry queuing policies can be specified by pragmas (see D.4)." > > :True. However, the question still stands: What happens if a thread attempts to > :access a locked (or otherwise unavailable) resource? > > It gets queued in the queue of callers for that object (one queue per object). > Out of interest, is there one queue per protected object or one queue per entry? One per entry (which is what you want, if you want the timing behavior to be different based on the operation/entry called). > > :I can use requeue in these situations; > > Sorry, don't see what you mean. As far as I can see, requeue is used by the > thread that has control of the protected object, not a thread that's trying > to get hold of it. No, any entry can be requeued. Furthermore, it's not up to the caller or callee, it's up to the protected object: "A requeue_statement can be used to complete an accept_statement or entry_body, while redirecting the corresponding entry call to a new (or the same) entry queue. Such a requeue can be performed with or without allowing an intermediate cancellation of the call, due to an abort or the expiration of a delay." "A requeue_statement shall be within a callable construct that is either an entry_body or an accept_statement, and this construct shall be the innermost enclosing body or callable construct." Again, the internal timing/sequence requirements can be hidden within the object. It makes the decisions based on its internal state, not the caller or callee. This is what you want a server task to be able to do, of course. > > what do you do? > > The controlling thread doesn't have to worry about it because it retains control > of the separate object even when individual calls to it have completed. The > separate object only gets unlocked when the calling operation itself completes. > > :> For example, > :> > :> do_something (a: separate A) is > :> do > :> a.do_x > :> a.do_y > :> end > :> > :> does exactly what we expect. There is no need for do_x to "requeue" do_y. > : > :That's not how requeue works, as I understand it. The issue is more: you > :attempt to do a.do_x, and someone else has already seized the resource, or > :there is some other time-based reason why a.do_x is unavailable. > > What you've described sounds more like the mechanism for queuing calls. Requeue > is something different, as I understand it. Well, I'm new to Ada 95, so you may be right. However, take a peek at http://www.adahome.com/rm95/rm9x-09-05-04.html#1 or the quotes from it above. > > :> IMO, "requeue" is a wokaround to a design flaw in Ada's concurrency - namely > :> locking at the object level. Further, it's a *deficient* workaround because > :> supplier objects are forced to do things (do_y) that should be the > :> responsibility of clients (do_something). > : > :It depends. A "requeue" may be needed because of the state of the > :object, and may not be related to the state of do_something. > > In that case, do_somthing need only test the state of the separate object > and take whatever action is necessary - calling another operation in it, > for example. It's that "test the state" that bothers me. Why do I need to expose the internal state of the object? Seems somewhat non-OO to me. It also means that the object can't enforce it's own timing policies -- it has to trust the caller to do the right thing. > > do_something (a: separate A) is > do > a.do_x > if a.some_condition then > a.do_y > end > end > > :> :If anything, "requeue" probably encourages poor design. > :> > :> .. as I've just explained. > : > :Sorry, don't see it. > : > :I think you would need to apply SCOOP to some fairly complex > :real-time systems to see the problems I'm discussing. > > I think I've addressed all the issues you were concerned about. From a > theoretical standpoint, SCOOP should work and should be scaleable. Of course, > it will be reassuring to have the theory vindicated by seeing it applied > successfully to a significant-sized project. Agreed. I think I would be much more convinced once this optimizing compiler hits the streets, and people start looking at the effort to define all of the dueling relationships. > > :So long as all the objects have short lifetimes, and no priority issues > :are around, I would assume it seems to work fine for simple systems. > > I think it will be fine for *any* size system. Obviously, it will require a > different design approach to that used with Ada because of some fundamental > differences. These differences make it both more restrictive (in reliability- > enhancing ways) and less restrictive (in ways that enhance reuse and modelling > integrity). The design approaches I describe didn't come with Ada. They've been around since assembly days. The same issues are described in real-time courses regardless of implementation language. It would be interested to take some examples from these courses, such as the HAS Buoy, Cruise Control, and ATD/CWM case studies from the ADARTS material, and have them coded in SCOOP and executed. > > Don. > =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- > Don Harrison donh@syd.csa.com.au