1 ------------------------------------------------------------------------------
3 -- GNU ADA 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 --
11 -- Copyright (C) 1998-2001, Free Software Foundation, Inc. --
13 -- GNARL is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNARL; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
24 -- As a special exception, if other files instantiate generics from this --
25 -- unit, or you link this unit with other files to produce an executable, --
26 -- this unit does not by itself cause the resulting executable to be --
27 -- covered by the GNU General Public License. This exception does not --
28 -- however invalidate any other reasons why the executable file might be --
29 -- covered by the GNU Public License. --
31 -- GNARL was developed by the GNARL team at Florida State University. It is --
32 -- now maintained by Ada Core Technologies, Inc. (http://www.gnat.com). --
34 ------------------------------------------------------------------------------
36 -- This package contains all the extended primitives related to
37 -- Protected_Objects with entries.
39 -- The handling of protected objects with no entries is done in
40 -- System.Tasking.Protected_Objects, the simple routines for protected
41 -- objects with entries in System.Tasking.Protected_Objects.Entries.
43 -- The split between Entries and Operations is needed to break circular
44 -- dependencies inside the run time.
46 -- This package contains all primitives related to Protected_Objects.
47 -- Note: the compiler generates direct calls to this interface, via Rtsfind.
50 -- Used for Exception_ID
54 with System
.Task_Primitives
.Operations
;
55 -- used for Initialize_Lock
61 with System
.Tasking
.Entry_Calls
;
62 -- used for Wait_For_Completion
63 -- Wait_Until_Abortable
64 -- Wait_For_Completion_With_Timeout
66 with System
.Tasking
.Initialization
;
67 -- Used for Defer_Abort,
69 -- Change_Base_Priority
71 pragma Elaborate_All
(System
.Tasking
.Initialization
);
72 -- This insures that tasking is initialized if any protected objects are
75 with System
.Tasking
.Queuing
;
77 -- Broadcast_Program_Error
78 -- Select_Protected_Entry_Call
82 with System
.Tasking
.Rendezvous
;
83 -- used for Task_Do_Or_Queue
85 with System
.Tasking
.Debug
;
88 with System
.Parameters
;
89 -- used for Single_Lock
92 with System
.Traces
.Tasking
;
93 -- used for Send_Trace_Info
95 package body System
.Tasking
.Protected_Objects
.Operations
is
97 package STPO
renames System
.Task_Primitives
.Operations
;
105 use System
.Traces
.Tasking
;
107 -----------------------
108 -- Local Subprograms --
109 -----------------------
111 procedure Update_For_Queue_To_PO
112 (Entry_Call
: Entry_Call_Link
;
113 With_Abort
: Boolean);
114 pragma Inline
(Update_For_Queue_To_PO
);
115 -- Update the state of an existing entry call to reflect
116 -- the fact that it is being enqueued, based on
117 -- whether the current queuing action is with or without abort.
118 -- Call this only while holding the PO's lock.
119 -- It returns with the PO's lock still held.
121 ---------------------------------
122 -- Cancel_Protected_Entry_Call --
123 ---------------------------------
125 -- Compiler interface only. Do not call from within the RTS.
126 -- This should have analogous effect to Cancel_Task_Entry_Call,
127 -- setting the value of Block.Cancelled instead of returning
128 -- the parameter value Cancelled.
130 -- The effect should be idempotent, since the call may already
131 -- have been dequeued.
144 -- X : protected_entry_index := 1;
145 -- B80b : communication_block;
146 -- _init_proc (B80b);
151 -- procedure _clean is
153 -- if enqueued (B80b) then
154 -- cancel_protected_entry_call (B80b);
159 -- protected_entry_call (rTV!(r)._object'unchecked_access, X,
160 -- null_address, asynchronous_call, B80b, objectF => 0);
161 -- if enqueued (B80b) then
168 -- when _abort_signal =>
169 -- abort_undefer.all;
172 -- if not cancelled (B80b) then
177 -- If the entry call completes after we get into the abortable part,
178 -- Abort_Signal should be raised and ATC will take us to the at-end
179 -- handler, which will call _clean.
181 -- If the entry call returns with the call already completed,
182 -- we can skip this, and use the "if enqueued()" to go past
183 -- the at-end handler, but we will still call _clean.
185 -- If the abortable part completes before the entry call is Done,
186 -- it will call _clean.
188 -- If the entry call or the abortable part raises an exception,
189 -- we will still call _clean, but the value of Cancelled should not matter.
191 -- Whoever calls _clean first gets to decide whether the call
192 -- has been "cancelled".
194 -- Enqueued should be true if there is any chance that the call
195 -- is still on a queue. It seems to be safe to make it True if
196 -- the call was Onqueue at some point before return from
197 -- Protected_Entry_Call.
199 -- Cancelled should be true iff the abortable part completed
200 -- and succeeded in cancelling the entry call before it completed.
203 -- The need for Enqueued is less obvious.
204 -- The "if enqueued ()" tests are not necessary, since both
205 -- Cancel_Protected_Entry_Call and Protected_Entry_Call must
206 -- do the same test internally, with locking. The one that
207 -- makes cancellation conditional may be a useful heuristic
208 -- since at least 1/2 the time the call should be off-queue
209 -- by that point. The other one seems totally useless, since
210 -- Protected_Entry_Call must do the same check and then
211 -- possibly wait for the call to be abortable, internally.
213 -- We can check Call.State here without locking the caller's mutex,
214 -- since the call must be over after returning from Wait_For_Completion.
215 -- No other task can access the call record at this point.
217 procedure Cancel_Protected_Entry_Call
218 (Block
: in out Communication_Block
) is
220 Entry_Calls
.Try_To_Cancel_Entry_Call
(Block
.Cancelled
);
221 end Cancel_Protected_Entry_Call
;
227 function Cancelled
(Block
: Communication_Block
) return Boolean is
229 return Block
.Cancelled
;
232 -------------------------
233 -- Complete_Entry_Body --
234 -------------------------
236 procedure Complete_Entry_Body
(Object
: Protection_Entries_Access
) is
238 Exceptional_Complete_Entry_Body
(Object
, Ada
.Exceptions
.Null_Id
);
239 end Complete_Entry_Body
;
245 function Enqueued
(Block
: Communication_Block
) return Boolean is
247 return Block
.Enqueued
;
250 -------------------------------------
251 -- Exceptional_Complete_Entry_Body --
252 -------------------------------------
254 procedure Exceptional_Complete_Entry_Body
255 (Object
: Protection_Entries_Access
;
256 Ex
: Ada
.Exceptions
.Exception_Id
)
258 Entry_Call
: constant Entry_Call_Link
:= Object
.Call_In_Progress
;
261 (Debug
.Trace
(STPO
.Self
, "Exceptional_Complete_Entry_Body", 'P'));
263 -- We must have abort deferred, since we are inside
264 -- a protected operation.
266 if Entry_Call
/= null then
267 -- The call was not requeued.
269 Entry_Call
.Exception_To_Raise
:= Ex
;
271 -- Wakeup_Entry_Caller will be called from PO_Do_Or_Queue or
272 -- PO_Service_Entries on return.
275 if Runtime_Traces
then
276 Send_Trace_Info
(PO_Done
, Entry_Call
.Self
);
278 end Exceptional_Complete_Entry_Body
;
284 procedure PO_Do_Or_Queue
286 Object
: Protection_Entries_Access
;
287 Entry_Call
: Entry_Call_Link
;
288 With_Abort
: Boolean)
290 E
: Protected_Entry_Index
:= Protected_Entry_Index
(Entry_Call
.E
);
291 New_Object
: Protection_Entries_Access
;
292 Ceiling_Violation
: Boolean;
293 Barrier_Value
: Boolean;
297 -- When the Action procedure for an entry body returns, it is either
298 -- completed (having called [Exceptional_]Complete_Entry_Body) or it
299 -- is queued, having executed a requeue statement.
302 Object
.Entry_Bodies
(
303 Object
.Find_Body_Index
(Object
.Compiler_Info
, E
)).
304 Barrier
(Object
.Compiler_Info
, E
);
306 if Barrier_Value
then
308 -- Not abortable while service is in progress.
310 if Entry_Call
.State
= Now_Abortable
then
311 Entry_Call
.State
:= Was_Abortable
;
314 Object
.Call_In_Progress
:= Entry_Call
;
317 (Debug
.Trace
(Self_ID
, "PODOQ: start entry body", 'P'));
318 Object
.Entry_Bodies
(
319 Object
.Find_Body_Index
(Object
.Compiler_Info
, E
)).Action
(
320 Object
.Compiler_Info
, Entry_Call
.Uninterpreted_Data
, E
);
322 if Object
.Call_In_Progress
/= null then
324 -- Body of current entry served call to completion
326 Object
.Call_In_Progress
:= null;
332 STPO
.Write_Lock
(Entry_Call
.Self
);
333 Initialization
.Wakeup_Entry_Caller
(Self_ID
, Entry_Call
, Done
);
334 STPO
.Unlock
(Entry_Call
.Self
);
341 -- Body of current entry requeued the call
342 New_Object
:= To_Protection
(Entry_Call
.Called_PO
);
344 if New_Object
= null then
346 -- Call was requeued to a task
352 Result
:= Rendezvous
.Task_Do_Or_Queue
353 (Self_ID
, Entry_Call
,
354 With_Abort
=> Entry_Call
.Requeue_With_Abort
);
357 Queuing
.Broadcast_Program_Error
358 (Self_ID
, Object
, Entry_Call
, RTS_Locked
=> True);
368 if Object
/= New_Object
then
369 -- Requeue is on a different object
371 Lock_Entries
(New_Object
, Ceiling_Violation
);
373 if Ceiling_Violation
then
374 Object
.Call_In_Progress
:= null;
375 Queuing
.Broadcast_Program_Error
376 (Self_ID
, Object
, Entry_Call
);
379 PO_Do_Or_Queue
(Self_ID
, New_Object
, Entry_Call
, With_Abort
);
380 PO_Service_Entries
(Self_ID
, New_Object
);
381 Unlock_Entries
(New_Object
);
385 -- Requeue is on same protected object
387 if Entry_Call
.Requeue_With_Abort
388 and then Entry_Call
.Cancellation_Attempted
390 -- If this is a requeue with abort and someone tried
391 -- to cancel this call, cancel it at this point.
393 Entry_Call
.State
:= Cancelled
;
397 if not With_Abort
or else
398 Entry_Call
.Mode
/= Conditional_Call
400 E
:= Protected_Entry_Index
(Entry_Call
.E
);
402 (New_Object
.Entry_Queues
(E
), Entry_Call
);
403 Update_For_Queue_To_PO
(Entry_Call
, With_Abort
);
407 -- Can we convert this recursion to a loop?
409 PO_Do_Or_Queue
(Self_ID
, New_Object
, Entry_Call
, With_Abort
);
414 elsif Entry_Call
.Mode
/= Conditional_Call
or else
416 Queuing
.Enqueue
(Object
.Entry_Queues
(E
), Entry_Call
);
417 Update_For_Queue_To_PO
(Entry_Call
, With_Abort
);
420 -- Conditional_Call and With_Abort
426 STPO
.Write_Lock
(Entry_Call
.Self
);
427 pragma Assert
(Entry_Call
.State
>= Was_Abortable
);
428 Initialization
.Wakeup_Entry_Caller
(Self_ID
, Entry_Call
, Cancelled
);
429 STPO
.Unlock
(Entry_Call
.Self
);
438 Queuing
.Broadcast_Program_Error
(Self_ID
, Object
, Entry_Call
);
441 ------------------------
442 -- PO_Service_Entries --
443 ------------------------
445 procedure PO_Service_Entries
447 Object
: Protection_Entries_Access
)
449 Entry_Call
: Entry_Call_Link
;
450 E
: Protected_Entry_Index
;
452 New_Object
: Protection_Entries_Access
;
453 Ceiling_Violation
: Boolean;
458 Queuing
.Select_Protected_Entry_Call
(Self_ID
, Object
, Entry_Call
);
460 if Entry_Call
/= null then
461 E
:= Protected_Entry_Index
(Entry_Call
.E
);
463 -- Not abortable while service is in progress.
465 if Entry_Call
.State
= Now_Abortable
then
466 Entry_Call
.State
:= Was_Abortable
;
469 Object
.Call_In_Progress
:= Entry_Call
;
472 if Runtime_Traces
then
473 Send_Trace_Info
(PO_Run
, Self_ID
,
474 Entry_Call
.Self
, Entry_Index
(E
));
478 (Debug
.Trace
(Self_ID
, "POSE: start entry body", 'P'));
479 Object
.Entry_Bodies
(
480 Object
.Find_Body_Index
(Object
.Compiler_Info
, E
)).Action
(
481 Object
.Compiler_Info
, Entry_Call
.Uninterpreted_Data
, E
);
484 Queuing
.Broadcast_Program_Error
485 (Self_ID
, Object
, Entry_Call
);
488 if Object
.Call_In_Progress
/= null then
489 Object
.Call_In_Progress
:= null;
490 Caller
:= Entry_Call
.Self
;
496 STPO
.Write_Lock
(Caller
);
497 Initialization
.Wakeup_Entry_Caller
(Self_ID
, Entry_Call
, Done
);
498 STPO
.Unlock
(Caller
);
505 -- Call needs to be requeued
507 New_Object
:= To_Protection
(Entry_Call
.Called_PO
);
509 if New_Object
= null then
511 -- Call is to be requeued to a task entry
517 Result
:= Rendezvous
.Task_Do_Or_Queue
518 (Self_ID
, Entry_Call
,
519 With_Abort
=> Entry_Call
.Requeue_With_Abort
);
522 Queuing
.Broadcast_Program_Error
523 (Self_ID
, Object
, Entry_Call
, RTS_Locked
=> True);
531 -- Call should be requeued to a PO
533 if Object
/= New_Object
then
534 -- Requeue is to different PO
536 Lock_Entries
(New_Object
, Ceiling_Violation
);
538 if Ceiling_Violation
then
539 Object
.Call_In_Progress
:= null;
540 Queuing
.Broadcast_Program_Error
541 (Self_ID
, Object
, Entry_Call
);
544 PO_Do_Or_Queue
(Self_ID
, New_Object
, Entry_Call
,
545 Entry_Call
.Requeue_With_Abort
);
546 PO_Service_Entries
(Self_ID
, New_Object
);
547 Unlock_Entries
(New_Object
);
551 -- Requeue is to same protected object
553 -- ??? Try to compensate apparent failure of the
554 -- scheduler on some OS (e.g VxWorks) to give higher
555 -- priority tasks a chance to run (see CXD6002).
559 if Entry_Call
.Requeue_With_Abort
560 and then Entry_Call
.Cancellation_Attempted
562 -- If this is a requeue with abort and someone tried
563 -- to cancel this call, cancel it at this point.
565 Entry_Call
.State
:= Cancelled
;
569 if not Entry_Call
.Requeue_With_Abort
or else
570 Entry_Call
.Mode
/= Conditional_Call
572 E
:= Protected_Entry_Index
(Entry_Call
.E
);
574 (New_Object
.Entry_Queues
(E
), Entry_Call
);
575 Update_For_Queue_To_PO
(Entry_Call
,
576 Entry_Call
.Requeue_With_Abort
);
579 PO_Do_Or_Queue
(Self_ID
, New_Object
, Entry_Call
,
580 Entry_Call
.Requeue_With_Abort
);
590 end PO_Service_Entries
;
592 ---------------------
593 -- Protected_Count --
594 ---------------------
596 function Protected_Count
597 (Object
: Protection_Entries
'Class;
598 E
: Protected_Entry_Index
)
602 return Queuing
.Count_Waiting
(Object
.Entry_Queues
(E
));
605 --------------------------
606 -- Protected_Entry_Call --
607 --------------------------
609 -- Compiler interface only. Do not call from within the RTS.
618 -- X : protected_entry_index := 1;
619 -- B85b : communication_block;
620 -- _init_proc (B85b);
622 -- protected_entry_call (rTV!(r)._object'unchecked_access, X,
623 -- null_address, conditional_call, B85b, objectF => 0);
624 -- if cancelled (B85b) then
631 -- See also Cancel_Protected_Entry_Call for code expansion of asynchronous
634 -- The initial part of this procedure does not need to lock the the calling
635 -- task's ATCB, up to the point where the call record first may be queued
636 -- (PO_Do_Or_Queue), since before that no other task will have access to
639 -- If this is a call made inside of an abort deferred region, the call
640 -- should be never abortable.
642 -- If the call was not queued abortably, we need to wait until it is before
643 -- proceeding with the abortable part.
645 -- There are some heuristics here, just to save time for frequently
646 -- occurring cases. For example, we check Initially_Abortable to try to
647 -- avoid calling the procedure Wait_Until_Abortable, since the normal case
648 -- for async. entry calls is to be queued abortably.
650 -- Another heuristic uses the Block.Enqueued to try to avoid calling
651 -- Cancel_Protected_Entry_Call if the call can be served immediately.
653 procedure Protected_Entry_Call
654 (Object
: Protection_Entries_Access
;
655 E
: Protected_Entry_Index
;
656 Uninterpreted_Data
: System
.Address
;
658 Block
: out Communication_Block
)
660 Self_ID
: Task_ID
:= STPO
.Self
;
661 Entry_Call
: Entry_Call_Link
;
662 Initially_Abortable
: Boolean;
663 Ceiling_Violation
: Boolean;
667 (Debug
.Trace
(Self_ID
, "Protected_Entry_Call", 'P'));
669 if Runtime_Traces
then
670 Send_Trace_Info
(PO_Call
, Entry_Index
(E
));
673 if Self_ID
.ATC_Nesting_Level
= ATC_Level
'Last then
675 (Storage_Error
'Identity, "not enough ATC nesting levels");
678 Initialization
.Defer_Abort
(Self_ID
);
679 Lock_Entries
(Object
, Ceiling_Violation
);
681 if Ceiling_Violation
then
683 -- Failed ceiling check
685 Initialization
.Undefer_Abort
(Self_ID
);
689 Block
.Self
:= Self_ID
;
690 Self_ID
.ATC_Nesting_Level
:= Self_ID
.ATC_Nesting_Level
+ 1;
692 (Debug
.Trace
(Self_ID
, "PEC: entered ATC level: " &
693 ATC_Level
'Image (Self_ID
.ATC_Nesting_Level
), 'A'));
695 Self_ID
.Entry_Calls
(Self_ID
.ATC_Nesting_Level
)'Access;
696 Entry_Call
.Next
:= null;
697 Entry_Call
.Mode
:= Mode
;
698 Entry_Call
.Cancellation_Attempted
:= False;
700 if Self_ID
.Deferral_Level
> 1 then
701 Entry_Call
.State
:= Never_Abortable
;
703 Entry_Call
.State
:= Now_Abortable
;
706 Entry_Call
.E
:= Entry_Index
(E
);
707 Entry_Call
.Prio
:= STPO
.Get_Priority
(Self_ID
);
708 Entry_Call
.Uninterpreted_Data
:= Uninterpreted_Data
;
709 Entry_Call
.Called_PO
:= To_Address
(Object
);
710 Entry_Call
.Called_Task
:= null;
711 Entry_Call
.Exception_To_Raise
:= Ada
.Exceptions
.Null_Id
;
713 PO_Do_Or_Queue
(Self_ID
, Object
, Entry_Call
, With_Abort
=> True);
714 Initially_Abortable
:= Entry_Call
.State
= Now_Abortable
;
715 PO_Service_Entries
(Self_ID
, Object
);
717 Unlock_Entries
(Object
);
719 -- Try to prevent waiting later (in Cancel_Protected_Entry_Call)
720 -- for completed or cancelled calls. (This is a heuristic, only.)
722 if Entry_Call
.State
>= Done
then
724 -- Once State >= Done it will not change any more.
726 Self_ID
.ATC_Nesting_Level
:= Self_ID
.ATC_Nesting_Level
- 1;
728 (Debug
.Trace
(Self_ID
, "PEC: exited to ATC level: " &
729 ATC_Level
'Image (Self_ID
.ATC_Nesting_Level
), 'A'));
730 Block
.Enqueued
:= False;
731 Block
.Cancelled
:= Entry_Call
.State
= Cancelled
;
732 Initialization
.Undefer_Abort
(Self_ID
);
733 Entry_Calls
.Check_Exception
(Self_ID
, Entry_Call
);
737 -- In this case we cannot conclude anything,
738 -- since State can change concurrently.
742 -- Now for the general case.
744 if Mode
= Asynchronous_Call
then
746 -- Try to avoid an expensive call.
748 if not Initially_Abortable
then
751 Entry_Calls
.Wait_Until_Abortable
(Self_ID
, Entry_Call
);
754 Entry_Calls
.Wait_Until_Abortable
(Self_ID
, Entry_Call
);
758 elsif Mode
< Asynchronous_Call
then
760 -- Simple_Call or Conditional_Call
764 Entry_Calls
.Wait_For_Completion
(Entry_Call
);
767 STPO
.Write_Lock
(Self_ID
);
768 Entry_Calls
.Wait_For_Completion
(Entry_Call
);
769 STPO
.Unlock
(Self_ID
);
772 Block
.Cancelled
:= Entry_Call
.State
= Cancelled
;
775 pragma Assert
(False);
779 Initialization
.Undefer_Abort
(Self_ID
);
780 Entry_Calls
.Check_Exception
(Self_ID
, Entry_Call
);
781 end Protected_Entry_Call
;
783 ----------------------------
784 -- Protected_Entry_Caller --
785 ----------------------------
787 function Protected_Entry_Caller
788 (Object
: Protection_Entries
'Class) return Task_ID
is
790 return Object
.Call_In_Progress
.Self
;
791 end Protected_Entry_Caller
;
793 -----------------------------
794 -- Requeue_Protected_Entry --
795 -----------------------------
797 -- Compiler interface only. Do not call from within the RTS.
806 -- procedure rPT__E10b (O : address; P : address; E :
807 -- protected_entry_index) is
808 -- type rTVP is access rTV;
810 -- _object : rTVP := rTVP!(O);
813 -- rR : protection renames _object._object;
814 -- vP : integer renames _object.v;
815 -- bP : boolean renames _object.b;
819 -- requeue_protected_entry (rR'unchecked_access, rR'
820 -- unchecked_access, 2, false, objectF => 0, new_objectF =>
824 -- complete_entry_body (_object._object'unchecked_access, objectF =>
829 -- abort_undefer.all;
830 -- exceptional_complete_entry_body (_object._object'
831 -- unchecked_access, current_exception, objectF => 0);
835 procedure Requeue_Protected_Entry
836 (Object
: Protection_Entries_Access
;
837 New_Object
: Protection_Entries_Access
;
838 E
: Protected_Entry_Index
;
839 With_Abort
: Boolean)
841 Entry_Call
: constant Entry_Call_Link
:= Object
.Call_In_Progress
;
845 (Debug
.Trace
(STPO
.Self
, "Requeue_Protected_Entry", 'P'));
846 pragma Assert
(STPO
.Self
.Deferral_Level
> 0);
848 Entry_Call
.E
:= Entry_Index
(E
);
849 Entry_Call
.Called_PO
:= To_Address
(New_Object
);
850 Entry_Call
.Called_Task
:= null;
851 Entry_Call
.Requeue_With_Abort
:= With_Abort
;
852 Object
.Call_In_Progress
:= null;
853 end Requeue_Protected_Entry
;
855 -------------------------------------
856 -- Requeue_Task_To_Protected_Entry --
857 -------------------------------------
859 -- Compiler interface only.
869 -- accept_call (1, A79b);
871 -- requeue_task_to_protected_entry (rTV!(r)._object'
872 -- unchecked_access, 2, false, new_objectF => 0);
875 -- complete_rendezvous;
877 -- when all others =>
878 -- exceptional_complete_rendezvous (get_gnat_exception);
881 procedure Requeue_Task_To_Protected_Entry
882 (New_Object
: Protection_Entries_Access
;
883 E
: Protected_Entry_Index
;
884 With_Abort
: Boolean)
886 Self_ID
: constant Task_ID
:= STPO
.Self
;
887 Entry_Call
: constant Entry_Call_Link
:= Self_ID
.Common
.Call
;
890 Initialization
.Defer_Abort
(Self_ID
);
892 -- We do not need to lock Self_ID here since the call is not abortable
893 -- at this point, and therefore, the caller cannot cancel the call.
895 Entry_Call
.Needs_Requeue
:= True;
896 Entry_Call
.Requeue_With_Abort
:= With_Abort
;
897 Entry_Call
.Called_PO
:= To_Address
(New_Object
);
898 Entry_Call
.Called_Task
:= null;
899 Entry_Call
.E
:= Entry_Index
(E
);
900 Initialization
.Undefer_Abort
(Self_ID
);
901 end Requeue_Task_To_Protected_Entry
;
903 ---------------------
904 -- Service_Entries --
905 ---------------------
907 procedure Service_Entries
(Object
: Protection_Entries_Access
) is
908 Self_ID
: constant Task_ID
:= STPO
.Self
;
910 PO_Service_Entries
(Self_ID
, Object
);
913 --------------------------------
914 -- Timed_Protected_Entry_Call --
915 --------------------------------
917 -- Compiler interface only. Do not call from within the RTS.
919 procedure Timed_Protected_Entry_Call
920 (Object
: Protection_Entries_Access
;
921 E
: Protected_Entry_Index
;
922 Uninterpreted_Data
: System
.Address
;
925 Entry_Call_Successful
: out Boolean)
927 Self_Id
: constant Task_ID
:= STPO
.Self
;
928 Entry_Call
: Entry_Call_Link
;
929 Ceiling_Violation
: Boolean;
933 if Self_Id
.ATC_Nesting_Level
= ATC_Level
'Last then
934 Raise_Exception
(Storage_Error
'Identity,
935 "not enough ATC nesting levels");
938 if Runtime_Traces
then
939 Send_Trace_Info
(POT_Call
, Entry_Index
(E
), Timeout
);
942 Initialization
.Defer_Abort
(Self_Id
);
943 Lock_Entries
(Object
, Ceiling_Violation
);
945 if Ceiling_Violation
then
946 Initialization
.Undefer_Abort
(Self_Id
);
950 Self_Id
.ATC_Nesting_Level
:= Self_Id
.ATC_Nesting_Level
+ 1;
952 (Debug
.Trace
(Self_Id
, "TPEC: exited to ATC level: " &
953 ATC_Level
'Image (Self_Id
.ATC_Nesting_Level
), 'A'));
955 Self_Id
.Entry_Calls
(Self_Id
.ATC_Nesting_Level
)'Access;
956 Entry_Call
.Next
:= null;
957 Entry_Call
.Mode
:= Timed_Call
;
958 Entry_Call
.Cancellation_Attempted
:= False;
960 if Self_Id
.Deferral_Level
> 1 then
961 Entry_Call
.State
:= Never_Abortable
;
963 Entry_Call
.State
:= Now_Abortable
;
966 Entry_Call
.E
:= Entry_Index
(E
);
967 Entry_Call
.Prio
:= STPO
.Get_Priority
(Self_Id
);
968 Entry_Call
.Uninterpreted_Data
:= Uninterpreted_Data
;
969 Entry_Call
.Called_PO
:= To_Address
(Object
);
970 Entry_Call
.Called_Task
:= null;
971 Entry_Call
.Exception_To_Raise
:= Ada
.Exceptions
.Null_Id
;
973 PO_Do_Or_Queue
(Self_Id
, Object
, Entry_Call
, With_Abort
=> True);
974 PO_Service_Entries
(Self_Id
, Object
);
976 Unlock_Entries
(Object
);
978 -- Try to avoid waiting for completed or cancelled calls.
980 if Entry_Call
.State
>= Done
then
981 Self_Id
.ATC_Nesting_Level
:= Self_Id
.ATC_Nesting_Level
- 1;
983 (Debug
.Trace
(Self_Id
, "TPEC: exited to ATC level: " &
984 ATC_Level
'Image (Self_Id
.ATC_Nesting_Level
), 'A'));
985 Entry_Call_Successful
:= Entry_Call
.State
= Done
;
986 Initialization
.Undefer_Abort
(Self_Id
);
987 Entry_Calls
.Check_Exception
(Self_Id
, Entry_Call
);
994 STPO
.Write_Lock
(Self_Id
);
997 Entry_Calls
.Wait_For_Completion_With_Timeout
998 (Entry_Call
, Timeout
, Mode
, Yielded
);
1003 STPO
.Unlock
(Self_Id
);
1006 -- ??? Do we need to yield in case Yielded is False
1008 Initialization
.Undefer_Abort
(Self_Id
);
1009 Entry_Call_Successful
:= Entry_Call
.State
= Done
;
1010 Entry_Calls
.Check_Exception
(Self_Id
, Entry_Call
);
1011 end Timed_Protected_Entry_Call
;
1013 ----------------------------
1014 -- Update_For_Queue_To_PO --
1015 ----------------------------
1017 -- Update the state of an existing entry call, based on
1018 -- whether the current queuing action is with or without abort.
1019 -- Call this only while holding the server's lock.
1020 -- It returns with the server's lock released.
1022 New_State
: constant array (Boolean, Entry_Call_State
)
1023 of Entry_Call_State
:=
1025 (Never_Abortable
=> Never_Abortable
,
1026 Not_Yet_Abortable
=> Now_Abortable
,
1027 Was_Abortable
=> Now_Abortable
,
1028 Now_Abortable
=> Now_Abortable
,
1030 Cancelled
=> Cancelled
),
1032 (Never_Abortable
=> Never_Abortable
,
1033 Not_Yet_Abortable
=> Not_Yet_Abortable
,
1034 Was_Abortable
=> Was_Abortable
,
1035 Now_Abortable
=> Now_Abortable
,
1037 Cancelled
=> Cancelled
)
1040 procedure Update_For_Queue_To_PO
1041 (Entry_Call
: Entry_Call_Link
;
1042 With_Abort
: Boolean)
1044 Old
: Entry_Call_State
:= Entry_Call
.State
;
1046 pragma Assert
(Old
< Done
);
1048 Entry_Call
.State
:= New_State
(With_Abort
, Entry_Call
.State
);
1050 if Entry_Call
.Mode
= Asynchronous_Call
then
1051 if Old
< Was_Abortable
and then
1052 Entry_Call
.State
= Now_Abortable
1058 STPO
.Write_Lock
(Entry_Call
.Self
);
1060 if Entry_Call
.Self
.Common
.State
= Async_Select_Sleep
then
1061 STPO
.Wakeup
(Entry_Call
.Self
, Async_Select_Sleep
);
1064 STPO
.Unlock
(Entry_Call
.Self
);
1072 elsif Entry_Call
.Mode
= Conditional_Call
then
1073 pragma Assert
(Entry_Call
.State
< Was_Abortable
);
1076 end Update_For_Queue_To_PO
;
1078 end System
.Tasking
.Protected_Objects
.Operations
;