PR testsuite/79036 - gcc.dg/tree-ssa/builtin-sprintf.c fails starting with r244037
[official-gcc.git] / gcc / ada / s-tpobop.adb
blob3a884c5d8943ecdf4092c26ac4037b9d18c38b21
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- SYSTEM.TASKING.PROTECTED_OBJECTS.OPERATIONS --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1998-2016, Free Software Foundation, Inc. --
10 -- --
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 3, or (at your option) any later ver- --
14 -- sion. GNAT 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. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- GNARL was developed by the GNARL team at Florida State University. --
28 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 -- This package contains all extended primitives related to Protected_Objects
33 -- with entries.
35 -- The handling of protected objects with no entries is done in
36 -- System.Tasking.Protected_Objects, the simple routines for protected
37 -- objects with entries in System.Tasking.Protected_Objects.Entries.
39 -- The split between Entries and Operations is needed to break circular
40 -- dependencies inside the run time.
42 -- This package contains all primitives related to Protected_Objects.
43 -- Note: the compiler generates direct calls to this interface, via Rtsfind.
45 with System.Task_Primitives.Operations;
46 with System.Tasking.Entry_Calls;
47 with System.Tasking.Queuing;
48 with System.Tasking.Rendezvous;
49 with System.Tasking.Utilities;
50 with System.Tasking.Debug;
51 with System.Parameters;
52 with System.Traces.Tasking;
53 with System.Restrictions;
55 with System.Tasking.Initialization;
56 pragma Elaborate_All (System.Tasking.Initialization);
57 -- Insures that tasking is initialized if any protected objects are created
59 package body System.Tasking.Protected_Objects.Operations is
61 package STPO renames System.Task_Primitives.Operations;
63 use Parameters;
64 use Task_Primitives;
65 use Ada.Exceptions;
66 use Entries;
68 use System.Restrictions;
69 use System.Restrictions.Rident;
70 use System.Traces;
71 use System.Traces.Tasking;
73 -----------------------
74 -- Local Subprograms --
75 -----------------------
77 procedure Update_For_Queue_To_PO
78 (Entry_Call : Entry_Call_Link;
79 With_Abort : Boolean);
80 pragma Inline (Update_For_Queue_To_PO);
81 -- Update the state of an existing entry call to reflect the fact that it
82 -- is being enqueued, based on whether the current queuing action is with
83 -- or without abort. Call this only while holding the PO's lock. It returns
84 -- with the PO's lock still held.
86 procedure Requeue_Call
87 (Self_Id : Task_Id;
88 Object : Protection_Entries_Access;
89 Entry_Call : Entry_Call_Link);
90 -- Handle requeue of Entry_Call.
91 -- In particular, queue the call if needed, or service it immediately
92 -- if possible.
94 ---------------------------------
95 -- Cancel_Protected_Entry_Call --
96 ---------------------------------
98 -- Compiler interface only (do not call from within the RTS)
100 -- This should have analogous effect to Cancel_Task_Entry_Call, setting
101 -- the value of Block.Cancelled instead of returning the parameter value
102 -- Cancelled.
104 -- The effect should be idempotent, since the call may already have been
105 -- dequeued.
107 -- Source code:
109 -- select r.e;
110 -- ...A...
111 -- then abort
112 -- ...B...
113 -- end select;
115 -- Expanded code:
117 -- declare
118 -- X : protected_entry_index := 1;
119 -- B80b : communication_block;
120 -- communication_blockIP (B80b);
122 -- begin
123 -- begin
124 -- A79b : label
125 -- A79b : declare
126 -- procedure _clean is
127 -- begin
128 -- if enqueued (B80b) then
129 -- cancel_protected_entry_call (B80b);
130 -- end if;
131 -- return;
132 -- end _clean;
134 -- begin
135 -- protected_entry_call (rTV!(r)._object'unchecked_access, X,
136 -- null_address, asynchronous_call, B80b, objectF => 0);
137 -- if enqueued (B80b) then
138 -- ...B...
139 -- end if;
140 -- at end
141 -- _clean;
142 -- end A79b;
144 -- exception
145 -- when _abort_signal =>
146 -- abort_undefer.all;
147 -- null;
148 -- end;
150 -- if not cancelled (B80b) then
151 -- x := ...A...
152 -- end if;
153 -- end;
155 -- If the entry call completes after we get into the abortable part,
156 -- Abort_Signal should be raised and ATC will take us to the at-end
157 -- handler, which will call _clean.
159 -- If the entry call returns with the call already completed, we can skip
160 -- this, and use the "if enqueued()" to go past the at-end handler, but we
161 -- will still call _clean.
163 -- If the abortable part completes before the entry call is Done, it will
164 -- call _clean.
166 -- If the entry call or the abortable part raises an exception,
167 -- we will still call _clean, but the value of Cancelled should not matter.
169 -- Whoever calls _clean first gets to decide whether the call
170 -- has been "cancelled".
172 -- Enqueued should be true if there is any chance that the call is still on
173 -- a queue. It seems to be safe to make it True if the call was Onqueue at
174 -- some point before return from Protected_Entry_Call.
176 -- Cancelled should be true iff the abortable part completed
177 -- and succeeded in cancelling the entry call before it completed.
179 -- ?????
180 -- The need for Enqueued is less obvious. The "if enqueued ()" tests are
181 -- not necessary, since Cancel_Protected_Entry_Call/Protected_Entry_Call
182 -- must do the same test internally, with locking. The one that makes
183 -- cancellation conditional may be a useful heuristic since at least 1/2
184 -- the time the call should be off-queue by that point. The other one seems
185 -- totally useless, since Protected_Entry_Call must do the same check and
186 -- then possibly wait for the call to be abortable, internally.
188 -- We can check Call.State here without locking the caller's mutex,
189 -- since the call must be over after returning from Wait_For_Completion.
190 -- No other task can access the call record at this point.
192 procedure Cancel_Protected_Entry_Call
193 (Block : in out Communication_Block) is
194 begin
195 Entry_Calls.Try_To_Cancel_Entry_Call (Block.Cancelled);
196 end Cancel_Protected_Entry_Call;
198 ---------------
199 -- Cancelled --
200 ---------------
202 function Cancelled (Block : Communication_Block) return Boolean is
203 begin
204 return Block.Cancelled;
205 end Cancelled;
207 -------------------------
208 -- Complete_Entry_Body --
209 -------------------------
211 procedure Complete_Entry_Body (Object : Protection_Entries_Access) is
212 begin
213 Exceptional_Complete_Entry_Body (Object, Ada.Exceptions.Null_Id);
214 end Complete_Entry_Body;
216 --------------
217 -- Enqueued --
218 --------------
220 function Enqueued (Block : Communication_Block) return Boolean is
221 begin
222 return Block.Enqueued;
223 end Enqueued;
225 -------------------------------------
226 -- Exceptional_Complete_Entry_Body --
227 -------------------------------------
229 procedure Exceptional_Complete_Entry_Body
230 (Object : Protection_Entries_Access;
231 Ex : Ada.Exceptions.Exception_Id)
233 procedure Transfer_Occurrence
234 (Target : Ada.Exceptions.Exception_Occurrence_Access;
235 Source : Ada.Exceptions.Exception_Occurrence);
236 pragma Import (C, Transfer_Occurrence, "__gnat_transfer_occurrence");
238 Entry_Call : constant Entry_Call_Link := Object.Call_In_Progress;
239 Self_Id : Task_Id;
241 begin
242 pragma Debug
243 (Debug.Trace (STPO.Self, "Exceptional_Complete_Entry_Body", 'P'));
245 -- We must have abort deferred, since we are inside a protected
246 -- operation.
248 if Entry_Call /= null then
250 -- The call was not requeued
252 Entry_Call.Exception_To_Raise := Ex;
254 if Ex /= Ada.Exceptions.Null_Id then
256 -- An exception was raised and abort was deferred, so adjust
257 -- before propagating, otherwise the task will stay with deferral
258 -- enabled for its remaining life.
260 Self_Id := STPO.Self;
262 if not ZCX_By_Default then
263 Initialization.Undefer_Abort_Nestable (Self_Id);
264 end if;
266 Transfer_Occurrence
267 (Entry_Call.Self.Common.Compiler_Data.Current_Excep'Access,
268 Self_Id.Common.Compiler_Data.Current_Excep);
269 end if;
271 -- Wakeup_Entry_Caller will be called from PO_Do_Or_Queue or
272 -- PO_Service_Entries on return.
274 end if;
276 if Runtime_Traces then
278 -- ??? Entry_Call can be null
280 Send_Trace_Info (PO_Done, Entry_Call.Self);
281 end if;
282 end Exceptional_Complete_Entry_Body;
284 --------------------
285 -- PO_Do_Or_Queue --
286 --------------------
288 procedure PO_Do_Or_Queue
289 (Self_ID : Task_Id;
290 Object : Protection_Entries_Access;
291 Entry_Call : Entry_Call_Link)
293 E : constant Protected_Entry_Index :=
294 Protected_Entry_Index (Entry_Call.E);
295 Index : constant Protected_Entry_Index :=
296 Object.Find_Body_Index (Object.Compiler_Info, E);
297 Barrier_Value : Boolean;
298 Queue_Length : Natural;
299 begin
300 -- When the Action procedure for an entry body returns, it is either
301 -- completed (having called [Exceptional_]Complete_Entry_Body) or it
302 -- is queued, having executed a requeue statement.
304 Barrier_Value :=
305 Object.Entry_Bodies (Index).Barrier (Object.Compiler_Info, E);
307 if Barrier_Value then
309 -- Not abortable while service is in progress
311 if Entry_Call.State = Now_Abortable then
312 Entry_Call.State := Was_Abortable;
313 end if;
315 Object.Call_In_Progress := Entry_Call;
317 pragma Debug
318 (Debug.Trace (Self_ID, "PODOQ: start entry body", 'P'));
319 Object.Entry_Bodies (Index).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;
328 if Single_Lock then
329 STPO.Lock_RTS;
330 end if;
332 STPO.Write_Lock (Entry_Call.Self);
333 Initialization.Wakeup_Entry_Caller (Self_ID, Entry_Call, Done);
334 STPO.Unlock (Entry_Call.Self);
336 if Single_Lock then
337 STPO.Unlock_RTS;
338 end if;
340 else
341 Requeue_Call (Self_ID, Object, Entry_Call);
342 end if;
344 elsif Entry_Call.Mode /= Conditional_Call
345 or else not Entry_Call.With_Abort
346 then
347 if Run_Time_Restrictions.Set (Max_Entry_Queue_Length)
348 or else Object.Entry_Queue_Maxes /= null
349 then
350 -- Need to check the queue length. Computing the length is an
351 -- unusual case and is slow (need to walk the queue).
353 Queue_Length := Queuing.Count_Waiting (Object.Entry_Queues (E));
355 if (Run_Time_Restrictions.Set (Max_Entry_Queue_Length)
356 and then Queue_Length >=
357 Run_Time_Restrictions.Value (Max_Entry_Queue_Length))
358 or else
359 (Object.Entry_Queue_Maxes /= null
360 and then Object.Entry_Queue_Maxes (Index) /= 0
361 and then Queue_Length >= Object.Entry_Queue_Maxes (Index))
362 then
363 -- This violates the Max_Entry_Queue_Length restriction or the
364 -- Max_Queue_Length bound, raise Program_Error.
366 Entry_Call.Exception_To_Raise := Program_Error'Identity;
368 if Single_Lock then
369 STPO.Lock_RTS;
370 end if;
372 STPO.Write_Lock (Entry_Call.Self);
373 Initialization.Wakeup_Entry_Caller (Self_ID, Entry_Call, Done);
374 STPO.Unlock (Entry_Call.Self);
376 if Single_Lock then
377 STPO.Unlock_RTS;
378 end if;
380 return;
381 end if;
382 end if;
384 -- Do the work: queue the call
386 Queuing.Enqueue (Object.Entry_Queues (E), Entry_Call);
387 Update_For_Queue_To_PO (Entry_Call, Entry_Call.With_Abort);
389 return;
390 else
391 -- Conditional_Call and With_Abort
393 if Single_Lock then
394 STPO.Lock_RTS;
395 end if;
397 STPO.Write_Lock (Entry_Call.Self);
398 pragma Assert (Entry_Call.State /= Not_Yet_Abortable);
399 Initialization.Wakeup_Entry_Caller (Self_ID, Entry_Call, Cancelled);
400 STPO.Unlock (Entry_Call.Self);
402 if Single_Lock then
403 STPO.Unlock_RTS;
404 end if;
405 end if;
407 exception
408 when others =>
409 Queuing.Broadcast_Program_Error (Self_ID, Object, Entry_Call);
410 end PO_Do_Or_Queue;
412 ------------------------
413 -- PO_Service_Entries --
414 ------------------------
416 procedure PO_Service_Entries
417 (Self_ID : Task_Id;
418 Object : Entries.Protection_Entries_Access;
419 Unlock_Object : Boolean := True)
421 E : Protected_Entry_Index;
422 Caller : Task_Id;
423 Entry_Call : Entry_Call_Link;
425 begin
426 loop
427 Queuing.Select_Protected_Entry_Call (Self_ID, Object, Entry_Call);
429 exit when Entry_Call = null;
431 E := Protected_Entry_Index (Entry_Call.E);
433 -- Not abortable while service is in progress
435 if Entry_Call.State = Now_Abortable then
436 Entry_Call.State := Was_Abortable;
437 end if;
439 Object.Call_In_Progress := Entry_Call;
441 begin
442 if Runtime_Traces then
443 Send_Trace_Info (PO_Run, Self_ID,
444 Entry_Call.Self, Entry_Index (E));
445 end if;
447 pragma Debug
448 (Debug.Trace (Self_ID, "POSE: start entry body", 'P'));
450 Object.Entry_Bodies
451 (Object.Find_Body_Index (Object.Compiler_Info, E)).Action
452 (Object.Compiler_Info, Entry_Call.Uninterpreted_Data, E);
454 exception
455 when others =>
456 Queuing.Broadcast_Program_Error
457 (Self_ID, Object, Entry_Call);
458 end;
460 if Object.Call_In_Progress = null then
461 Requeue_Call (Self_ID, Object, Entry_Call);
462 exit when Entry_Call.State = Cancelled;
464 else
465 Object.Call_In_Progress := null;
466 Caller := Entry_Call.Self;
468 if Single_Lock then
469 STPO.Lock_RTS;
470 end if;
472 STPO.Write_Lock (Caller);
473 Initialization.Wakeup_Entry_Caller (Self_ID, Entry_Call, Done);
474 STPO.Unlock (Caller);
476 if Single_Lock then
477 STPO.Unlock_RTS;
478 end if;
479 end if;
480 end loop;
482 if Unlock_Object then
483 Unlock_Entries (Object);
484 end if;
485 end PO_Service_Entries;
487 ---------------------
488 -- Protected_Count --
489 ---------------------
491 function Protected_Count
492 (Object : Protection_Entries'Class;
493 E : Protected_Entry_Index) return Natural
495 begin
496 return Queuing.Count_Waiting (Object.Entry_Queues (E));
497 end Protected_Count;
499 --------------------------
500 -- Protected_Entry_Call --
501 --------------------------
503 -- Compiler interface only (do not call from within the RTS)
505 -- select r.e;
506 -- ...A...
507 -- else
508 -- ...B...
509 -- end select;
511 -- declare
512 -- X : protected_entry_index := 1;
513 -- B85b : communication_block;
514 -- communication_blockIP (B85b);
516 -- begin
517 -- protected_entry_call (rTV!(r)._object'unchecked_access, X,
518 -- null_address, conditional_call, B85b, objectF => 0);
520 -- if cancelled (B85b) then
521 -- ...B...
522 -- else
523 -- ...A...
524 -- end if;
525 -- end;
527 -- See also Cancel_Protected_Entry_Call for code expansion of asynchronous
528 -- entry call.
530 -- The initial part of this procedure does not need to lock the calling
531 -- task's ATCB, up to the point where the call record first may be queued
532 -- (PO_Do_Or_Queue), since before that no other task will have access to
533 -- the record.
535 -- If this is a call made inside of an abort deferred region, the call
536 -- should be never abortable.
538 -- If the call was not queued abortably, we need to wait until it is before
539 -- proceeding with the abortable part.
541 -- There are some heuristics here, just to save time for frequently
542 -- occurring cases. For example, we check Initially_Abortable to try to
543 -- avoid calling the procedure Wait_Until_Abortable, since the normal case
544 -- for async. entry calls is to be queued abortably.
546 -- Another heuristic uses the Block.Enqueued to try to avoid calling
547 -- Cancel_Protected_Entry_Call if the call can be served immediately.
549 procedure Protected_Entry_Call
550 (Object : Protection_Entries_Access;
551 E : Protected_Entry_Index;
552 Uninterpreted_Data : System.Address;
553 Mode : Call_Modes;
554 Block : out Communication_Block)
556 Self_ID : constant Task_Id := STPO.Self;
557 Entry_Call : Entry_Call_Link;
558 Initially_Abortable : Boolean;
559 Ceiling_Violation : Boolean;
561 begin
562 pragma Debug
563 (Debug.Trace (Self_ID, "Protected_Entry_Call", 'P'));
565 if Runtime_Traces then
566 Send_Trace_Info (PO_Call, Entry_Index (E));
567 end if;
569 if Self_ID.ATC_Nesting_Level = ATC_Level'Last then
570 raise Storage_Error with "not enough ATC nesting levels";
571 end if;
573 -- If pragma Detect_Blocking is active then Program_Error must be
574 -- raised if this potentially blocking operation is called from a
575 -- protected action.
577 if Detect_Blocking
578 and then Self_ID.Common.Protected_Action_Nesting > 0
579 then
580 raise Program_Error with "potentially blocking operation";
581 end if;
583 -- Self_ID.Deferral_Level should be 0, except when called from Finalize,
584 -- where abort is already deferred.
586 Initialization.Defer_Abort_Nestable (Self_ID);
587 Lock_Entries_With_Status (Object, Ceiling_Violation);
589 if Ceiling_Violation then
591 -- Failed ceiling check
593 Initialization.Undefer_Abort_Nestable (Self_ID);
594 raise Program_Error;
595 end if;
597 Block.Self := Self_ID;
598 Self_ID.ATC_Nesting_Level := Self_ID.ATC_Nesting_Level + 1;
599 pragma Debug
600 (Debug.Trace (Self_ID, "PEC: entered ATC level: " &
601 ATC_Level'Image (Self_ID.ATC_Nesting_Level), 'A'));
602 Entry_Call :=
603 Self_ID.Entry_Calls (Self_ID.ATC_Nesting_Level)'Access;
604 Entry_Call.Next := null;
605 Entry_Call.Mode := Mode;
606 Entry_Call.Cancellation_Attempted := False;
608 Entry_Call.State :=
609 (if Self_ID.Deferral_Level > 1
610 then Never_Abortable else Now_Abortable);
612 Entry_Call.E := Entry_Index (E);
613 Entry_Call.Prio := STPO.Get_Priority (Self_ID);
614 Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
615 Entry_Call.Called_PO := To_Address (Object);
616 Entry_Call.Called_Task := null;
617 Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;
618 Entry_Call.With_Abort := True;
620 PO_Do_Or_Queue (Self_ID, Object, Entry_Call);
621 Initially_Abortable := Entry_Call.State = Now_Abortable;
622 PO_Service_Entries (Self_ID, Object);
624 -- Try to prevent waiting later (in Try_To_Cancel_Protected_Entry_Call)
625 -- for completed or cancelled calls. (This is a heuristic, only.)
627 if Entry_Call.State >= Done then
629 -- Once State >= Done it will not change any more
631 if Single_Lock then
632 STPO.Lock_RTS;
633 end if;
635 STPO.Write_Lock (Self_ID);
636 Utilities.Exit_One_ATC_Level (Self_ID);
637 STPO.Unlock (Self_ID);
639 if Single_Lock then
640 STPO.Unlock_RTS;
641 end if;
643 Block.Enqueued := False;
644 Block.Cancelled := Entry_Call.State = Cancelled;
645 Initialization.Undefer_Abort_Nestable (Self_ID);
646 Entry_Calls.Check_Exception (Self_ID, Entry_Call);
647 return;
649 else
650 -- In this case we cannot conclude anything, since State can change
651 -- concurrently.
653 null;
654 end if;
656 -- Now for the general case
658 if Mode = Asynchronous_Call then
660 -- Try to avoid an expensive call
662 if not Initially_Abortable then
663 if Single_Lock then
664 STPO.Lock_RTS;
665 Entry_Calls.Wait_Until_Abortable (Self_ID, Entry_Call);
666 STPO.Unlock_RTS;
667 else
668 Entry_Calls.Wait_Until_Abortable (Self_ID, Entry_Call);
669 end if;
670 end if;
672 else
673 case Mode is
674 when Simple_Call | Conditional_Call =>
675 if Single_Lock then
676 STPO.Lock_RTS;
677 Entry_Calls.Wait_For_Completion (Entry_Call);
678 STPO.Unlock_RTS;
680 else
681 STPO.Write_Lock (Self_ID);
682 Entry_Calls.Wait_For_Completion (Entry_Call);
683 STPO.Unlock (Self_ID);
684 end if;
686 Block.Cancelled := Entry_Call.State = Cancelled;
688 when Asynchronous_Call | Timed_Call =>
689 pragma Assert (False);
690 null;
691 end case;
692 end if;
694 Initialization.Undefer_Abort_Nestable (Self_ID);
695 Entry_Calls.Check_Exception (Self_ID, Entry_Call);
696 end Protected_Entry_Call;
698 ------------------
699 -- Requeue_Call --
700 ------------------
702 procedure Requeue_Call
703 (Self_Id : Task_Id;
704 Object : Protection_Entries_Access;
705 Entry_Call : Entry_Call_Link)
707 New_Object : Protection_Entries_Access;
708 Ceiling_Violation : Boolean;
709 Result : Boolean;
710 E : Protected_Entry_Index;
712 begin
713 New_Object := To_Protection (Entry_Call.Called_PO);
715 if New_Object = null then
717 -- Call is to be requeued to a task entry
719 if Single_Lock then
720 STPO.Lock_RTS;
721 end if;
723 Result := Rendezvous.Task_Do_Or_Queue (Self_Id, Entry_Call);
725 if not Result then
726 Queuing.Broadcast_Program_Error
727 (Self_Id, Object, Entry_Call, RTS_Locked => True);
728 end if;
730 if Single_Lock then
731 STPO.Unlock_RTS;
732 end if;
734 else
735 -- Call should be requeued to a PO
737 if Object /= New_Object then
739 -- Requeue is to different PO
741 Lock_Entries_With_Status (New_Object, Ceiling_Violation);
743 if Ceiling_Violation then
744 Object.Call_In_Progress := null;
745 Queuing.Broadcast_Program_Error (Self_Id, Object, Entry_Call);
747 else
748 PO_Do_Or_Queue (Self_Id, New_Object, Entry_Call);
749 PO_Service_Entries (Self_Id, New_Object);
750 end if;
752 else
753 -- Requeue is to same protected object
755 -- ??? Try to compensate apparent failure of the scheduler on some
756 -- OS (e.g VxWorks) to give higher priority tasks a chance to run
757 -- (see CXD6002).
759 STPO.Yield (Do_Yield => False);
761 if Entry_Call.With_Abort
762 and then Entry_Call.Cancellation_Attempted
763 then
764 -- If this is a requeue with abort and someone tried to cancel
765 -- this call, cancel it at this point.
767 Entry_Call.State := Cancelled;
768 return;
769 end if;
771 if not Entry_Call.With_Abort
772 or else Entry_Call.Mode /= Conditional_Call
773 then
774 E := Protected_Entry_Index (Entry_Call.E);
776 if Run_Time_Restrictions.Set (Max_Entry_Queue_Length)
777 and then
778 Run_Time_Restrictions.Value (Max_Entry_Queue_Length) <=
779 Queuing.Count_Waiting (Object.Entry_Queues (E))
780 then
781 -- This violates the Max_Entry_Queue_Length restriction,
782 -- raise Program_Error.
784 Entry_Call.Exception_To_Raise := Program_Error'Identity;
786 if Single_Lock then
787 STPO.Lock_RTS;
788 end if;
790 STPO.Write_Lock (Entry_Call.Self);
791 Initialization.Wakeup_Entry_Caller
792 (Self_Id, Entry_Call, Done);
793 STPO.Unlock (Entry_Call.Self);
795 if Single_Lock then
796 STPO.Unlock_RTS;
797 end if;
799 else
800 Queuing.Enqueue
801 (New_Object.Entry_Queues (E), Entry_Call);
802 Update_For_Queue_To_PO (Entry_Call, Entry_Call.With_Abort);
803 end if;
805 else
806 PO_Do_Or_Queue (Self_Id, New_Object, Entry_Call);
807 end if;
808 end if;
809 end if;
810 end Requeue_Call;
812 ----------------------------
813 -- Protected_Entry_Caller --
814 ----------------------------
816 function Protected_Entry_Caller
817 (Object : Protection_Entries'Class) return Task_Id is
818 begin
819 return Object.Call_In_Progress.Self;
820 end Protected_Entry_Caller;
822 -----------------------------
823 -- Requeue_Protected_Entry --
824 -----------------------------
826 -- Compiler interface only (do not call from within the RTS)
828 -- entry e when b is
829 -- begin
830 -- b := false;
831 -- ...A...
832 -- requeue e2;
833 -- end e;
835 -- procedure rPT__E10b (O : address; P : address; E :
836 -- protected_entry_index) is
837 -- type rTVP is access rTV;
838 -- freeze rTVP []
839 -- _object : rTVP := rTVP!(O);
840 -- begin
841 -- declare
842 -- rR : protection renames _object._object;
843 -- vP : integer renames _object.v;
844 -- bP : boolean renames _object.b;
845 -- begin
846 -- b := false;
847 -- ...A...
848 -- requeue_protected_entry (rR'unchecked_access, rR'
849 -- unchecked_access, 2, false, objectF => 0, new_objectF =>
850 -- 0);
851 -- return;
852 -- end;
853 -- complete_entry_body (_object._object'unchecked_access, objectF =>
854 -- 0);
855 -- return;
856 -- exception
857 -- when others =>
858 -- abort_undefer.all;
859 -- exceptional_complete_entry_body (_object._object'
860 -- unchecked_access, current_exception, objectF => 0);
861 -- return;
862 -- end rPT__E10b;
864 procedure Requeue_Protected_Entry
865 (Object : Protection_Entries_Access;
866 New_Object : Protection_Entries_Access;
867 E : Protected_Entry_Index;
868 With_Abort : Boolean)
870 Entry_Call : constant Entry_Call_Link := Object.Call_In_Progress;
872 begin
873 pragma Debug
874 (Debug.Trace (STPO.Self, "Requeue_Protected_Entry", 'P'));
875 pragma Assert (STPO.Self.Deferral_Level > 0);
877 Entry_Call.E := Entry_Index (E);
878 Entry_Call.Called_PO := To_Address (New_Object);
879 Entry_Call.Called_Task := null;
880 Entry_Call.With_Abort := With_Abort;
881 Object.Call_In_Progress := null;
882 end Requeue_Protected_Entry;
884 -------------------------------------
885 -- Requeue_Task_To_Protected_Entry --
886 -------------------------------------
888 -- Compiler interface only (do not call from within the RTS)
890 -- accept e1 do
891 -- ...A...
892 -- requeue r.e2;
893 -- end e1;
895 -- A79b : address;
896 -- L78b : label
898 -- begin
899 -- accept_call (1, A79b);
900 -- ...A...
901 -- requeue_task_to_protected_entry (rTV!(r)._object'
902 -- unchecked_access, 2, false, new_objectF => 0);
903 -- goto L78b;
904 -- <<L78b>>
905 -- complete_rendezvous;
907 -- exception
908 -- when all others =>
909 -- exceptional_complete_rendezvous (get_gnat_exception);
910 -- end;
912 procedure Requeue_Task_To_Protected_Entry
913 (New_Object : Protection_Entries_Access;
914 E : Protected_Entry_Index;
915 With_Abort : Boolean)
917 Self_ID : constant Task_Id := STPO.Self;
918 Entry_Call : constant Entry_Call_Link := Self_ID.Common.Call;
920 begin
921 Initialization.Defer_Abort (Self_ID);
923 -- We do not need to lock Self_ID here since the call is not abortable
924 -- at this point, and therefore, the caller cannot cancel the call.
926 Entry_Call.Needs_Requeue := True;
927 Entry_Call.With_Abort := With_Abort;
928 Entry_Call.Called_PO := To_Address (New_Object);
929 Entry_Call.Called_Task := null;
930 Entry_Call.E := Entry_Index (E);
931 Initialization.Undefer_Abort (Self_ID);
932 end Requeue_Task_To_Protected_Entry;
934 ---------------------
935 -- Service_Entries --
936 ---------------------
938 procedure Service_Entries (Object : Protection_Entries_Access) is
939 Self_ID : constant Task_Id := STPO.Self;
940 begin
941 PO_Service_Entries (Self_ID, Object);
942 end Service_Entries;
944 --------------------------------
945 -- Timed_Protected_Entry_Call --
946 --------------------------------
948 -- Compiler interface only (do not call from within the RTS)
950 procedure Timed_Protected_Entry_Call
951 (Object : Protection_Entries_Access;
952 E : Protected_Entry_Index;
953 Uninterpreted_Data : System.Address;
954 Timeout : Duration;
955 Mode : Delay_Modes;
956 Entry_Call_Successful : out Boolean)
958 Self_Id : constant Task_Id := STPO.Self;
959 Entry_Call : Entry_Call_Link;
960 Ceiling_Violation : Boolean;
962 Yielded : Boolean;
963 pragma Unreferenced (Yielded);
965 begin
966 if Self_Id.ATC_Nesting_Level = ATC_Level'Last then
967 raise Storage_Error with "not enough ATC nesting levels";
968 end if;
970 -- If pragma Detect_Blocking is active then Program_Error must be
971 -- raised if this potentially blocking operation is called from a
972 -- protected action.
974 if Detect_Blocking
975 and then Self_Id.Common.Protected_Action_Nesting > 0
976 then
977 raise Program_Error with "potentially blocking operation";
978 end if;
980 if Runtime_Traces then
981 Send_Trace_Info (POT_Call, Entry_Index (E), Timeout);
982 end if;
984 Initialization.Defer_Abort_Nestable (Self_Id);
985 Lock_Entries_With_Status (Object, Ceiling_Violation);
987 if Ceiling_Violation then
988 Initialization.Undefer_Abort (Self_Id);
989 raise Program_Error;
990 end if;
992 Self_Id.ATC_Nesting_Level := Self_Id.ATC_Nesting_Level + 1;
993 pragma Debug
994 (Debug.Trace (Self_Id, "TPEC: exited to ATC level: " &
995 ATC_Level'Image (Self_Id.ATC_Nesting_Level), 'A'));
996 Entry_Call := 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 Entry_Call.State :=
1002 (if Self_Id.Deferral_Level > 1
1003 then Never_Abortable
1004 else Now_Abortable);
1006 Entry_Call.E := Entry_Index (E);
1007 Entry_Call.Prio := STPO.Get_Priority (Self_Id);
1008 Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
1009 Entry_Call.Called_PO := To_Address (Object);
1010 Entry_Call.Called_Task := null;
1011 Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;
1012 Entry_Call.With_Abort := True;
1014 PO_Do_Or_Queue (Self_Id, Object, Entry_Call);
1015 PO_Service_Entries (Self_Id, Object);
1017 if Single_Lock then
1018 STPO.Lock_RTS;
1019 else
1020 STPO.Write_Lock (Self_Id);
1021 end if;
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);
1028 if Single_Lock then
1029 STPO.Unlock_RTS;
1030 else
1031 STPO.Unlock (Self_Id);
1032 end if;
1034 Entry_Call_Successful := Entry_Call.State = Done;
1035 Initialization.Undefer_Abort_Nestable (Self_Id);
1036 Entry_Calls.Check_Exception (Self_Id, Entry_Call);
1037 return;
1038 end if;
1040 Entry_Calls.Wait_For_Completion_With_Timeout
1041 (Entry_Call, Timeout, Mode, Yielded);
1043 if Single_Lock then
1044 STPO.Unlock_RTS;
1045 else
1046 STPO.Unlock (Self_Id);
1047 end if;
1049 -- ??? Do we need to yield in case Yielded is False
1051 Initialization.Undefer_Abort_Nestable (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 :=
1067 (True =>
1068 (Never_Abortable => Never_Abortable,
1069 Not_Yet_Abortable => Now_Abortable,
1070 Was_Abortable => Now_Abortable,
1071 Now_Abortable => Now_Abortable,
1072 Done => Done,
1073 Cancelled => Cancelled),
1074 False =>
1075 (Never_Abortable => Never_Abortable,
1076 Not_Yet_Abortable => Not_Yet_Abortable,
1077 Was_Abortable => Was_Abortable,
1078 Now_Abortable => Now_Abortable,
1079 Done => Done,
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;
1089 begin
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
1097 then
1098 if Single_Lock then
1099 STPO.Lock_RTS;
1100 end if;
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);
1106 end if;
1108 STPO.Unlock (Entry_Call.Self);
1110 if Single_Lock then
1111 STPO.Unlock_RTS;
1112 end if;
1114 end if;
1116 elsif Entry_Call.Mode = Conditional_Call then
1117 pragma Assert (Entry_Call.State < Was_Abortable);
1118 null;
1119 end if;
1120 end Update_For_Queue_To_PO;
1122 end System.Tasking.Protected_Objects.Operations;