aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.4.3/gcc/ada/s-tpobop.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.4.3/gcc/ada/s-tpobop.adb')
-rw-r--r--gcc-4.4.3/gcc/ada/s-tpobop.adb1103
1 files changed, 0 insertions, 1103 deletions
diff --git a/gcc-4.4.3/gcc/ada/s-tpobop.adb b/gcc-4.4.3/gcc/ada/s-tpobop.adb
deleted file mode 100644
index 06102daf6..000000000
--- a/gcc-4.4.3/gcc/ada/s-tpobop.adb
+++ /dev/null
@@ -1,1103 +0,0 @@
-------------------------------------------------------------------------------
--- --
--- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
--- --
--- SYSTEM.TASKING.PROTECTED_OBJECTS.OPERATIONS --
--- --
--- B o d y --
--- --
--- Copyright (C) 1998-2009, Free Software Foundation, Inc. --
--- --
--- GNARL is free software; you can redistribute it and/or modify it under --
--- terms of the GNU General Public License as published by the Free Soft- --
--- ware Foundation; either version 3, or (at your option) any later ver- --
--- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
--- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
--- or FITNESS FOR A PARTICULAR PURPOSE. --
--- --
--- As a special exception under Section 7 of GPL version 3, you are granted --
--- additional permissions described in the GCC Runtime Library Exception, --
--- version 3.1, as published by the Free Software Foundation. --
--- --
--- You should have received a copy of the GNU General Public License and --
--- a copy of the GCC Runtime Library Exception along with this program; --
--- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
--- <http://www.gnu.org/licenses/>. --
--- --
--- GNARL was developed by the GNARL team at Florida State University. --
--- Extensive contributions were provided by Ada Core Technologies, Inc. --
--- --
-------------------------------------------------------------------------------
-
--- This package contains all extended primitives related to Protected_Objects
--- with entries.
-
--- The handling of protected objects with no entries is done in
--- System.Tasking.Protected_Objects, the simple routines for protected
--- objects with entries in System.Tasking.Protected_Objects.Entries.
-
--- The split between Entries and Operations is needed to break circular
--- dependencies inside the run time.
-
--- This package contains all primitives related to Protected_Objects.
--- Note: the compiler generates direct calls to this interface, via Rtsfind.
-
-with System.Task_Primitives.Operations;
-with System.Tasking.Entry_Calls;
-with System.Tasking.Queuing;
-with System.Tasking.Rendezvous;
-with System.Tasking.Utilities;
-with System.Tasking.Debug;
-with System.Parameters;
-with System.Traces.Tasking;
-with System.Restrictions;
-
-with System.Tasking.Initialization;
-pragma Elaborate_All (System.Tasking.Initialization);
--- Insures that tasking is initialized if any protected objects are created
-
-package body System.Tasking.Protected_Objects.Operations is
-
- package STPO renames System.Task_Primitives.Operations;
-
- use Parameters;
- use Task_Primitives;
- use Ada.Exceptions;
- use Entries;
-
- use System.Restrictions;
- use System.Restrictions.Rident;
- use System.Traces;
- use System.Traces.Tasking;
-
- -----------------------
- -- Local Subprograms --
- -----------------------
-
- procedure Update_For_Queue_To_PO
- (Entry_Call : Entry_Call_Link;
- With_Abort : Boolean);
- pragma Inline (Update_For_Queue_To_PO);
- -- Update the state of an existing entry call to reflect the fact that it
- -- is being enqueued, based on whether the current queuing action is with
- -- or without abort. Call this only while holding the PO's lock. It returns
- -- with the PO's lock still held.
-
- procedure Requeue_Call
- (Self_Id : Task_Id;
- Object : Protection_Entries_Access;
- Entry_Call : Entry_Call_Link);
- -- Handle requeue of Entry_Call.
- -- In particular, queue the call if needed, or service it immediately
- -- if possible.
-
- ---------------------------------
- -- Cancel_Protected_Entry_Call --
- ---------------------------------
-
- -- Compiler interface only (do not call from within the RTS)
-
- -- This should have analogous effect to Cancel_Task_Entry_Call, setting
- -- the value of Block.Cancelled instead of returning the parameter value
- -- Cancelled.
-
- -- The effect should be idempotent, since the call may already have been
- -- dequeued.
-
- -- Source code:
-
- -- select r.e;
- -- ...A...
- -- then abort
- -- ...B...
- -- end select;
-
- -- Expanded code:
-
- -- declare
- -- X : protected_entry_index := 1;
- -- B80b : communication_block;
- -- communication_blockIP (B80b);
-
- -- begin
- -- begin
- -- A79b : label
- -- A79b : declare
- -- procedure _clean is
- -- begin
- -- if enqueued (B80b) then
- -- cancel_protected_entry_call (B80b);
- -- end if;
- -- return;
- -- end _clean;
-
- -- begin
- -- protected_entry_call (rTV!(r)._object'unchecked_access, X,
- -- null_address, asynchronous_call, B80b, objectF => 0);
- -- if enqueued (B80b) then
- -- ...B...
- -- end if;
- -- at end
- -- _clean;
- -- end A79b;
-
- -- exception
- -- when _abort_signal =>
- -- abort_undefer.all;
- -- null;
- -- end;
-
- -- if not cancelled (B80b) then
- -- x := ...A...
- -- end if;
- -- end;
-
- -- If the entry call completes after we get into the abortable part,
- -- Abort_Signal should be raised and ATC will take us to the at-end
- -- handler, which will call _clean.
-
- -- If the entry call returns with the call already completed, we can skip
- -- this, and use the "if enqueued()" to go past the at-end handler, but we
- -- will still call _clean.
-
- -- If the abortable part completes before the entry call is Done, it will
- -- call _clean.
-
- -- If the entry call or the abortable part raises an exception,
- -- we will still call _clean, but the value of Cancelled should not matter.
-
- -- Whoever calls _clean first gets to decide whether the call
- -- has been "cancelled".
-
- -- Enqueued should be true if there is any chance that the call is still on
- -- a queue. It seems to be safe to make it True if the call was Onqueue at
- -- some point before return from Protected_Entry_Call.
-
- -- Cancelled should be true iff the abortable part completed
- -- and succeeded in cancelling the entry call before it completed.
-
- -- ?????
- -- The need for Enqueued is less obvious. The "if enqueued ()" tests are
- -- not necessary, since Cancel_Protected_Entry_Call/Protected_Entry_Call
- -- must do the same test internally, with locking. The one that makes
- -- cancellation conditional may be a useful heuristic since at least 1/2
- -- the time the call should be off-queue by that point. The other one seems
- -- totally useless, since Protected_Entry_Call must do the same check and
- -- then possibly wait for the call to be abortable, internally.
-
- -- We can check Call.State here without locking the caller's mutex,
- -- since the call must be over after returning from Wait_For_Completion.
- -- No other task can access the call record at this point.
-
- procedure Cancel_Protected_Entry_Call
- (Block : in out Communication_Block) is
- begin
- Entry_Calls.Try_To_Cancel_Entry_Call (Block.Cancelled);
- end Cancel_Protected_Entry_Call;
-
- ---------------
- -- Cancelled --
- ---------------
-
- function Cancelled (Block : Communication_Block) return Boolean is
- begin
- return Block.Cancelled;
- end Cancelled;
-
- -------------------------
- -- Complete_Entry_Body --
- -------------------------
-
- procedure Complete_Entry_Body (Object : Protection_Entries_Access) is
- begin
- Exceptional_Complete_Entry_Body (Object, Ada.Exceptions.Null_Id);
- end Complete_Entry_Body;
-
- --------------
- -- Enqueued --
- --------------
-
- function Enqueued (Block : Communication_Block) return Boolean is
- begin
- return Block.Enqueued;
- end Enqueued;
-
- -------------------------------------
- -- Exceptional_Complete_Entry_Body --
- -------------------------------------
-
- procedure Exceptional_Complete_Entry_Body
- (Object : Protection_Entries_Access;
- Ex : Ada.Exceptions.Exception_Id)
- is
- procedure Transfer_Occurrence
- (Target : Ada.Exceptions.Exception_Occurrence_Access;
- Source : Ada.Exceptions.Exception_Occurrence);
- pragma Import (C, Transfer_Occurrence, "__gnat_transfer_occurrence");
-
- Entry_Call : constant Entry_Call_Link := Object.Call_In_Progress;
- Self_Id : Task_Id;
-
- begin
- pragma Debug
- (Debug.Trace (STPO.Self, "Exceptional_Complete_Entry_Body", 'P'));
-
- -- We must have abort deferred, since we are inside a protected
- -- operation.
-
- if Entry_Call /= null then
-
- -- The call was not requeued
-
- Entry_Call.Exception_To_Raise := Ex;
-
- if Ex /= Ada.Exceptions.Null_Id then
-
- -- An exception was raised and abort was deferred, so adjust
- -- before propagating, otherwise the task will stay with deferral
- -- enabled for its remaining life.
-
- Self_Id := STPO.Self;
- Initialization.Undefer_Abort_Nestable (Self_Id);
- Transfer_Occurrence
- (Entry_Call.Self.Common.Compiler_Data.Current_Excep'Access,
- Self_Id.Common.Compiler_Data.Current_Excep);
- end if;
-
- -- Wakeup_Entry_Caller will be called from PO_Do_Or_Queue or
- -- PO_Service_Entries on return.
-
- end if;
-
- if Runtime_Traces then
- Send_Trace_Info (PO_Done, Entry_Call.Self);
- end if;
- end Exceptional_Complete_Entry_Body;
-
- --------------------
- -- PO_Do_Or_Queue --
- --------------------
-
- procedure PO_Do_Or_Queue
- (Self_ID : Task_Id;
- Object : Protection_Entries_Access;
- Entry_Call : Entry_Call_Link)
- is
- E : constant Protected_Entry_Index :=
- Protected_Entry_Index (Entry_Call.E);
- Barrier_Value : Boolean;
-
- begin
- -- When the Action procedure for an entry body returns, it is either
- -- completed (having called [Exceptional_]Complete_Entry_Body) or it
- -- is queued, having executed a requeue statement.
-
- Barrier_Value :=
- Object.Entry_Bodies (
- Object.Find_Body_Index (Object.Compiler_Info, E)).
- Barrier (Object.Compiler_Info, E);
-
- if Barrier_Value then
-
- -- Not abortable while service is in progress
-
- if Entry_Call.State = Now_Abortable then
- Entry_Call.State := Was_Abortable;
- end if;
-
- Object.Call_In_Progress := Entry_Call;
-
- pragma Debug
- (Debug.Trace (Self_ID, "PODOQ: start entry body", 'P'));
- Object.Entry_Bodies (
- Object.Find_Body_Index (Object.Compiler_Info, E)).Action (
- Object.Compiler_Info, Entry_Call.Uninterpreted_Data, E);
-
- if Object.Call_In_Progress /= null then
-
- -- Body of current entry served call to completion
-
- Object.Call_In_Progress := null;
-
- if Single_Lock then
- STPO.Lock_RTS;
- end if;
-
- STPO.Write_Lock (Entry_Call.Self);
- Initialization.Wakeup_Entry_Caller (Self_ID, Entry_Call, Done);
- STPO.Unlock (Entry_Call.Self);
-
- if Single_Lock then
- STPO.Unlock_RTS;
- end if;
-
- else
- Requeue_Call (Self_ID, Object, Entry_Call);
- end if;
-
- elsif Entry_Call.Mode /= Conditional_Call
- or else not Entry_Call.With_Abort
- then
-
- if Run_Time_Restrictions.Set (Max_Entry_Queue_Length)
- and then
- Run_Time_Restrictions.Value (Max_Entry_Queue_Length) <=
- Queuing.Count_Waiting (Object.Entry_Queues (E))
- then
- -- This violates the Max_Entry_Queue_Length restriction,
- -- raise Program_Error.
-
- Entry_Call.Exception_To_Raise := Program_Error'Identity;
-
- if Single_Lock then
- STPO.Lock_RTS;
- end if;
-
- STPO.Write_Lock (Entry_Call.Self);
- Initialization.Wakeup_Entry_Caller (Self_ID, Entry_Call, Done);
- STPO.Unlock (Entry_Call.Self);
-
- if Single_Lock then
- STPO.Unlock_RTS;
- end if;
- else
- Queuing.Enqueue (Object.Entry_Queues (E), Entry_Call);
- Update_For_Queue_To_PO (Entry_Call, Entry_Call.With_Abort);
- end if;
- else
- -- Conditional_Call and With_Abort
-
- if Single_Lock then
- STPO.Lock_RTS;
- end if;
-
- STPO.Write_Lock (Entry_Call.Self);
- pragma Assert (Entry_Call.State >= Was_Abortable);
- Initialization.Wakeup_Entry_Caller (Self_ID, Entry_Call, Cancelled);
- STPO.Unlock (Entry_Call.Self);
-
- if Single_Lock then
- STPO.Unlock_RTS;
- end if;
- end if;
-
- exception
- when others =>
- Queuing.Broadcast_Program_Error (Self_ID, Object, Entry_Call);
- end PO_Do_Or_Queue;
-
- ------------------------
- -- PO_Service_Entries --
- ------------------------
-
- procedure PO_Service_Entries
- (Self_ID : Task_Id;
- Object : Entries.Protection_Entries_Access;
- Unlock_Object : Boolean := True)
- is
- E : Protected_Entry_Index;
- Caller : Task_Id;
- Entry_Call : Entry_Call_Link;
-
- begin
- loop
- Queuing.Select_Protected_Entry_Call (Self_ID, Object, Entry_Call);
-
- exit when Entry_Call = null;
-
- E := Protected_Entry_Index (Entry_Call.E);
-
- -- Not abortable while service is in progress
-
- if Entry_Call.State = Now_Abortable then
- Entry_Call.State := Was_Abortable;
- end if;
-
- Object.Call_In_Progress := Entry_Call;
-
- begin
- if Runtime_Traces then
- Send_Trace_Info (PO_Run, Self_ID,
- Entry_Call.Self, Entry_Index (E));
- end if;
-
- pragma Debug
- (Debug.Trace (Self_ID, "POSE: start entry body", 'P'));
-
- Object.Entry_Bodies
- (Object.Find_Body_Index (Object.Compiler_Info, E)).Action
- (Object.Compiler_Info, Entry_Call.Uninterpreted_Data, E);
-
- exception
- when others =>
- Queuing.Broadcast_Program_Error
- (Self_ID, Object, Entry_Call);
- end;
-
- if Object.Call_In_Progress = null then
- Requeue_Call (Self_ID, Object, Entry_Call);
- exit when Entry_Call.State = Cancelled;
-
- else
- Object.Call_In_Progress := null;
- Caller := Entry_Call.Self;
-
- if Single_Lock then
- STPO.Lock_RTS;
- end if;
-
- STPO.Write_Lock (Caller);
- Initialization.Wakeup_Entry_Caller (Self_ID, Entry_Call, Done);
- STPO.Unlock (Caller);
-
- if Single_Lock then
- STPO.Unlock_RTS;
- end if;
- end if;
- end loop;
-
- if Unlock_Object then
- Unlock_Entries (Object);
- end if;
- end PO_Service_Entries;
-
- ---------------------
- -- Protected_Count --
- ---------------------
-
- function Protected_Count
- (Object : Protection_Entries'Class;
- E : Protected_Entry_Index) return Natural
- is
- begin
- return Queuing.Count_Waiting (Object.Entry_Queues (E));
- end Protected_Count;
-
- --------------------------
- -- Protected_Entry_Call --
- --------------------------
-
- -- Compiler interface only (do not call from within the RTS)
-
- -- select r.e;
- -- ...A...
- -- else
- -- ...B...
- -- end select;
-
- -- declare
- -- X : protected_entry_index := 1;
- -- B85b : communication_block;
- -- communication_blockIP (B85b);
-
- -- begin
- -- protected_entry_call (rTV!(r)._object'unchecked_access, X,
- -- null_address, conditional_call, B85b, objectF => 0);
-
- -- if cancelled (B85b) then
- -- ...B...
- -- else
- -- ...A...
- -- end if;
- -- end;
-
- -- See also Cancel_Protected_Entry_Call for code expansion of asynchronous
- -- entry call.
-
- -- The initial part of this procedure does not need to lock the calling
- -- task's ATCB, up to the point where the call record first may be queued
- -- (PO_Do_Or_Queue), since before that no other task will have access to
- -- the record.
-
- -- If this is a call made inside of an abort deferred region, the call
- -- should be never abortable.
-
- -- If the call was not queued abortably, we need to wait until it is before
- -- proceeding with the abortable part.
-
- -- There are some heuristics here, just to save time for frequently
- -- occurring cases. For example, we check Initially_Abortable to try to
- -- avoid calling the procedure Wait_Until_Abortable, since the normal case
- -- for async. entry calls is to be queued abortably.
-
- -- Another heuristic uses the Block.Enqueued to try to avoid calling
- -- Cancel_Protected_Entry_Call if the call can be served immediately.
-
- procedure Protected_Entry_Call
- (Object : Protection_Entries_Access;
- E : Protected_Entry_Index;
- Uninterpreted_Data : System.Address;
- Mode : Call_Modes;
- Block : out Communication_Block)
- is
- Self_ID : constant Task_Id := STPO.Self;
- Entry_Call : Entry_Call_Link;
- Initially_Abortable : Boolean;
- Ceiling_Violation : Boolean;
-
- begin
- pragma Debug
- (Debug.Trace (Self_ID, "Protected_Entry_Call", 'P'));
-
- if Runtime_Traces then
- Send_Trace_Info (PO_Call, Entry_Index (E));
- end if;
-
- if Self_ID.ATC_Nesting_Level = ATC_Level'Last then
- raise Storage_Error with "not enough ATC nesting levels";
- end if;
-
- -- If pragma Detect_Blocking is active then Program_Error must be
- -- raised if this potentially blocking operation is called from a
- -- protected action.
-
- if Detect_Blocking
- and then Self_ID.Common.Protected_Action_Nesting > 0
- then
- raise Program_Error with "potentially blocking operation";
- end if;
-
- -- Self_ID.Deferral_Level should be 0, except when called from Finalize,
- -- where abort is already deferred.
-
- Initialization.Defer_Abort_Nestable (Self_ID);
- Lock_Entries (Object, Ceiling_Violation);
-
- if Ceiling_Violation then
-
- -- Failed ceiling check
-
- Initialization.Undefer_Abort_Nestable (Self_ID);
- raise Program_Error;
- end if;
-
- Block.Self := Self_ID;
- Self_ID.ATC_Nesting_Level := Self_ID.ATC_Nesting_Level + 1;
- pragma Debug
- (Debug.Trace (Self_ID, "PEC: entered ATC level: " &
- ATC_Level'Image (Self_ID.ATC_Nesting_Level), 'A'));
- Entry_Call :=
- Self_ID.Entry_Calls (Self_ID.ATC_Nesting_Level)'Access;
- Entry_Call.Next := null;
- Entry_Call.Mode := Mode;
- Entry_Call.Cancellation_Attempted := False;
-
- if Self_ID.Deferral_Level > 1 then
- Entry_Call.State := Never_Abortable;
- else
- Entry_Call.State := Now_Abortable;
- end if;
-
- Entry_Call.E := Entry_Index (E);
- Entry_Call.Prio := STPO.Get_Priority (Self_ID);
- Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
- Entry_Call.Called_PO := To_Address (Object);
- Entry_Call.Called_Task := null;
- Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;
- Entry_Call.With_Abort := True;
-
- PO_Do_Or_Queue (Self_ID, Object, Entry_Call);
- Initially_Abortable := Entry_Call.State = Now_Abortable;
- PO_Service_Entries (Self_ID, Object);
-
- -- Try to prevent waiting later (in Try_To_Cancel_Protected_Entry_Call)
- -- for completed or cancelled calls. (This is a heuristic, only.)
-
- if Entry_Call.State >= Done then
-
- -- Once State >= Done it will not change any more
-
- if Single_Lock then
- STPO.Lock_RTS;
- end if;
-
- STPO.Write_Lock (Self_ID);
- Utilities.Exit_One_ATC_Level (Self_ID);
- STPO.Unlock (Self_ID);
-
- if Single_Lock then
- STPO.Unlock_RTS;
- end if;
-
- Block.Enqueued := False;
- Block.Cancelled := Entry_Call.State = Cancelled;
- Initialization.Undefer_Abort_Nestable (Self_ID);
- Entry_Calls.Check_Exception (Self_ID, Entry_Call);
- return;
-
- else
- -- In this case we cannot conclude anything, since State can change
- -- concurrently.
-
- null;
- end if;
-
- -- Now for the general case
-
- if Mode = Asynchronous_Call then
-
- -- Try to avoid an expensive call
-
- if not Initially_Abortable then
- if Single_Lock then
- STPO.Lock_RTS;
- Entry_Calls.Wait_Until_Abortable (Self_ID, Entry_Call);
- STPO.Unlock_RTS;
- else
- Entry_Calls.Wait_Until_Abortable (Self_ID, Entry_Call);
- end if;
- end if;
-
- elsif Mode < Asynchronous_Call then
-
- -- Simple_Call or Conditional_Call
-
- if Single_Lock then
- STPO.Lock_RTS;
- Entry_Calls.Wait_For_Completion (Entry_Call);
- STPO.Unlock_RTS;
-
- else
- STPO.Write_Lock (Self_ID);
- Entry_Calls.Wait_For_Completion (Entry_Call);
- STPO.Unlock (Self_ID);
- end if;
-
- Block.Cancelled := Entry_Call.State = Cancelled;
-
- else
- pragma Assert (False);
- null;
- end if;
-
- Initialization.Undefer_Abort_Nestable (Self_ID);
- Entry_Calls.Check_Exception (Self_ID, Entry_Call);
- end Protected_Entry_Call;
-
- ------------------
- -- Requeue_Call --
- ------------------
-
- procedure Requeue_Call
- (Self_Id : Task_Id;
- Object : Protection_Entries_Access;
- Entry_Call : Entry_Call_Link)
- is
- New_Object : Protection_Entries_Access;
- Ceiling_Violation : Boolean;
- Result : Boolean;
- E : Protected_Entry_Index;
-
- begin
- New_Object := To_Protection (Entry_Call.Called_PO);
-
- if New_Object = null then
-
- -- Call is to be requeued to a task entry
-
- if Single_Lock then
- STPO.Lock_RTS;
- end if;
-
- Result := Rendezvous.Task_Do_Or_Queue (Self_Id, Entry_Call);
-
- if not Result then
- Queuing.Broadcast_Program_Error
- (Self_Id, Object, Entry_Call, RTS_Locked => True);
- end if;
-
- if Single_Lock then
- STPO.Unlock_RTS;
- end if;
-
- else
- -- Call should be requeued to a PO
-
- if Object /= New_Object then
-
- -- Requeue is to different PO
-
- Lock_Entries (New_Object, Ceiling_Violation);
-
- if Ceiling_Violation then
- Object.Call_In_Progress := null;
- Queuing.Broadcast_Program_Error (Self_Id, Object, Entry_Call);
-
- else
- PO_Do_Or_Queue (Self_Id, New_Object, Entry_Call);
- PO_Service_Entries (Self_Id, New_Object);
- end if;
-
- else
- -- Requeue is to same protected object
-
- -- ??? Try to compensate apparent failure of the scheduler on some
- -- OS (e.g VxWorks) to give higher priority tasks a chance to run
- -- (see CXD6002).
-
- STPO.Yield (False);
-
- if Entry_Call.With_Abort
- and then Entry_Call.Cancellation_Attempted
- then
- -- If this is a requeue with abort and someone tried to cancel
- -- this call, cancel it at this point.
-
- Entry_Call.State := Cancelled;
- return;
- end if;
-
- if not Entry_Call.With_Abort
- or else Entry_Call.Mode /= Conditional_Call
- then
- E := Protected_Entry_Index (Entry_Call.E);
-
- if Run_Time_Restrictions.Set (Max_Entry_Queue_Length)
- and then
- Run_Time_Restrictions.Value (Max_Entry_Queue_Length) <=
- Queuing.Count_Waiting (Object.Entry_Queues (E))
- then
- -- This violates the Max_Entry_Queue_Length restriction,
- -- raise Program_Error.
-
- Entry_Call.Exception_To_Raise := Program_Error'Identity;
-
- if Single_Lock then
- STPO.Lock_RTS;
- end if;
-
- STPO.Write_Lock (Entry_Call.Self);
- Initialization.Wakeup_Entry_Caller
- (Self_Id, Entry_Call, Done);
- STPO.Unlock (Entry_Call.Self);
-
- if Single_Lock then
- STPO.Unlock_RTS;
- end if;
-
- else
- Queuing.Enqueue
- (New_Object.Entry_Queues (E), Entry_Call);
- Update_For_Queue_To_PO (Entry_Call, Entry_Call.With_Abort);
- end if;
-
- else
- PO_Do_Or_Queue (Self_Id, New_Object, Entry_Call);
- end if;
- end if;
- end if;
- end Requeue_Call;
-
- ----------------------------
- -- Protected_Entry_Caller --
- ----------------------------
-
- function Protected_Entry_Caller
- (Object : Protection_Entries'Class) return Task_Id is
- begin
- return Object.Call_In_Progress.Self;
- end Protected_Entry_Caller;
-
- -----------------------------
- -- Requeue_Protected_Entry --
- -----------------------------
-
- -- Compiler interface only (do not call from within the RTS)
-
- -- entry e when b is
- -- begin
- -- b := false;
- -- ...A...
- -- requeue e2;
- -- end e;
-
- -- procedure rPT__E10b (O : address; P : address; E :
- -- protected_entry_index) is
- -- type rTVP is access rTV;
- -- freeze rTVP []
- -- _object : rTVP := rTVP!(O);
- -- begin
- -- declare
- -- rR : protection renames _object._object;
- -- vP : integer renames _object.v;
- -- bP : boolean renames _object.b;
- -- begin
- -- b := false;
- -- ...A...
- -- requeue_protected_entry (rR'unchecked_access, rR'
- -- unchecked_access, 2, false, objectF => 0, new_objectF =>
- -- 0);
- -- return;
- -- end;
- -- complete_entry_body (_object._object'unchecked_access, objectF =>
- -- 0);
- -- return;
- -- exception
- -- when others =>
- -- abort_undefer.all;
- -- exceptional_complete_entry_body (_object._object'
- -- unchecked_access, current_exception, objectF => 0);
- -- return;
- -- end rPT__E10b;
-
- procedure Requeue_Protected_Entry
- (Object : Protection_Entries_Access;
- New_Object : Protection_Entries_Access;
- E : Protected_Entry_Index;
- With_Abort : Boolean)
- is
- Entry_Call : constant Entry_Call_Link := Object.Call_In_Progress;
-
- begin
- pragma Debug
- (Debug.Trace (STPO.Self, "Requeue_Protected_Entry", 'P'));
- pragma Assert (STPO.Self.Deferral_Level > 0);
-
- Entry_Call.E := Entry_Index (E);
- Entry_Call.Called_PO := To_Address (New_Object);
- Entry_Call.Called_Task := null;
- Entry_Call.With_Abort := With_Abort;
- Object.Call_In_Progress := null;
- end Requeue_Protected_Entry;
-
- -------------------------------------
- -- Requeue_Task_To_Protected_Entry --
- -------------------------------------
-
- -- Compiler interface only (do not call from within the RTS)
-
- -- accept e1 do
- -- ...A...
- -- requeue r.e2;
- -- end e1;
-
- -- A79b : address;
- -- L78b : label
-
- -- begin
- -- accept_call (1, A79b);
- -- ...A...
- -- requeue_task_to_protected_entry (rTV!(r)._object'
- -- unchecked_access, 2, false, new_objectF => 0);
- -- goto L78b;
- -- <<L78b>>
- -- complete_rendezvous;
-
- -- exception
- -- when all others =>
- -- exceptional_complete_rendezvous (get_gnat_exception);
- -- end;
-
- procedure Requeue_Task_To_Protected_Entry
- (New_Object : Protection_Entries_Access;
- E : Protected_Entry_Index;
- With_Abort : Boolean)
- is
- Self_ID : constant Task_Id := STPO.Self;
- Entry_Call : constant Entry_Call_Link := Self_ID.Common.Call;
-
- begin
- Initialization.Defer_Abort (Self_ID);
-
- -- We do not need to lock Self_ID here since the call is not abortable
- -- at this point, and therefore, the caller cannot cancel the call.
-
- Entry_Call.Needs_Requeue := True;
- Entry_Call.With_Abort := With_Abort;
- Entry_Call.Called_PO := To_Address (New_Object);
- Entry_Call.Called_Task := null;
- Entry_Call.E := Entry_Index (E);
- Initialization.Undefer_Abort (Self_ID);
- end Requeue_Task_To_Protected_Entry;
-
- ---------------------
- -- Service_Entries --
- ---------------------
-
- procedure Service_Entries (Object : Protection_Entries_Access) is
- Self_ID : constant Task_Id := STPO.Self;
- begin
- PO_Service_Entries (Self_ID, Object);
- end Service_Entries;
-
- --------------------------------
- -- Timed_Protected_Entry_Call --
- --------------------------------
-
- -- Compiler interface only (do not call from within the RTS)
-
- procedure Timed_Protected_Entry_Call
- (Object : Protection_Entries_Access;
- E : Protected_Entry_Index;
- Uninterpreted_Data : System.Address;
- Timeout : Duration;
- Mode : Delay_Modes;
- Entry_Call_Successful : out Boolean)
- is
- Self_Id : constant Task_Id := STPO.Self;
- Entry_Call : Entry_Call_Link;
- Ceiling_Violation : Boolean;
-
- Yielded : Boolean;
- pragma Unreferenced (Yielded);
-
- begin
- if Self_Id.ATC_Nesting_Level = ATC_Level'Last then
- raise Storage_Error with "not enough ATC nesting levels";
- end if;
-
- -- If pragma Detect_Blocking is active then Program_Error must be
- -- raised if this potentially blocking operation is called from a
- -- protected action.
-
- if Detect_Blocking
- and then Self_Id.Common.Protected_Action_Nesting > 0
- then
- raise Program_Error with "potentially blocking operation";
- end if;
-
- if Runtime_Traces then
- Send_Trace_Info (POT_Call, Entry_Index (E), Timeout);
- end if;
-
- Initialization.Defer_Abort (Self_Id);
- Lock_Entries (Object, Ceiling_Violation);
-
- if Ceiling_Violation then
- Initialization.Undefer_Abort (Self_Id);
- raise Program_Error;
- end if;
-
- Self_Id.ATC_Nesting_Level := Self_Id.ATC_Nesting_Level + 1;
- pragma Debug
- (Debug.Trace (Self_Id, "TPEC: exited to ATC level: " &
- ATC_Level'Image (Self_Id.ATC_Nesting_Level), 'A'));
- Entry_Call :=
- Self_Id.Entry_Calls (Self_Id.ATC_Nesting_Level)'Access;
- Entry_Call.Next := null;
- Entry_Call.Mode := Timed_Call;
- Entry_Call.Cancellation_Attempted := False;
-
- if Self_Id.Deferral_Level > 1 then
- Entry_Call.State := Never_Abortable;
- else
- Entry_Call.State := Now_Abortable;
- end if;
-
- Entry_Call.E := Entry_Index (E);
- Entry_Call.Prio := STPO.Get_Priority (Self_Id);
- Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
- Entry_Call.Called_PO := To_Address (Object);
- Entry_Call.Called_Task := null;
- Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;
- Entry_Call.With_Abort := True;
-
- PO_Do_Or_Queue (Self_Id, Object, Entry_Call);
- PO_Service_Entries (Self_Id, Object);
-
- if Single_Lock then
- STPO.Lock_RTS;
- else
- STPO.Write_Lock (Self_Id);
- end if;
-
- -- Try to avoid waiting for completed or cancelled calls
-
- if Entry_Call.State >= Done then
- Utilities.Exit_One_ATC_Level (Self_Id);
-
- if Single_Lock then
- STPO.Unlock_RTS;
- else
- STPO.Unlock (Self_Id);
- end if;
-
- Entry_Call_Successful := Entry_Call.State = Done;
- Initialization.Undefer_Abort (Self_Id);
- Entry_Calls.Check_Exception (Self_Id, Entry_Call);
- return;
- end if;
-
- Entry_Calls.Wait_For_Completion_With_Timeout
- (Entry_Call, Timeout, Mode, Yielded);
-
- if Single_Lock then
- STPO.Unlock_RTS;
- else
- STPO.Unlock (Self_Id);
- end if;
-
- -- ??? Do we need to yield in case Yielded is False
-
- Initialization.Undefer_Abort (Self_Id);
- Entry_Call_Successful := Entry_Call.State = Done;
- Entry_Calls.Check_Exception (Self_Id, Entry_Call);
- end Timed_Protected_Entry_Call;
-
- ----------------------------
- -- Update_For_Queue_To_PO --
- ----------------------------
-
- -- Update the state of an existing entry call, based on
- -- whether the current queuing action is with or without abort.
- -- Call this only while holding the server's lock.
- -- It returns with the server's lock released.
-
- New_State : constant array (Boolean, Entry_Call_State)
- of Entry_Call_State :=
- (True =>
- (Never_Abortable => Never_Abortable,
- Not_Yet_Abortable => Now_Abortable,
- Was_Abortable => Now_Abortable,
- Now_Abortable => Now_Abortable,
- Done => Done,
- Cancelled => Cancelled),
- False =>
- (Never_Abortable => Never_Abortable,
- Not_Yet_Abortable => Not_Yet_Abortable,
- Was_Abortable => Was_Abortable,
- Now_Abortable => Now_Abortable,
- Done => Done,
- Cancelled => Cancelled)
- );
-
- procedure Update_For_Queue_To_PO
- (Entry_Call : Entry_Call_Link;
- With_Abort : Boolean)
- is
- Old : constant Entry_Call_State := Entry_Call.State;
-
- begin
- pragma Assert (Old < Done);
-
- Entry_Call.State := New_State (With_Abort, Entry_Call.State);
-
- if Entry_Call.Mode = Asynchronous_Call then
- if Old < Was_Abortable and then
- Entry_Call.State = Now_Abortable
- then
- if Single_Lock then
- STPO.Lock_RTS;
- end if;
-
- STPO.Write_Lock (Entry_Call.Self);
-
- if Entry_Call.Self.Common.State = Async_Select_Sleep then
- STPO.Wakeup (Entry_Call.Self, Async_Select_Sleep);
- end if;
-
- STPO.Unlock (Entry_Call.Self);
-
- if Single_Lock then
- STPO.Unlock_RTS;
- end if;
-
- end if;
-
- elsif Entry_Call.Mode = Conditional_Call then
- pragma Assert (Entry_Call.State < Was_Abortable);
- null;
- end if;
- end Update_For_Queue_To_PO;
-
-end System.Tasking.Protected_Objects.Operations;