1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
5 -- S Y S T E M . T A S K I N G . P R O T E C T E D _ O B J E C T S . --
6 -- O P E R A T I O N S --
10 -- Copyright (C) 1998-2005, Free Software Foundation, Inc. --
12 -- GNARL is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNARL; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
21 -- Boston, MA 02110-1301, USA. --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
30 -- GNARL was developed by the GNARL team at Florida State University. --
31 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
33 ------------------------------------------------------------------------------
35 -- This package contains all the extended primitives related to
36 -- Protected_Objects with entries.
38 -- The handling of protected objects with no entries is done in
39 -- System.Tasking.Protected_Objects, the simple routines for protected
40 -- objects with entries in System.Tasking.Protected_Objects.Entries.
42 -- The split between Entries and Operations is needed to break circular
43 -- dependencies inside the run time.
45 -- This package contains all primitives related to Protected_Objects.
46 -- Note: the compiler generates direct calls to this interface, via Rtsfind.
49 -- Used for Exception_ID
53 with System
.Task_Primitives
.Operations
;
54 -- used for Initialize_Lock
60 with System
.Tasking
.Entry_Calls
;
61 -- used for Wait_For_Completion
62 -- Wait_Until_Abortable
63 -- Wait_For_Completion_With_Timeout
65 with System
.Tasking
.Initialization
;
66 -- Used for Defer_Abort,
68 -- Change_Base_Priority
70 pragma Elaborate_All
(System
.Tasking
.Initialization
);
71 -- This insures that tasking is initialized if any protected objects are
74 with System
.Tasking
.Queuing
;
76 -- Broadcast_Program_Error
77 -- Select_Protected_Entry_Call
81 with System
.Tasking
.Rendezvous
;
82 -- used for Task_Do_Or_Queue
84 with System
.Tasking
.Utilities
;
85 -- used for Exit_One_ATC_Level
87 with System
.Tasking
.Debug
;
90 with System
.Parameters
;
91 -- used for Single_Lock
94 with System
.Traces
.Tasking
;
95 -- used for Send_Trace_Info
97 with System
.Restrictions
;
98 -- used for Run_Time_Restrictions
100 package body System
.Tasking
.Protected_Objects
.Operations
is
102 package STPO
renames System
.Task_Primitives
.Operations
;
109 use System
.Restrictions
;
110 use System
.Restrictions
.Rident
;
112 use System
.Traces
.Tasking
;
114 -----------------------
115 -- Local Subprograms --
116 -----------------------
118 procedure Update_For_Queue_To_PO
119 (Entry_Call
: Entry_Call_Link
;
120 With_Abort
: Boolean);
121 pragma Inline
(Update_For_Queue_To_PO
);
122 -- Update the state of an existing entry call to reflect
123 -- the fact that it is being enqueued, based on
124 -- whether the current queuing action is with or without abort.
125 -- Call this only while holding the PO's lock.
126 -- It returns with the PO's lock still held.
128 procedure Requeue_Call
130 Object
: Protection_Entries_Access
;
131 Entry_Call
: Entry_Call_Link
;
132 With_Abort
: Boolean);
133 -- Handle requeue of Entry_Call.
134 -- In particular, queue the call if needed, or service it immediately
137 ---------------------------------
138 -- Cancel_Protected_Entry_Call --
139 ---------------------------------
141 -- Compiler interface only. Do not call from within the RTS.
142 -- This should have analogous effect to Cancel_Task_Entry_Call,
143 -- setting the value of Block.Cancelled instead of returning
144 -- the parameter value Cancelled.
146 -- The effect should be idempotent, since the call may already
147 -- have been dequeued.
160 -- X : protected_entry_index := 1;
161 -- B80b : communication_block;
162 -- communication_blockIP (B80b);
167 -- procedure _clean is
169 -- if enqueued (B80b) then
170 -- cancel_protected_entry_call (B80b);
175 -- protected_entry_call (rTV!(r)._object'unchecked_access, X,
176 -- null_address, asynchronous_call, B80b, objectF => 0);
177 -- if enqueued (B80b) then
184 -- when _abort_signal =>
185 -- abort_undefer.all;
188 -- if not cancelled (B80b) then
193 -- If the entry call completes after we get into the abortable part,
194 -- Abort_Signal should be raised and ATC will take us to the at-end
195 -- handler, which will call _clean.
197 -- If the entry call returns with the call already completed,
198 -- we can skip this, and use the "if enqueued()" to go past
199 -- the at-end handler, but we will still call _clean.
201 -- If the abortable part completes before the entry call is Done,
202 -- it will call _clean.
204 -- If the entry call or the abortable part raises an exception,
205 -- we will still call _clean, but the value of Cancelled should not matter.
207 -- Whoever calls _clean first gets to decide whether the call
208 -- has been "cancelled".
210 -- Enqueued should be true if there is any chance that the call
211 -- is still on a queue. It seems to be safe to make it True if
212 -- the call was Onqueue at some point before return from
213 -- Protected_Entry_Call.
215 -- Cancelled should be true iff the abortable part completed
216 -- and succeeded in cancelling the entry call before it completed.
219 -- The need for Enqueued is less obvious.
220 -- The "if enqueued ()" tests are not necessary, since both
221 -- Cancel_Protected_Entry_Call and Protected_Entry_Call must
222 -- do the same test internally, with locking. The one that
223 -- makes cancellation conditional may be a useful heuristic
224 -- since at least 1/2 the time the call should be off-queue
225 -- by that point. The other one seems totally useless, since
226 -- Protected_Entry_Call must do the same check and then
227 -- possibly wait for the call to be abortable, internally.
229 -- We can check Call.State here without locking the caller's mutex,
230 -- since the call must be over after returning from Wait_For_Completion.
231 -- No other task can access the call record at this point.
233 procedure Cancel_Protected_Entry_Call
234 (Block
: in out Communication_Block
) is
236 Entry_Calls
.Try_To_Cancel_Entry_Call
(Block
.Cancelled
);
237 end Cancel_Protected_Entry_Call
;
243 function Cancelled
(Block
: Communication_Block
) return Boolean is
245 return Block
.Cancelled
;
248 -------------------------
249 -- Complete_Entry_Body --
250 -------------------------
252 procedure Complete_Entry_Body
(Object
: Protection_Entries_Access
) is
254 Exceptional_Complete_Entry_Body
(Object
, Ada
.Exceptions
.Null_Id
);
255 end Complete_Entry_Body
;
261 function Enqueued
(Block
: Communication_Block
) return Boolean is
263 return Block
.Enqueued
;
266 -------------------------------------
267 -- Exceptional_Complete_Entry_Body --
268 -------------------------------------
270 procedure Exceptional_Complete_Entry_Body
271 (Object
: Protection_Entries_Access
;
272 Ex
: Ada
.Exceptions
.Exception_Id
)
274 procedure Transfer_Occurrence
275 (Target
: Ada
.Exceptions
.Exception_Occurrence_Access
;
276 Source
: Ada
.Exceptions
.Exception_Occurrence
);
277 pragma Import
(C
, Transfer_Occurrence
, "__gnat_transfer_occurrence");
279 Entry_Call
: constant Entry_Call_Link
:= Object
.Call_In_Progress
;
282 (Debug
.Trace
(STPO
.Self
, "Exceptional_Complete_Entry_Body", 'P'));
284 -- We must have abort deferred, since we are inside
285 -- a protected operation.
287 if Entry_Call
/= null then
288 -- The call was not requeued.
290 Entry_Call
.Exception_To_Raise
:= Ex
;
292 if Ex
/= Ada
.Exceptions
.Null_Id
then
294 (Entry_Call
.Self
.Common
.Compiler_Data
.Current_Excep
'Access,
295 STPO
.Self
.Common
.Compiler_Data
.Current_Excep
);
298 -- Wakeup_Entry_Caller will be called from PO_Do_Or_Queue or
299 -- PO_Service_Entries on return.
302 if Runtime_Traces
then
303 Send_Trace_Info
(PO_Done
, Entry_Call
.Self
);
305 end Exceptional_Complete_Entry_Body
;
311 procedure PO_Do_Or_Queue
313 Object
: Protection_Entries_Access
;
314 Entry_Call
: Entry_Call_Link
;
315 With_Abort
: Boolean)
317 E
: constant Protected_Entry_Index
:=
318 Protected_Entry_Index
(Entry_Call
.E
);
319 Barrier_Value
: Boolean;
322 -- When the Action procedure for an entry body returns, it is either
323 -- completed (having called [Exceptional_]Complete_Entry_Body) or it
324 -- is queued, having executed a requeue statement.
327 Object
.Entry_Bodies
(
328 Object
.Find_Body_Index
(Object
.Compiler_Info
, E
)).
329 Barrier
(Object
.Compiler_Info
, E
);
331 if Barrier_Value
then
333 -- Not abortable while service is in progress.
335 if Entry_Call
.State
= Now_Abortable
then
336 Entry_Call
.State
:= Was_Abortable
;
339 Object
.Call_In_Progress
:= Entry_Call
;
342 (Debug
.Trace
(Self_ID
, "PODOQ: start entry body", 'P'));
343 Object
.Entry_Bodies
(
344 Object
.Find_Body_Index
(Object
.Compiler_Info
, E
)).Action
(
345 Object
.Compiler_Info
, Entry_Call
.Uninterpreted_Data
, E
);
347 if Object
.Call_In_Progress
/= null then
349 -- Body of current entry served call to completion
351 Object
.Call_In_Progress
:= null;
357 STPO
.Write_Lock
(Entry_Call
.Self
);
358 Initialization
.Wakeup_Entry_Caller
(Self_ID
, Entry_Call
, Done
);
359 STPO
.Unlock
(Entry_Call
.Self
);
366 Requeue_Call
(Self_ID
, Object
, Entry_Call
, With_Abort
);
369 elsif Entry_Call
.Mode
/= Conditional_Call
370 or else not With_Abort
373 if Run_Time_Restrictions
.Set
(Max_Entry_Queue_Length
)
375 Run_Time_Restrictions
.Value
(Max_Entry_Queue_Length
) <=
376 Queuing
.Count_Waiting
(Object
.Entry_Queues
(E
))
378 -- This violates the Max_Entry_Queue_Length restriction,
379 -- raise Program_Error.
381 Entry_Call
.Exception_To_Raise
:= Program_Error
'Identity;
387 STPO
.Write_Lock
(Entry_Call
.Self
);
388 Initialization
.Wakeup_Entry_Caller
(Self_ID
, Entry_Call
, Done
);
389 STPO
.Unlock
(Entry_Call
.Self
);
395 Queuing
.Enqueue
(Object
.Entry_Queues
(E
), Entry_Call
);
396 Update_For_Queue_To_PO
(Entry_Call
, With_Abort
);
399 -- Conditional_Call and With_Abort
405 STPO
.Write_Lock
(Entry_Call
.Self
);
406 pragma Assert
(Entry_Call
.State
>= Was_Abortable
);
407 Initialization
.Wakeup_Entry_Caller
(Self_ID
, Entry_Call
, Cancelled
);
408 STPO
.Unlock
(Entry_Call
.Self
);
417 Queuing
.Broadcast_Program_Error
(Self_ID
, Object
, Entry_Call
);
420 ------------------------
421 -- PO_Service_Entries --
422 ------------------------
424 procedure PO_Service_Entries
426 Object
: Entries
.Protection_Entries_Access
;
427 Unlock_Object
: Boolean := True)
429 E
: Protected_Entry_Index
;
431 Entry_Call
: Entry_Call_Link
;
435 Queuing
.Select_Protected_Entry_Call
(Self_ID
, Object
, Entry_Call
);
437 exit when Entry_Call
= null;
439 E
:= Protected_Entry_Index
(Entry_Call
.E
);
441 -- Not abortable while service is in progress.
443 if Entry_Call
.State
= Now_Abortable
then
444 Entry_Call
.State
:= Was_Abortable
;
447 Object
.Call_In_Progress
:= Entry_Call
;
450 if Runtime_Traces
then
451 Send_Trace_Info
(PO_Run
, Self_ID
,
452 Entry_Call
.Self
, Entry_Index
(E
));
456 (Debug
.Trace
(Self_ID
, "POSE: start entry body", 'P'));
457 Object
.Entry_Bodies
(
458 Object
.Find_Body_Index
(Object
.Compiler_Info
, E
)).Action
(
459 Object
.Compiler_Info
, Entry_Call
.Uninterpreted_Data
, E
);
462 Queuing
.Broadcast_Program_Error
463 (Self_ID
, Object
, Entry_Call
);
466 if Object
.Call_In_Progress
= null then
468 (Self_ID
, Object
, Entry_Call
, Entry_Call
.Requeue_With_Abort
);
469 exit when Entry_Call
.State
= Cancelled
;
472 Object
.Call_In_Progress
:= null;
473 Caller
:= Entry_Call
.Self
;
479 STPO
.Write_Lock
(Caller
);
480 Initialization
.Wakeup_Entry_Caller
(Self_ID
, Entry_Call
, Done
);
481 STPO
.Unlock
(Caller
);
489 if Unlock_Object
then
490 Unlock_Entries
(Object
);
492 end PO_Service_Entries
;
494 ---------------------
495 -- Protected_Count --
496 ---------------------
498 function Protected_Count
499 (Object
: Protection_Entries
'Class;
500 E
: Protected_Entry_Index
)
504 return Queuing
.Count_Waiting
(Object
.Entry_Queues
(E
));
507 --------------------------
508 -- Protected_Entry_Call --
509 --------------------------
511 -- Compiler interface only. Do not call from within the RTS.
520 -- X : protected_entry_index := 1;
521 -- B85b : communication_block;
522 -- communication_blockIP (B85b);
524 -- protected_entry_call (rTV!(r)._object'unchecked_access, X,
525 -- null_address, conditional_call, B85b, objectF => 0);
526 -- if cancelled (B85b) then
533 -- See also Cancel_Protected_Entry_Call for code expansion of asynchronous
536 -- The initial part of this procedure does not need to lock the the calling
537 -- task's ATCB, up to the point where the call record first may be queued
538 -- (PO_Do_Or_Queue), since before that no other task will have access to
541 -- If this is a call made inside of an abort deferred region, the call
542 -- should be never abortable.
544 -- If the call was not queued abortably, we need to wait until it is before
545 -- proceeding with the abortable part.
547 -- There are some heuristics here, just to save time for frequently
548 -- occurring cases. For example, we check Initially_Abortable to try to
549 -- avoid calling the procedure Wait_Until_Abortable, since the normal case
550 -- for async. entry calls is to be queued abortably.
552 -- Another heuristic uses the Block.Enqueued to try to avoid calling
553 -- Cancel_Protected_Entry_Call if the call can be served immediately.
555 procedure Protected_Entry_Call
556 (Object
: Protection_Entries_Access
;
557 E
: Protected_Entry_Index
;
558 Uninterpreted_Data
: System
.Address
;
560 Block
: out Communication_Block
)
562 Self_ID
: constant Task_Id
:= STPO
.Self
;
563 Entry_Call
: Entry_Call_Link
;
564 Initially_Abortable
: Boolean;
565 Ceiling_Violation
: Boolean;
569 (Debug
.Trace
(Self_ID
, "Protected_Entry_Call", 'P'));
571 if Runtime_Traces
then
572 Send_Trace_Info
(PO_Call
, Entry_Index
(E
));
575 if Self_ID
.ATC_Nesting_Level
= ATC_Level
'Last then
577 (Storage_Error
'Identity, "not enough ATC nesting levels");
580 -- If pragma Detect_Blocking is active then Program_Error must be
581 -- raised if this potentially blocking operation is called from a
585 and then Self_ID
.Common
.Protected_Action_Nesting
> 0
587 Ada
.Exceptions
.Raise_Exception
588 (Program_Error
'Identity, "potentially blocking operation");
591 Initialization
.Defer_Abort
(Self_ID
);
592 Lock_Entries
(Object
, Ceiling_Violation
);
594 if Ceiling_Violation
then
596 -- Failed ceiling check
598 Initialization
.Undefer_Abort
(Self_ID
);
602 Block
.Self
:= Self_ID
;
603 Self_ID
.ATC_Nesting_Level
:= Self_ID
.ATC_Nesting_Level
+ 1;
605 (Debug
.Trace
(Self_ID
, "PEC: entered ATC level: " &
606 ATC_Level
'Image (Self_ID
.ATC_Nesting_Level
), 'A'));
608 Self_ID
.Entry_Calls
(Self_ID
.ATC_Nesting_Level
)'Access;
609 Entry_Call
.Next
:= null;
610 Entry_Call
.Mode
:= Mode
;
611 Entry_Call
.Cancellation_Attempted
:= False;
613 if Self_ID
.Deferral_Level
> 1 then
614 Entry_Call
.State
:= Never_Abortable
;
616 Entry_Call
.State
:= Now_Abortable
;
619 Entry_Call
.E
:= Entry_Index
(E
);
620 Entry_Call
.Prio
:= STPO
.Get_Priority
(Self_ID
);
621 Entry_Call
.Uninterpreted_Data
:= Uninterpreted_Data
;
622 Entry_Call
.Called_PO
:= To_Address
(Object
);
623 Entry_Call
.Called_Task
:= null;
624 Entry_Call
.Exception_To_Raise
:= Ada
.Exceptions
.Null_Id
;
626 PO_Do_Or_Queue
(Self_ID
, Object
, Entry_Call
, With_Abort
=> True);
627 Initially_Abortable
:= Entry_Call
.State
= Now_Abortable
;
628 PO_Service_Entries
(Self_ID
, Object
);
630 -- Try to prevent waiting later (in Try_To_Cancel_Protected_Entry_Call)
631 -- for completed or cancelled calls. (This is a heuristic, only.)
633 if Entry_Call
.State
>= Done
then
635 -- Once State >= Done it will not change any more.
641 STPO
.Write_Lock
(Self_ID
);
642 Utilities
.Exit_One_ATC_Level
(Self_ID
);
643 STPO
.Unlock
(Self_ID
);
649 Block
.Enqueued
:= False;
650 Block
.Cancelled
:= Entry_Call
.State
= Cancelled
;
651 Initialization
.Undefer_Abort
(Self_ID
);
652 Entry_Calls
.Check_Exception
(Self_ID
, Entry_Call
);
656 -- In this case we cannot conclude anything,
657 -- since State can change concurrently.
661 -- Now for the general case.
663 if Mode
= Asynchronous_Call
then
665 -- Try to avoid an expensive call.
667 if not Initially_Abortable
then
670 Entry_Calls
.Wait_Until_Abortable
(Self_ID
, Entry_Call
);
673 Entry_Calls
.Wait_Until_Abortable
(Self_ID
, Entry_Call
);
677 elsif Mode
< Asynchronous_Call
then
679 -- Simple_Call or Conditional_Call
683 Entry_Calls
.Wait_For_Completion
(Entry_Call
);
686 STPO
.Write_Lock
(Self_ID
);
687 Entry_Calls
.Wait_For_Completion
(Entry_Call
);
688 STPO
.Unlock
(Self_ID
);
691 Block
.Cancelled
:= Entry_Call
.State
= Cancelled
;
694 pragma Assert
(False);
698 Initialization
.Undefer_Abort
(Self_ID
);
699 Entry_Calls
.Check_Exception
(Self_ID
, Entry_Call
);
700 end Protected_Entry_Call
;
706 procedure Requeue_Call
708 Object
: Protection_Entries_Access
;
709 Entry_Call
: Entry_Call_Link
;
710 With_Abort
: Boolean)
712 New_Object
: Protection_Entries_Access
;
713 Ceiling_Violation
: Boolean;
715 E
: Protected_Entry_Index
;
718 New_Object
:= To_Protection
(Entry_Call
.Called_PO
);
720 if New_Object
= null then
722 -- Call is to be requeued to a task entry
728 Result
:= Rendezvous
.Task_Do_Or_Queue
729 (Self_Id
, Entry_Call
,
730 With_Abort
=> Entry_Call
.Requeue_With_Abort
);
733 Queuing
.Broadcast_Program_Error
734 (Self_Id
, Object
, Entry_Call
, RTS_Locked
=> True);
742 -- Call should be requeued to a PO
744 if Object
/= New_Object
then
746 -- Requeue is to different PO
748 Lock_Entries
(New_Object
, Ceiling_Violation
);
750 if Ceiling_Violation
then
751 Object
.Call_In_Progress
:= null;
752 Queuing
.Broadcast_Program_Error
753 (Self_Id
, Object
, Entry_Call
);
756 PO_Do_Or_Queue
(Self_Id
, New_Object
, Entry_Call
, With_Abort
);
757 PO_Service_Entries
(Self_Id
, New_Object
);
761 -- Requeue is to same protected object
763 if Entry_Call
.Requeue_With_Abort
764 and then Entry_Call
.Cancellation_Attempted
766 -- If this is a requeue with abort and someone tried
767 -- to cancel this call, cancel it at this point.
769 Entry_Call
.State
:= Cancelled
;
774 or else Entry_Call
.Mode
/= Conditional_Call
776 E
:= Protected_Entry_Index
(Entry_Call
.E
);
778 if Run_Time_Restrictions
.Set
(Max_Entry_Queue_Length
)
780 Run_Time_Restrictions
.Value
(Max_Entry_Queue_Length
) <=
781 Queuing
.Count_Waiting
(Object
.Entry_Queues
(E
))
783 -- This violates the Max_Entry_Queue_Length restriction,
784 -- raise Program_Error.
786 Entry_Call
.Exception_To_Raise
:= Program_Error
'Identity;
792 STPO
.Write_Lock
(Entry_Call
.Self
);
793 Initialization
.Wakeup_Entry_Caller
794 (Self_Id
, Entry_Call
, Done
);
795 STPO
.Unlock
(Entry_Call
.Self
);
802 (New_Object
.Entry_Queues
(E
), Entry_Call
);
803 Update_For_Queue_To_PO
(Entry_Call
, With_Abort
);
807 PO_Do_Or_Queue
(Self_Id
, New_Object
, Entry_Call
, With_Abort
);
813 ----------------------------
814 -- Protected_Entry_Caller --
815 ----------------------------
817 function Protected_Entry_Caller
818 (Object
: Protection_Entries
'Class) return Task_Id
is
820 return Object
.Call_In_Progress
.Self
;
821 end Protected_Entry_Caller
;
823 -----------------------------
824 -- Requeue_Protected_Entry --
825 -----------------------------
827 -- Compiler interface only. Do not call from within the RTS.
836 -- procedure rPT__E10b (O : address; P : address; E :
837 -- protected_entry_index) is
838 -- type rTVP is access rTV;
840 -- _object : rTVP := rTVP!(O);
843 -- rR : protection renames _object._object;
844 -- vP : integer renames _object.v;
845 -- bP : boolean renames _object.b;
849 -- requeue_protected_entry (rR'unchecked_access, rR'
850 -- unchecked_access, 2, false, objectF => 0, new_objectF =>
854 -- complete_entry_body (_object._object'unchecked_access, objectF =>
859 -- abort_undefer.all;
860 -- exceptional_complete_entry_body (_object._object'
861 -- unchecked_access, current_exception, objectF => 0);
865 procedure Requeue_Protected_Entry
866 (Object
: Protection_Entries_Access
;
867 New_Object
: Protection_Entries_Access
;
868 E
: Protected_Entry_Index
;
869 With_Abort
: Boolean)
871 Entry_Call
: constant Entry_Call_Link
:= Object
.Call_In_Progress
;
875 (Debug
.Trace
(STPO
.Self
, "Requeue_Protected_Entry", 'P'));
876 pragma Assert
(STPO
.Self
.Deferral_Level
> 0);
878 Entry_Call
.E
:= Entry_Index
(E
);
879 Entry_Call
.Called_PO
:= To_Address
(New_Object
);
880 Entry_Call
.Called_Task
:= null;
881 Entry_Call
.Requeue_With_Abort
:= With_Abort
;
882 Object
.Call_In_Progress
:= null;
883 end Requeue_Protected_Entry
;
885 -------------------------------------
886 -- Requeue_Task_To_Protected_Entry --
887 -------------------------------------
889 -- Compiler interface only.
899 -- accept_call (1, A79b);
901 -- requeue_task_to_protected_entry (rTV!(r)._object'
902 -- unchecked_access, 2, false, new_objectF => 0);
905 -- complete_rendezvous;
907 -- when all others =>
908 -- exceptional_complete_rendezvous (get_gnat_exception);
911 procedure Requeue_Task_To_Protected_Entry
912 (New_Object
: Protection_Entries_Access
;
913 E
: Protected_Entry_Index
;
914 With_Abort
: Boolean)
916 Self_ID
: constant Task_Id
:= STPO
.Self
;
917 Entry_Call
: constant Entry_Call_Link
:= Self_ID
.Common
.Call
;
920 Initialization
.Defer_Abort
(Self_ID
);
922 -- We do not need to lock Self_ID here since the call is not abortable
923 -- at this point, and therefore, the caller cannot cancel the call.
925 Entry_Call
.Needs_Requeue
:= True;
926 Entry_Call
.Requeue_With_Abort
:= With_Abort
;
927 Entry_Call
.Called_PO
:= To_Address
(New_Object
);
928 Entry_Call
.Called_Task
:= null;
929 Entry_Call
.E
:= Entry_Index
(E
);
930 Initialization
.Undefer_Abort
(Self_ID
);
931 end Requeue_Task_To_Protected_Entry
;
933 ---------------------
934 -- Service_Entries --
935 ---------------------
937 procedure Service_Entries
(Object
: Protection_Entries_Access
) is
938 Self_ID
: constant Task_Id
:= STPO
.Self
;
940 PO_Service_Entries
(Self_ID
, Object
);
943 --------------------------------
944 -- Timed_Protected_Entry_Call --
945 --------------------------------
947 -- Compiler interface only. Do not call from within the RTS.
949 procedure Timed_Protected_Entry_Call
950 (Object
: Protection_Entries_Access
;
951 E
: Protected_Entry_Index
;
952 Uninterpreted_Data
: System
.Address
;
955 Entry_Call_Successful
: out Boolean)
957 Self_Id
: constant Task_Id
:= STPO
.Self
;
958 Entry_Call
: Entry_Call_Link
;
959 Ceiling_Violation
: Boolean;
963 if Self_Id
.ATC_Nesting_Level
= ATC_Level
'Last then
964 Raise_Exception
(Storage_Error
'Identity,
965 "not enough ATC nesting levels");
968 -- If pragma Detect_Blocking is active then Program_Error must be
969 -- raised if this potentially blocking operation is called from a
973 and then Self_Id
.Common
.Protected_Action_Nesting
> 0
975 Ada
.Exceptions
.Raise_Exception
976 (Program_Error
'Identity, "potentially blocking operation");
979 if Runtime_Traces
then
980 Send_Trace_Info
(POT_Call
, Entry_Index
(E
), Timeout
);
983 Initialization
.Defer_Abort
(Self_Id
);
984 Lock_Entries
(Object
, Ceiling_Violation
);
986 if Ceiling_Violation
then
987 Initialization
.Undefer_Abort
(Self_Id
);
991 Self_Id
.ATC_Nesting_Level
:= Self_Id
.ATC_Nesting_Level
+ 1;
993 (Debug
.Trace
(Self_Id
, "TPEC: exited to ATC level: " &
994 ATC_Level
'Image (Self_Id
.ATC_Nesting_Level
), 'A'));
996 Self_Id
.Entry_Calls
(Self_Id
.ATC_Nesting_Level
)'Access;
997 Entry_Call
.Next
:= null;
998 Entry_Call
.Mode
:= Timed_Call
;
999 Entry_Call
.Cancellation_Attempted
:= False;
1001 if Self_Id
.Deferral_Level
> 1 then
1002 Entry_Call
.State
:= Never_Abortable
;
1004 Entry_Call
.State
:= Now_Abortable
;
1007 Entry_Call
.E
:= Entry_Index
(E
);
1008 Entry_Call
.Prio
:= STPO
.Get_Priority
(Self_Id
);
1009 Entry_Call
.Uninterpreted_Data
:= Uninterpreted_Data
;
1010 Entry_Call
.Called_PO
:= To_Address
(Object
);
1011 Entry_Call
.Called_Task
:= null;
1012 Entry_Call
.Exception_To_Raise
:= Ada
.Exceptions
.Null_Id
;
1014 PO_Do_Or_Queue
(Self_Id
, Object
, Entry_Call
, With_Abort
=> True);
1015 PO_Service_Entries
(Self_Id
, Object
);
1020 STPO
.Write_Lock
(Self_Id
);
1023 -- Try to avoid waiting for completed or cancelled calls.
1025 if Entry_Call
.State
>= Done
then
1026 Utilities
.Exit_One_ATC_Level
(Self_Id
);
1031 STPO
.Unlock
(Self_Id
);
1034 Entry_Call_Successful
:= Entry_Call
.State
= Done
;
1035 Initialization
.Undefer_Abort
(Self_Id
);
1036 Entry_Calls
.Check_Exception
(Self_Id
, Entry_Call
);
1040 Entry_Calls
.Wait_For_Completion_With_Timeout
1041 (Entry_Call
, Timeout
, Mode
, Yielded
);
1046 STPO
.Unlock
(Self_Id
);
1049 -- ??? Do we need to yield in case Yielded is False
1051 Initialization
.Undefer_Abort
(Self_Id
);
1052 Entry_Call_Successful
:= Entry_Call
.State
= Done
;
1053 Entry_Calls
.Check_Exception
(Self_Id
, Entry_Call
);
1054 end Timed_Protected_Entry_Call
;
1056 ----------------------------
1057 -- Update_For_Queue_To_PO --
1058 ----------------------------
1060 -- Update the state of an existing entry call, based on
1061 -- whether the current queuing action is with or without abort.
1062 -- Call this only while holding the server's lock.
1063 -- It returns with the server's lock released.
1065 New_State
: constant array (Boolean, Entry_Call_State
)
1066 of Entry_Call_State
:=
1068 (Never_Abortable
=> Never_Abortable
,
1069 Not_Yet_Abortable
=> Now_Abortable
,
1070 Was_Abortable
=> Now_Abortable
,
1071 Now_Abortable
=> Now_Abortable
,
1073 Cancelled
=> Cancelled
),
1075 (Never_Abortable
=> Never_Abortable
,
1076 Not_Yet_Abortable
=> Not_Yet_Abortable
,
1077 Was_Abortable
=> Was_Abortable
,
1078 Now_Abortable
=> Now_Abortable
,
1080 Cancelled
=> Cancelled
)
1083 procedure Update_For_Queue_To_PO
1084 (Entry_Call
: Entry_Call_Link
;
1085 With_Abort
: Boolean)
1087 Old
: constant Entry_Call_State
:= Entry_Call
.State
;
1090 pragma Assert
(Old
< Done
);
1092 Entry_Call
.State
:= New_State
(With_Abort
, Entry_Call
.State
);
1094 if Entry_Call
.Mode
= Asynchronous_Call
then
1095 if Old
< Was_Abortable
and then
1096 Entry_Call
.State
= Now_Abortable
1102 STPO
.Write_Lock
(Entry_Call
.Self
);
1104 if Entry_Call
.Self
.Common
.State
= Async_Select_Sleep
then
1105 STPO
.Wakeup
(Entry_Call
.Self
, Async_Select_Sleep
);
1108 STPO
.Unlock
(Entry_Call
.Self
);
1116 elsif Entry_Call
.Mode
= Conditional_Call
then
1117 pragma Assert
(Entry_Call
.State
< Was_Abortable
);
1120 end Update_For_Queue_To_PO
;
1122 end System
.Tasking
.Protected_Objects
.Operations
;