1 ------------------------------------------------------------------------------
3 -- GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS --
5 -- SYSTEM.TASKING.PROTECTED_OBJECTS.OPERATIONS --
9 -- Copyright (C) 1998-2004, Free Software Foundation, Inc. --
11 -- GNARL is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNARL; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNARL was developed by the GNARL team at Florida State University. --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
32 ------------------------------------------------------------------------------
34 -- This package contains all the extended primitives related to
35 -- Protected_Objects with entries.
37 -- The handling of protected objects with no entries is done in
38 -- System.Tasking.Protected_Objects, the simple routines for protected
39 -- objects with entries in System.Tasking.Protected_Objects.Entries.
41 -- The split between Entries and Operations is needed to break circular
42 -- dependencies inside the run time.
44 -- This package contains all primitives related to Protected_Objects.
45 -- Note: the compiler generates direct calls to this interface, via Rtsfind.
48 -- Used for Exception_ID
52 with System
.Task_Primitives
.Operations
;
53 -- used for Initialize_Lock
59 with System
.Tasking
.Entry_Calls
;
60 -- used for Wait_For_Completion
61 -- Wait_Until_Abortable
62 -- Wait_For_Completion_With_Timeout
64 with System
.Tasking
.Initialization
;
65 -- Used for Defer_Abort,
67 -- Change_Base_Priority
69 pragma Elaborate_All
(System
.Tasking
.Initialization
);
70 -- This insures that tasking is initialized if any protected objects are
73 with System
.Tasking
.Queuing
;
75 -- Broadcast_Program_Error
76 -- Select_Protected_Entry_Call
80 with System
.Tasking
.Rendezvous
;
81 -- used for Task_Do_Or_Queue
83 with System
.Tasking
.Utilities
;
84 -- used for Exit_One_ATC_Level
86 with System
.Tasking
.Debug
;
89 with System
.Parameters
;
90 -- used for Single_Lock
93 with System
.Traces
.Tasking
;
94 -- used for Send_Trace_Info
96 package body System
.Tasking
.Protected_Objects
.Operations
is
98 package STPO
renames System
.Task_Primitives
.Operations
;
106 use System
.Traces
.Tasking
;
108 -----------------------
109 -- Local Subprograms --
110 -----------------------
112 procedure Update_For_Queue_To_PO
113 (Entry_Call
: Entry_Call_Link
;
114 With_Abort
: Boolean);
115 pragma Inline
(Update_For_Queue_To_PO
);
116 -- Update the state of an existing entry call to reflect
117 -- the fact that it is being enqueued, based on
118 -- whether the current queuing action is with or without abort.
119 -- Call this only while holding the PO's lock.
120 -- It returns with the PO's lock still held.
122 procedure Requeue_Call
124 Object
: Protection_Entries_Access
;
125 Entry_Call
: Entry_Call_Link
;
126 With_Abort
: Boolean);
127 -- Handle requeue of Entry_Call.
128 -- In particular, queue the call if needed, or service it immediately
131 ---------------------------------
132 -- Cancel_Protected_Entry_Call --
133 ---------------------------------
135 -- Compiler interface only. Do not call from within the RTS.
136 -- This should have analogous effect to Cancel_Task_Entry_Call,
137 -- setting the value of Block.Cancelled instead of returning
138 -- the parameter value Cancelled.
140 -- The effect should be idempotent, since the call may already
141 -- have been dequeued.
154 -- X : protected_entry_index := 1;
155 -- B80b : communication_block;
156 -- communication_blockIP (B80b);
161 -- procedure _clean is
163 -- if enqueued (B80b) then
164 -- cancel_protected_entry_call (B80b);
169 -- protected_entry_call (rTV!(r)._object'unchecked_access, X,
170 -- null_address, asynchronous_call, B80b, objectF => 0);
171 -- if enqueued (B80b) then
178 -- when _abort_signal =>
179 -- abort_undefer.all;
182 -- if not cancelled (B80b) then
187 -- If the entry call completes after we get into the abortable part,
188 -- Abort_Signal should be raised and ATC will take us to the at-end
189 -- handler, which will call _clean.
191 -- If the entry call returns with the call already completed,
192 -- we can skip this, and use the "if enqueued()" to go past
193 -- the at-end handler, but we will still call _clean.
195 -- If the abortable part completes before the entry call is Done,
196 -- it will call _clean.
198 -- If the entry call or the abortable part raises an exception,
199 -- we will still call _clean, but the value of Cancelled should not matter.
201 -- Whoever calls _clean first gets to decide whether the call
202 -- has been "cancelled".
204 -- Enqueued should be true if there is any chance that the call
205 -- is still on a queue. It seems to be safe to make it True if
206 -- the call was Onqueue at some point before return from
207 -- Protected_Entry_Call.
209 -- Cancelled should be true iff the abortable part completed
210 -- and succeeded in cancelling the entry call before it completed.
213 -- The need for Enqueued is less obvious.
214 -- The "if enqueued ()" tests are not necessary, since both
215 -- Cancel_Protected_Entry_Call and Protected_Entry_Call must
216 -- do the same test internally, with locking. The one that
217 -- makes cancellation conditional may be a useful heuristic
218 -- since at least 1/2 the time the call should be off-queue
219 -- by that point. The other one seems totally useless, since
220 -- Protected_Entry_Call must do the same check and then
221 -- possibly wait for the call to be abortable, internally.
223 -- We can check Call.State here without locking the caller's mutex,
224 -- since the call must be over after returning from Wait_For_Completion.
225 -- No other task can access the call record at this point.
227 procedure Cancel_Protected_Entry_Call
228 (Block
: in out Communication_Block
) is
230 Entry_Calls
.Try_To_Cancel_Entry_Call
(Block
.Cancelled
);
231 end Cancel_Protected_Entry_Call
;
237 function Cancelled
(Block
: Communication_Block
) return Boolean is
239 return Block
.Cancelled
;
242 -------------------------
243 -- Complete_Entry_Body --
244 -------------------------
246 procedure Complete_Entry_Body
(Object
: Protection_Entries_Access
) is
248 Exceptional_Complete_Entry_Body
(Object
, Ada
.Exceptions
.Null_Id
);
249 end Complete_Entry_Body
;
255 function Enqueued
(Block
: Communication_Block
) return Boolean is
257 return Block
.Enqueued
;
260 -------------------------------------
261 -- Exceptional_Complete_Entry_Body --
262 -------------------------------------
264 procedure Exceptional_Complete_Entry_Body
265 (Object
: Protection_Entries_Access
;
266 Ex
: Ada
.Exceptions
.Exception_Id
)
268 Entry_Call
: constant Entry_Call_Link
:= Object
.Call_In_Progress
;
271 (Debug
.Trace
(STPO
.Self
, "Exceptional_Complete_Entry_Body", 'P'));
273 -- We must have abort deferred, since we are inside
274 -- a protected operation.
276 if Entry_Call
/= null then
277 -- The call was not requeued.
279 Entry_Call
.Exception_To_Raise
:= Ex
;
281 -- Wakeup_Entry_Caller will be called from PO_Do_Or_Queue or
282 -- PO_Service_Entries on return.
285 if Runtime_Traces
then
286 Send_Trace_Info
(PO_Done
, Entry_Call
.Self
);
288 end Exceptional_Complete_Entry_Body
;
294 procedure PO_Do_Or_Queue
296 Object
: Protection_Entries_Access
;
297 Entry_Call
: Entry_Call_Link
;
298 With_Abort
: Boolean)
300 E
: constant Protected_Entry_Index
:=
301 Protected_Entry_Index
(Entry_Call
.E
);
302 Barrier_Value
: Boolean;
305 -- When the Action procedure for an entry body returns, it is either
306 -- completed (having called [Exceptional_]Complete_Entry_Body) or it
307 -- is queued, having executed a requeue statement.
310 Object
.Entry_Bodies
(
311 Object
.Find_Body_Index
(Object
.Compiler_Info
, E
)).
312 Barrier
(Object
.Compiler_Info
, E
);
314 if Barrier_Value
then
316 -- Not abortable while service is in progress.
318 if Entry_Call
.State
= Now_Abortable
then
319 Entry_Call
.State
:= Was_Abortable
;
322 Object
.Call_In_Progress
:= Entry_Call
;
325 (Debug
.Trace
(Self_ID
, "PODOQ: start entry body", 'P'));
326 Object
.Entry_Bodies
(
327 Object
.Find_Body_Index
(Object
.Compiler_Info
, E
)).Action
(
328 Object
.Compiler_Info
, Entry_Call
.Uninterpreted_Data
, E
);
330 if Object
.Call_In_Progress
/= null then
332 -- Body of current entry served call to completion
334 Object
.Call_In_Progress
:= null;
340 STPO
.Write_Lock
(Entry_Call
.Self
);
341 Initialization
.Wakeup_Entry_Caller
(Self_ID
, Entry_Call
, Done
);
342 STPO
.Unlock
(Entry_Call
.Self
);
349 Requeue_Call
(Self_ID
, Object
, Entry_Call
, With_Abort
);
352 elsif Entry_Call
.Mode
/= Conditional_Call
353 or else not With_Abort
355 Queuing
.Enqueue
(Object
.Entry_Queues
(E
), Entry_Call
);
356 Update_For_Queue_To_PO
(Entry_Call
, With_Abort
);
359 -- Conditional_Call and With_Abort
365 STPO
.Write_Lock
(Entry_Call
.Self
);
366 pragma Assert
(Entry_Call
.State
>= Was_Abortable
);
367 Initialization
.Wakeup_Entry_Caller
(Self_ID
, Entry_Call
, Cancelled
);
368 STPO
.Unlock
(Entry_Call
.Self
);
377 Queuing
.Broadcast_Program_Error
(Self_ID
, Object
, Entry_Call
);
380 ------------------------
381 -- PO_Service_Entries --
382 ------------------------
384 procedure PO_Service_Entries
386 Object
: Entries
.Protection_Entries_Access
;
387 Unlock_Object
: Boolean := True)
389 E
: Protected_Entry_Index
;
391 Entry_Call
: Entry_Call_Link
;
395 Queuing
.Select_Protected_Entry_Call
(Self_ID
, Object
, Entry_Call
);
397 exit when Entry_Call
= null;
399 E
:= Protected_Entry_Index
(Entry_Call
.E
);
401 -- Not abortable while service is in progress.
403 if Entry_Call
.State
= Now_Abortable
then
404 Entry_Call
.State
:= Was_Abortable
;
407 Object
.Call_In_Progress
:= Entry_Call
;
410 if Runtime_Traces
then
411 Send_Trace_Info
(PO_Run
, Self_ID
,
412 Entry_Call
.Self
, Entry_Index
(E
));
416 (Debug
.Trace
(Self_ID
, "POSE: start entry body", 'P'));
417 Object
.Entry_Bodies
(
418 Object
.Find_Body_Index
(Object
.Compiler_Info
, E
)).Action
(
419 Object
.Compiler_Info
, Entry_Call
.Uninterpreted_Data
, E
);
422 Queuing
.Broadcast_Program_Error
423 (Self_ID
, Object
, Entry_Call
);
426 if Object
.Call_In_Progress
= null then
428 (Self_ID
, Object
, Entry_Call
, Entry_Call
.Requeue_With_Abort
);
429 exit when Entry_Call
.State
= Cancelled
;
432 Object
.Call_In_Progress
:= null;
433 Caller
:= Entry_Call
.Self
;
439 STPO
.Write_Lock
(Caller
);
440 Initialization
.Wakeup_Entry_Caller
(Self_ID
, Entry_Call
, Done
);
441 STPO
.Unlock
(Caller
);
449 if Unlock_Object
then
450 Unlock_Entries
(Object
);
452 end PO_Service_Entries
;
454 ---------------------
455 -- Protected_Count --
456 ---------------------
458 function Protected_Count
459 (Object
: Protection_Entries
'Class;
460 E
: Protected_Entry_Index
)
464 return Queuing
.Count_Waiting
(Object
.Entry_Queues
(E
));
467 --------------------------
468 -- Protected_Entry_Call --
469 --------------------------
471 -- Compiler interface only. Do not call from within the RTS.
480 -- X : protected_entry_index := 1;
481 -- B85b : communication_block;
482 -- communication_blockIP (B85b);
484 -- protected_entry_call (rTV!(r)._object'unchecked_access, X,
485 -- null_address, conditional_call, B85b, objectF => 0);
486 -- if cancelled (B85b) then
493 -- See also Cancel_Protected_Entry_Call for code expansion of asynchronous
496 -- The initial part of this procedure does not need to lock the the calling
497 -- task's ATCB, up to the point where the call record first may be queued
498 -- (PO_Do_Or_Queue), since before that no other task will have access to
501 -- If this is a call made inside of an abort deferred region, the call
502 -- should be never abortable.
504 -- If the call was not queued abortably, we need to wait until it is before
505 -- proceeding with the abortable part.
507 -- There are some heuristics here, just to save time for frequently
508 -- occurring cases. For example, we check Initially_Abortable to try to
509 -- avoid calling the procedure Wait_Until_Abortable, since the normal case
510 -- for async. entry calls is to be queued abortably.
512 -- Another heuristic uses the Block.Enqueued to try to avoid calling
513 -- Cancel_Protected_Entry_Call if the call can be served immediately.
515 procedure Protected_Entry_Call
516 (Object
: Protection_Entries_Access
;
517 E
: Protected_Entry_Index
;
518 Uninterpreted_Data
: System
.Address
;
520 Block
: out Communication_Block
)
522 Self_ID
: constant Task_Id
:= STPO
.Self
;
523 Entry_Call
: Entry_Call_Link
;
524 Initially_Abortable
: Boolean;
525 Ceiling_Violation
: Boolean;
529 (Debug
.Trace
(Self_ID
, "Protected_Entry_Call", 'P'));
531 if Runtime_Traces
then
532 Send_Trace_Info
(PO_Call
, Entry_Index
(E
));
535 if Self_ID
.ATC_Nesting_Level
= ATC_Level
'Last then
537 (Storage_Error
'Identity, "not enough ATC nesting levels");
540 Initialization
.Defer_Abort
(Self_ID
);
541 Lock_Entries
(Object
, Ceiling_Violation
);
543 if Ceiling_Violation
then
545 -- Failed ceiling check
547 Initialization
.Undefer_Abort
(Self_ID
);
551 Block
.Self
:= Self_ID
;
552 Self_ID
.ATC_Nesting_Level
:= Self_ID
.ATC_Nesting_Level
+ 1;
554 (Debug
.Trace
(Self_ID
, "PEC: entered ATC level: " &
555 ATC_Level
'Image (Self_ID
.ATC_Nesting_Level
), 'A'));
557 Self_ID
.Entry_Calls
(Self_ID
.ATC_Nesting_Level
)'Access;
558 Entry_Call
.Next
:= null;
559 Entry_Call
.Mode
:= Mode
;
560 Entry_Call
.Cancellation_Attempted
:= False;
562 if Self_ID
.Deferral_Level
> 1 then
563 Entry_Call
.State
:= Never_Abortable
;
565 Entry_Call
.State
:= Now_Abortable
;
568 Entry_Call
.E
:= Entry_Index
(E
);
569 Entry_Call
.Prio
:= STPO
.Get_Priority
(Self_ID
);
570 Entry_Call
.Uninterpreted_Data
:= Uninterpreted_Data
;
571 Entry_Call
.Called_PO
:= To_Address
(Object
);
572 Entry_Call
.Called_Task
:= null;
573 Entry_Call
.Exception_To_Raise
:= Ada
.Exceptions
.Null_Id
;
575 PO_Do_Or_Queue
(Self_ID
, Object
, Entry_Call
, With_Abort
=> True);
576 Initially_Abortable
:= Entry_Call
.State
= Now_Abortable
;
577 PO_Service_Entries
(Self_ID
, Object
);
579 -- Try to prevent waiting later (in Try_To_Cancel_Protected_Entry_Call)
580 -- for completed or cancelled calls. (This is a heuristic, only.)
582 if Entry_Call
.State
>= Done
then
584 -- Once State >= Done it will not change any more.
590 STPO
.Write_Lock
(Self_ID
);
591 Utilities
.Exit_One_ATC_Level
(Self_ID
);
592 STPO
.Unlock
(Self_ID
);
598 Block
.Enqueued
:= False;
599 Block
.Cancelled
:= Entry_Call
.State
= Cancelled
;
600 Initialization
.Undefer_Abort
(Self_ID
);
601 Entry_Calls
.Check_Exception
(Self_ID
, Entry_Call
);
605 -- In this case we cannot conclude anything,
606 -- since State can change concurrently.
610 -- Now for the general case.
612 if Mode
= Asynchronous_Call
then
614 -- Try to avoid an expensive call.
616 if not Initially_Abortable
then
619 Entry_Calls
.Wait_Until_Abortable
(Self_ID
, Entry_Call
);
622 Entry_Calls
.Wait_Until_Abortable
(Self_ID
, Entry_Call
);
626 elsif Mode
< Asynchronous_Call
then
628 -- Simple_Call or Conditional_Call
632 Entry_Calls
.Wait_For_Completion
(Entry_Call
);
635 STPO
.Write_Lock
(Self_ID
);
636 Entry_Calls
.Wait_For_Completion
(Entry_Call
);
637 STPO
.Unlock
(Self_ID
);
640 Block
.Cancelled
:= Entry_Call
.State
= Cancelled
;
643 pragma Assert
(False);
647 Initialization
.Undefer_Abort
(Self_ID
);
648 Entry_Calls
.Check_Exception
(Self_ID
, Entry_Call
);
649 end Protected_Entry_Call
;
655 procedure Requeue_Call
657 Object
: Protection_Entries_Access
;
658 Entry_Call
: Entry_Call_Link
;
659 With_Abort
: Boolean)
661 New_Object
: Protection_Entries_Access
;
662 Ceiling_Violation
: Boolean;
664 E
: Protected_Entry_Index
;
667 New_Object
:= To_Protection
(Entry_Call
.Called_PO
);
669 if New_Object
= null then
671 -- Call is to be requeued to a task entry
677 Result
:= Rendezvous
.Task_Do_Or_Queue
678 (Self_Id
, Entry_Call
,
679 With_Abort
=> Entry_Call
.Requeue_With_Abort
);
682 Queuing
.Broadcast_Program_Error
683 (Self_Id
, Object
, Entry_Call
, RTS_Locked
=> True);
691 -- Call should be requeued to a PO
693 if Object
/= New_Object
then
695 -- Requeue is to different PO
697 Lock_Entries
(New_Object
, Ceiling_Violation
);
699 if Ceiling_Violation
then
700 Object
.Call_In_Progress
:= null;
701 Queuing
.Broadcast_Program_Error
702 (Self_Id
, Object
, Entry_Call
);
705 PO_Do_Or_Queue
(Self_Id
, New_Object
, Entry_Call
, With_Abort
);
706 PO_Service_Entries
(Self_Id
, New_Object
);
710 -- Requeue is to same protected object
712 if Entry_Call
.Requeue_With_Abort
713 and then Entry_Call
.Cancellation_Attempted
715 -- If this is a requeue with abort and someone tried
716 -- to cancel this call, cancel it at this point.
718 Entry_Call
.State
:= Cancelled
;
723 or else Entry_Call
.Mode
/= Conditional_Call
725 E
:= Protected_Entry_Index
(Entry_Call
.E
);
727 (New_Object
.Entry_Queues
(E
), Entry_Call
);
728 Update_For_Queue_To_PO
(Entry_Call
, With_Abort
);
731 PO_Do_Or_Queue
(Self_Id
, New_Object
, Entry_Call
, With_Abort
);
737 ----------------------------
738 -- Protected_Entry_Caller --
739 ----------------------------
741 function Protected_Entry_Caller
742 (Object
: Protection_Entries
'Class) return Task_Id
is
744 return Object
.Call_In_Progress
.Self
;
745 end Protected_Entry_Caller
;
747 -----------------------------
748 -- Requeue_Protected_Entry --
749 -----------------------------
751 -- Compiler interface only. Do not call from within the RTS.
760 -- procedure rPT__E10b (O : address; P : address; E :
761 -- protected_entry_index) is
762 -- type rTVP is access rTV;
764 -- _object : rTVP := rTVP!(O);
767 -- rR : protection renames _object._object;
768 -- vP : integer renames _object.v;
769 -- bP : boolean renames _object.b;
773 -- requeue_protected_entry (rR'unchecked_access, rR'
774 -- unchecked_access, 2, false, objectF => 0, new_objectF =>
778 -- complete_entry_body (_object._object'unchecked_access, objectF =>
783 -- abort_undefer.all;
784 -- exceptional_complete_entry_body (_object._object'
785 -- unchecked_access, current_exception, objectF => 0);
789 procedure Requeue_Protected_Entry
790 (Object
: Protection_Entries_Access
;
791 New_Object
: Protection_Entries_Access
;
792 E
: Protected_Entry_Index
;
793 With_Abort
: Boolean)
795 Entry_Call
: constant Entry_Call_Link
:= Object
.Call_In_Progress
;
799 (Debug
.Trace
(STPO
.Self
, "Requeue_Protected_Entry", 'P'));
800 pragma Assert
(STPO
.Self
.Deferral_Level
> 0);
802 Entry_Call
.E
:= Entry_Index
(E
);
803 Entry_Call
.Called_PO
:= To_Address
(New_Object
);
804 Entry_Call
.Called_Task
:= null;
805 Entry_Call
.Requeue_With_Abort
:= With_Abort
;
806 Object
.Call_In_Progress
:= null;
807 end Requeue_Protected_Entry
;
809 -------------------------------------
810 -- Requeue_Task_To_Protected_Entry --
811 -------------------------------------
813 -- Compiler interface only.
823 -- accept_call (1, A79b);
825 -- requeue_task_to_protected_entry (rTV!(r)._object'
826 -- unchecked_access, 2, false, new_objectF => 0);
829 -- complete_rendezvous;
831 -- when all others =>
832 -- exceptional_complete_rendezvous (get_gnat_exception);
835 procedure Requeue_Task_To_Protected_Entry
836 (New_Object
: Protection_Entries_Access
;
837 E
: Protected_Entry_Index
;
838 With_Abort
: Boolean)
840 Self_ID
: constant Task_Id
:= STPO
.Self
;
841 Entry_Call
: constant Entry_Call_Link
:= Self_ID
.Common
.Call
;
844 Initialization
.Defer_Abort
(Self_ID
);
846 -- We do not need to lock Self_ID here since the call is not abortable
847 -- at this point, and therefore, the caller cannot cancel the call.
849 Entry_Call
.Needs_Requeue
:= True;
850 Entry_Call
.Requeue_With_Abort
:= With_Abort
;
851 Entry_Call
.Called_PO
:= To_Address
(New_Object
);
852 Entry_Call
.Called_Task
:= null;
853 Entry_Call
.E
:= Entry_Index
(E
);
854 Initialization
.Undefer_Abort
(Self_ID
);
855 end Requeue_Task_To_Protected_Entry
;
857 ---------------------
858 -- Service_Entries --
859 ---------------------
861 procedure Service_Entries
(Object
: Protection_Entries_Access
) is
862 Self_ID
: constant Task_Id
:= STPO
.Self
;
864 PO_Service_Entries
(Self_ID
, Object
);
867 --------------------------------
868 -- Timed_Protected_Entry_Call --
869 --------------------------------
871 -- Compiler interface only. Do not call from within the RTS.
873 procedure Timed_Protected_Entry_Call
874 (Object
: Protection_Entries_Access
;
875 E
: Protected_Entry_Index
;
876 Uninterpreted_Data
: System
.Address
;
879 Entry_Call_Successful
: out Boolean)
881 Self_Id
: constant Task_Id
:= STPO
.Self
;
882 Entry_Call
: Entry_Call_Link
;
883 Ceiling_Violation
: Boolean;
887 if Self_Id
.ATC_Nesting_Level
= ATC_Level
'Last then
888 Raise_Exception
(Storage_Error
'Identity,
889 "not enough ATC nesting levels");
892 if Runtime_Traces
then
893 Send_Trace_Info
(POT_Call
, Entry_Index
(E
), Timeout
);
896 Initialization
.Defer_Abort
(Self_Id
);
897 Lock_Entries
(Object
, Ceiling_Violation
);
899 if Ceiling_Violation
then
900 Initialization
.Undefer_Abort
(Self_Id
);
904 Self_Id
.ATC_Nesting_Level
:= Self_Id
.ATC_Nesting_Level
+ 1;
906 (Debug
.Trace
(Self_Id
, "TPEC: exited to ATC level: " &
907 ATC_Level
'Image (Self_Id
.ATC_Nesting_Level
), 'A'));
909 Self_Id
.Entry_Calls
(Self_Id
.ATC_Nesting_Level
)'Access;
910 Entry_Call
.Next
:= null;
911 Entry_Call
.Mode
:= Timed_Call
;
912 Entry_Call
.Cancellation_Attempted
:= False;
914 if Self_Id
.Deferral_Level
> 1 then
915 Entry_Call
.State
:= Never_Abortable
;
917 Entry_Call
.State
:= Now_Abortable
;
920 Entry_Call
.E
:= Entry_Index
(E
);
921 Entry_Call
.Prio
:= STPO
.Get_Priority
(Self_Id
);
922 Entry_Call
.Uninterpreted_Data
:= Uninterpreted_Data
;
923 Entry_Call
.Called_PO
:= To_Address
(Object
);
924 Entry_Call
.Called_Task
:= null;
925 Entry_Call
.Exception_To_Raise
:= Ada
.Exceptions
.Null_Id
;
927 PO_Do_Or_Queue
(Self_Id
, Object
, Entry_Call
, With_Abort
=> True);
928 PO_Service_Entries
(Self_Id
, Object
);
933 STPO
.Write_Lock
(Self_Id
);
936 -- Try to avoid waiting for completed or cancelled calls.
938 if Entry_Call
.State
>= Done
then
939 Utilities
.Exit_One_ATC_Level
(Self_Id
);
944 STPO
.Unlock
(Self_Id
);
947 Entry_Call_Successful
:= Entry_Call
.State
= Done
;
948 Initialization
.Undefer_Abort
(Self_Id
);
949 Entry_Calls
.Check_Exception
(Self_Id
, Entry_Call
);
953 Entry_Calls
.Wait_For_Completion_With_Timeout
954 (Entry_Call
, Timeout
, Mode
, Yielded
);
959 STPO
.Unlock
(Self_Id
);
962 -- ??? Do we need to yield in case Yielded is False
964 Initialization
.Undefer_Abort
(Self_Id
);
965 Entry_Call_Successful
:= Entry_Call
.State
= Done
;
966 Entry_Calls
.Check_Exception
(Self_Id
, Entry_Call
);
967 end Timed_Protected_Entry_Call
;
969 ----------------------------
970 -- Update_For_Queue_To_PO --
971 ----------------------------
973 -- Update the state of an existing entry call, based on
974 -- whether the current queuing action is with or without abort.
975 -- Call this only while holding the server's lock.
976 -- It returns with the server's lock released.
978 New_State
: constant array (Boolean, Entry_Call_State
)
979 of Entry_Call_State
:=
981 (Never_Abortable
=> Never_Abortable
,
982 Not_Yet_Abortable
=> Now_Abortable
,
983 Was_Abortable
=> Now_Abortable
,
984 Now_Abortable
=> Now_Abortable
,
986 Cancelled
=> Cancelled
),
988 (Never_Abortable
=> Never_Abortable
,
989 Not_Yet_Abortable
=> Not_Yet_Abortable
,
990 Was_Abortable
=> Was_Abortable
,
991 Now_Abortable
=> Now_Abortable
,
993 Cancelled
=> Cancelled
)
996 procedure Update_For_Queue_To_PO
997 (Entry_Call
: Entry_Call_Link
;
998 With_Abort
: Boolean)
1000 Old
: constant Entry_Call_State
:= Entry_Call
.State
;
1003 pragma Assert
(Old
< Done
);
1005 Entry_Call
.State
:= New_State
(With_Abort
, Entry_Call
.State
);
1007 if Entry_Call
.Mode
= Asynchronous_Call
then
1008 if Old
< Was_Abortable
and then
1009 Entry_Call
.State
= Now_Abortable
1015 STPO
.Write_Lock
(Entry_Call
.Self
);
1017 if Entry_Call
.Self
.Common
.State
= Async_Select_Sleep
then
1018 STPO
.Wakeup
(Entry_Call
.Self
, Async_Select_Sleep
);
1021 STPO
.Unlock
(Entry_Call
.Self
);
1029 elsif Entry_Call
.Mode
= Conditional_Call
then
1030 pragma Assert
(Entry_Call
.State
< Was_Abortable
);
1033 end Update_For_Queue_To_PO
;
1035 end System
.Tasking
.Protected_Objects
.Operations
;