From: John Wilkinson on 28 Apr 2010 14:16 select PID.Call; --an entry call to task PID Status := P; then abort delay 10.0; Status := Q; end select; Is the above valid Ada code? It's been handed to me by someone, I don't really know much about Ada, and I'm supposed to understand what it does. I can't find any information on "abort" or even "then". If it's valid, what does it do?
From: Dmitry A. Kazakov on 28 Apr 2010 14:36 On Wed, 28 Apr 2010 18:16:44 +0000 (UTC), John Wilkinson wrote: > select > PID.Call; --an entry call to task PID > Status := P; > then abort > delay 10.0; > Status := Q; > end select; > > Is the above valid Ada code? It's been handed to me by someone, I > don't really know much about Ada, and I'm supposed to understand > what it does. I can't find any information on "abort" or even > "then". See ARM 9.7.4 Asynchronous Transfer of Control > If it's valid, what does it do? It waits 10s and then assigns Q to Status. But if within these 10s + the time needed to assign Status, the task PID accepts Call, then the sequence introduced by "then abort" is aborted, Call is performed, and finally, P is assigned to Status. Note that the recommended way to do this is the timed entry call ARM 9.7.2: select PID.Call; -- call to task PID Status := P; or delay 10.0; -- wait to longer than 10s Status := Q; end select; -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: Jeffrey R. Carter on 28 Apr 2010 17:00 Dmitry A. Kazakov wrote: > > It waits 10s and then assigns Q to Status. But if within these 10s + the > time needed to assign Status, the task PID accepts Call, then the sequence > introduced by "then abort" is aborted, Call is performed, and finally, P is > assigned to Status. That's a good explanation for the OP. Technically, though, it isn't quite true: if the entry call *completes* then the abortable part (after "then abort") is aborted: "If the triggering_statement completes other than due to cancellation, the abortable_part is aborted". The abortable part only begins execution if the entry call is queued, either immediately or by requeue-with-abort. If the abortable part completes, then it attempts to cancel the entry call, even if it has been "selected" (is no longer queued but has not completed). For a timed entry call, no attempt is made to cancel the entry call if the entry has been "selected". This difference in semantics may be why this code uses asynchronous transfer of control rather than a timed entry call. But I doubt it. -- Jeff Carter "From this day on, the official language of San Marcos will be Swedish." Bananas 28
From: Dmitry A. Kazakov on 28 Apr 2010 18:41 On Wed, 28 Apr 2010 14:00:50 -0700, Jeffrey R. Carter wrote: > Technically, though, it isn't quite true: if the entry call *completes* then the > abortable part (after "then abort") is aborted: "If the triggering_statement > completes other than due to cancellation, the abortable_part is aborted". This is a very interesting question. I don't know if this wording indeed requires the rendezvous and the abortable part to execute in parallel. Otherwise, in effect, fetching the call from the queue must abort. I would expect rather the latter, because the former would be quite difficult to implement. The following example illustrates the case: protected Event is procedure Signal; entry Wait; private Signaled : Boolean := False; end Event; protected body Event is procedure Signal is begin Signaled := True; end Signal; entry Wait when Signaled is begin Signaled := False; end; end Event; task PID is entry Call; end PID; task body PID is begin accept Call do Event.Wait; end; end PID; begin select PID.Call; -- Blocked in the rendezvous then abort delay 2.0; Event.Signal; -- Releases the rendezvous after 2s end select; If abort to happen after *completion* of the rendezvous then the above shall not deadlock. (I checked this under GNAT/Windows, it deadlocks there.) -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: Jeffrey R. Carter on 28 Apr 2010 20:20 Dmitry A. Kazakov wrote: > > protected Event is > procedure Signal; > entry Wait; > private > Signaled : Boolean := False; > end Event; > > protected body Event is > procedure Signal is > begin > Signaled := True; > end Signal; > entry Wait when Signaled is > begin > Signaled := False; > end; > end Event; > > task PID is > entry Call; > end PID; > > task body PID is > begin > accept Call do Event.Wait; end; > end PID; > > begin > select > PID.Call; -- Blocked in the rendezvous > then abort > delay 2.0; > Event.Signal; -- Releases the rendezvous after 2s > end select; > > If abort to happen after *completion* of the rendezvous then the above > shall not deadlock. (I checked this under GNAT/Windows, it deadlocks > there.) Here the call to PID.Call is not queued, but is accepted immediately, and does not encounter an explicit requeue-with-abort. I guess that queuing on Event.Wait does not count as equivalent to requeue-with-abort (unless this is a compiler error; any language lawyers care to comment?). So the abortable part is never executed, leading to deadlock. It will be interesting to add "delay 1.0;" to the task before the accept, and see if that changes the behavior. Then the call to PID.Call will queue, and the abortable part should execute. -- Jeff Carter "From this day on, the official language of San Marcos will be Swedish." Bananas 28
|
Next
|
Last
Pages: 1 2 3 Prev: Missing libgthread-2.0-0.dll Next: On database interface libraries for Ada |