home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / adav313.zip / gnat-3_13p-os2-bin-20010916.zip / emx / gnatlib / s-tasren.adb < prev    next >
Text File  |  2000-07-19  |  60KB  |  1,816 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --               GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS                --
  4. --                                                                          --
  5. --            S Y S T E M . T A S K I N G . R E N D E Z V O U S             --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.99 $
  10. --                                                                          --
  11. --            Copyright (C) 1991-2000, Florida State University             --
  12. --                                                                          --
  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.                                                      --
  23. --                                                                          --
  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.                                      --
  30. --                                                                          --
  31. -- GNARL was developed by the GNARL team at Florida State University. It is --
  32. -- now maintained by Ada Core Technologies Inc. in cooperation with Florida --
  33. -- State University (http://www.gnat.com).                                  --
  34. --                                                                          --
  35. ------------------------------------------------------------------------------
  36.  
  37. with Ada.Exceptions;
  38. --  Used for Exception_ID
  39. --           Null_Id
  40. --           Save_Occurrence
  41. --           Raise_Exception
  42.  
  43. with System.Task_Primitives.Operations;
  44. --  used for Get_Priority
  45. --           Set_Priority
  46. --           Write_Lock
  47. --           Unlock
  48. --           Sleep
  49. --           Wakeup
  50. --           Timed_Sleep
  51.  
  52. with System.Tasking.Entry_Calls;
  53. --  Used for Wait_For_Completion
  54. --           Wait_For_Completion_With_Timeout
  55. --           Wait_Until_Abortable
  56.  
  57. with System.Tasking.Initialization;
  58. --  used for Defer_Abort
  59. --           Undefer_Abort
  60. --           Poll_Base_Priority_Change
  61.  
  62. with System.Tasking.Queuing;
  63. --  used for Enqueue
  64. --           Dequeue_Head
  65. --           Select_Task_Entry_Call
  66. --           Count_Waiting
  67.  
  68. with System.Tasking.Utilities;
  69. --  used for Check_Exception
  70. --           Make_Passive
  71. --           Wakeup_Entry_Caller
  72.  
  73. with System.Tasking.Protected_Objects.Operations;
  74. --  used for PO_Do_Or_Queue
  75. --           PO_Service_Entries
  76. --           Lock_Entries
  77. --           Unlock_Entries
  78.  
  79. with System.Tasking.Debug;
  80. --  used for Trace
  81.  
  82. package body System.Tasking.Rendezvous is
  83.  
  84.    package STPO renames System.Task_Primitives.Operations;
  85.    package POO renames System.Tasking.Protected_Objects.Operations;
  86.    package POE renames System.Tasking.Protected_Objects.Entries;
  87.  
  88.    use System.Task_Primitives;
  89.    use System.Task_Primitives.Operations;
  90.  
  91.    type Select_Treatment is (
  92.      Accept_Alternative_Selected,   --  alternative with non-null body
  93.      Accept_Alternative_Completed,  --  alternative with null body
  94.      Else_Selected,
  95.      Terminate_Selected,
  96.      Accept_Alternative_Open,
  97.      No_Alternative_Open);
  98.  
  99.    Default_Treatment : constant array (Select_Modes) of Select_Treatment :=
  100.      (Simple_Mode         => No_Alternative_Open,
  101.       Else_Mode           => Else_Selected,
  102.       Terminate_Mode      => Terminate_Selected,
  103.       Delay_Mode          => No_Alternative_Open);
  104.  
  105.    New_State : constant array (Boolean, Entry_Call_State)
  106.      of Entry_Call_State :=
  107.        (True =>
  108.          (Never_Abortable   => Never_Abortable,
  109.           Not_Yet_Abortable => Now_Abortable,
  110.           Was_Abortable     => Now_Abortable,
  111.           Now_Abortable     => Now_Abortable,
  112.           Done              => Done,
  113.           Cancelled         => Cancelled),
  114.         False =>
  115.          (Never_Abortable   => Never_Abortable,
  116.           Not_Yet_Abortable => Not_Yet_Abortable,
  117.           Was_Abortable     => Was_Abortable,
  118.           Now_Abortable     => Now_Abortable,
  119.           Done              => Done,
  120.           Cancelled         => Cancelled)
  121.        );
  122.  
  123.    -----------------------
  124.    -- Local Subprograms --
  125.    -----------------------
  126.  
  127.    procedure Local_Defer_Abort (Self_Id : Task_ID) renames
  128.      System.Tasking.Initialization.Defer_Abort_Nestable;
  129.  
  130.    procedure Local_Undefer_Abort (Self_Id : Task_ID) renames
  131.      System.Tasking.Initialization.Undefer_Abort_Nestable;
  132.  
  133.    --  Florist defers abort around critical sections that
  134.    --  make entry calls to the Interrupt_Manager task, which
  135.    --  violates the general rule about top-level runtime system
  136.    --  calls from abort-deferred regions.  It is not that this is
  137.    --  unsafe, but when it occurs in "normal" programs it usually
  138.    --  means either the user is trying to do a potentially blocking
  139.    --  operation from within a protected object, or there is a
  140.    --  runtime system/compiler error that has failed to undefer
  141.    --  an earlier abort deferral.  Thus, for debugging it may be
  142.    --  wise to modify the above renamings to the non-nestable forms.
  143.  
  144.    procedure Boost_Priority
  145.      (Call     : Entry_Call_Link;
  146.       Acceptor : Task_ID);
  147.    pragma Inline (Boost_Priority);
  148.    --  Call this only with abort deferred and holding lock of Acceptor.
  149.  
  150.    procedure Call_Synchronous
  151.      (Acceptor              : Task_ID;
  152.       E                     : Task_Entry_Index;
  153.       Uninterpreted_Data    : System.Address;
  154.       Mode                  : Call_Modes;
  155.       Rendezvous_Successful : out Boolean);
  156.    pragma Inline (Call_Synchronous);
  157.    --  This call is used to make a simple or conditional entry call.
  158.  
  159.    procedure Setup_For_Rendezvous_With_Body
  160.      (Entry_Call : Entry_Call_Link;
  161.       Acceptor   : Task_ID);
  162.    pragma Inline (Setup_For_Rendezvous_With_Body);
  163.    --  Call this only with abort deferred and holding lock of Acceptor.
  164.    --  When a rendezvous selected (ready for rendezvous) we need to save
  165.    --  privious caller and adjust the priority. Also we need to make
  166.    --  this call not Abortable (Cancellable) since the rendezvous has
  167.    --  already been started.
  168.  
  169.    function Is_Entry_Open (T : Task_ID; E : Task_Entry_Index) return Boolean;
  170.    pragma Inline (Is_Entry_Open);
  171.    --  Call this only with abort deferred and holding lock of T.
  172.  
  173.    procedure Wait_For_Call (Self_Id : Task_ID);
  174.    pragma Inline (Wait_For_Call);
  175.    --  Call this only with abort deferred and holding lock of Self_Id.
  176.    --  An accepting task goes into Sleep by calling this routine
  177.    --  waiting for a call from the caller or waiting for an abortion.
  178.    --  Make sure Self_Id is locked before calling this routine.
  179.  
  180.    --------------------
  181.    -- Boost_Priority --
  182.    --------------------
  183.  
  184.    --  Call this only with abort deferred and holding lock of Acceptor.
  185.  
  186.    procedure Boost_Priority (Call : Entry_Call_Link; Acceptor : Task_ID) is
  187.       Caller        : Task_ID := Call.Self;
  188.       Caller_Prio   : System.Any_Priority := Get_Priority (Caller);
  189.       Acceptor_Prio : System.Any_Priority := Get_Priority (Acceptor);
  190.  
  191.    begin
  192.       if Caller_Prio > Acceptor_Prio then
  193.          Call.Acceptor_Prev_Priority := Acceptor_Prio;
  194.          Set_Priority (Acceptor, Caller_Prio);
  195.  
  196.       else
  197.          Call.Acceptor_Prev_Priority := Priority_Not_Boosted;
  198.       end if;
  199.    end Boost_Priority;
  200.  
  201.    ----------------------
  202.    -- Task_Do_Or_Queue --
  203.    ----------------------
  204.  
  205.    --  Call this only with abort deferred and holding no locks.
  206.    --  May propagate an exception, including Abort_Signal & Tasking_Error.
  207.    --  ?????
  208.    --  See Check_Callable.  Check all call contexts to verify
  209.    --  it is OK to raise an exception.
  210.  
  211.    --  Find out whether Entry_Call can be accepted immediately.
  212.    --  If the Acceptor is not callable, raise Tasking_Error.
  213.    --  If the rendezvous can start, initiate it.
  214.    --  If the accept-body is trivial, also complete the rendezvous.
  215.    --  If the acceptor is not ready, enqueue the call.
  216.  
  217.    --  ?????
  218.    --  This should have a special case for Accept_Call and
  219.    --  Accept_Trivial, so that
  220.    --  we don't have the loop setup overhead, below.
  221.  
  222.    --  ?????
  223.    --  The call state Done is used here and elsewhere to include
  224.    --  both the case of normal successful completion, and the case
  225.    --  of an exception being raised.  The difference is that if an
  226.    --  exception is raised no one will pay attention to the fact
  227.    --  that State = Done.  Instead the exception will be raised in
  228.    --  Undefer_Abort, and control will skip past the place where
  229.    --  we normally would resume from an entry call.
  230.  
  231.    function Task_Do_Or_Queue
  232.      (Self_ID    : Task_ID;
  233.       Entry_Call : Entry_Call_Link;
  234.       With_Abort : Boolean) return Boolean
  235.    is
  236.       E         : constant Task_Entry_Index := Task_Entry_Index (Entry_Call.E);
  237.       Old_State : constant Entry_Call_State := Entry_Call.State;
  238.       Acceptor  : constant Task_ID := Entry_Call.Called_Task;
  239.       Parent    : constant Task_ID := Acceptor.Common.Parent;
  240.       Parent_Locked : Boolean := False;
  241.       Null_Body : Boolean;
  242.  
  243.    begin
  244.       pragma Assert (not Queuing.Onqueue (Entry_Call));
  245.  
  246.       --  We rely that the call is off-queue for protection,
  247.       --  that the caller will not exit the Entry_Caller_Sleep,
  248.       --  and so will not reuse the call record for another call.
  249.       --  We rely on the Caller's lock for call State mod's.
  250.  
  251.       --  We can't lock Acceptor.Parent while holding Acceptor,
  252.       --  so lock it in advance if we expect to need to lock it.
  253.       --  ?????
  254.       --  Is there some better solution?
  255.  
  256.       if Acceptor.Terminate_Alternative then
  257.          STPO.Write_Lock (Parent);
  258.          Parent_Locked := True;
  259.       end if;
  260.  
  261.       STPO.Write_Lock (Acceptor);
  262.  
  263.       --  If the acceptor is not callable, abort the call
  264.       --  and raise Tasking_Error.  The call is not aborted
  265.       --  for an asynchronous call, since Cancel_Task_Entry_Call
  266.       --  will do the cancelation in that case.
  267.       --  ????? .....
  268.       --  Does the above still make sense?
  269.  
  270.       if not Acceptor.Callable then
  271.          STPO.Unlock (Acceptor);
  272.  
  273.          if Parent_Locked then
  274.             STPO.Unlock (Acceptor.Common.Parent);
  275.          end if;
  276.  
  277.          pragma Assert (Entry_Call.State < Done);
  278.  
  279.          --  In case we are not the caller, set up the caller
  280.          --  to raise Tasking_Error when it wakes up.
  281.  
  282.          STPO.Write_Lock (Entry_Call.Self);
  283.          Entry_Call.Exception_To_Raise := Tasking_Error'Identity;
  284.          Initialization.Wakeup_Entry_Caller (Self_ID, Entry_Call, Done);
  285.          STPO.Unlock (Entry_Call.Self);
  286.          return False;
  287.       end if;
  288.  
  289.       --  Try to serve the call immediately.
  290.  
  291.       if Acceptor.Open_Accepts /= null then
  292.          for J in Acceptor.Open_Accepts'Range loop
  293.             if Entry_Call.E = Entry_Index (Acceptor.Open_Accepts (J).S) then
  294.  
  295.                --  Commit acceptor to rendezvous with us.
  296.  
  297.                Acceptor.Chosen_Index := J;
  298.                Null_Body := Acceptor.Open_Accepts (J).Null_Body;
  299.                Acceptor.Open_Accepts := null;
  300.  
  301.                --  Prevent abort while call is being served.
  302.  
  303.                if Entry_Call.State = Now_Abortable then
  304.                   Entry_Call.State := Was_Abortable;
  305.                end if;
  306.  
  307.                if Acceptor.Terminate_Alternative then
  308.  
  309.                   --  Cancel terminate alternative.
  310.                   --  See matching code in Selective_Wait and
  311.                   --  Vulnerable_Complete_Master.
  312.  
  313.                   Acceptor.Terminate_Alternative := False;
  314.                   Acceptor.Awake_Count := Acceptor.Awake_Count + 1;
  315.  
  316.                   if Acceptor.Awake_Count = 1 then
  317.  
  318.                      --  Notify parent that acceptor is awake.
  319.  
  320.                      pragma Assert (Parent.Awake_Count > 0);
  321.  
  322.                      Parent.Awake_Count := Parent.Awake_Count + 1;
  323.  
  324.                      if Parent.Common.State = Master_Completion_Sleep and then
  325.                         Acceptor.Master_of_Task = Parent.Master_Within
  326.                      then
  327.                         Parent.Common.Wait_Count :=
  328.                           Parent.Common.Wait_Count + 1;
  329.                      end if;
  330.                   end if;
  331.                end if;
  332.  
  333.                if Null_Body then
  334.  
  335.                   --  Rendezvous is over immediately.
  336.  
  337.                   STPO.Wakeup (Acceptor, Acceptor_Sleep);
  338.                   STPO.Unlock (Acceptor);
  339.  
  340.                   if Parent_Locked then
  341.                      STPO.Unlock (Parent);
  342.                   end if;
  343.  
  344.                   STPO.Write_Lock (Entry_Call.Self);
  345.                   Initialization.Wakeup_Entry_Caller
  346.                     (Self_ID, Entry_Call, Done);
  347.                   STPO.Unlock (Entry_Call.Self);
  348.  
  349.                else
  350.                   Setup_For_Rendezvous_With_Body (Entry_Call, Acceptor);
  351.  
  352.                   --  For terminate_alternative, acceptor may not be
  353.                   --  asleep yet, so we skip the wakeup
  354.  
  355.                   if Acceptor.Common.State /= Runnable then
  356.                      STPO.Wakeup (Acceptor, Acceptor_Sleep);
  357.                   end if;
  358.  
  359.                   STPO.Unlock (Acceptor);
  360.  
  361.                   if Parent_Locked then
  362.                      STPO.Unlock (Parent);
  363.                   end if;
  364.                end if;
  365.  
  366.                return True;
  367.             end if;
  368.          end loop;
  369.  
  370.          --  The acceptor is accepting, but not this entry.
  371.       end if;
  372.  
  373.       --  If the acceptor was ready to accept this call,
  374.       --  we would not have gotten this far, so now we should
  375.       --  (re)enqueue the call, if the mode permits that.
  376.  
  377.       if Entry_Call.Mode /= Conditional_Call
  378.         or else not With_Abort
  379.       then
  380.          --  Timed_Call, Simple_Call, or Asynchronous_Call
  381.  
  382.          Queuing.Enqueue (Acceptor.Entry_Queues (E), Entry_Call);
  383.  
  384.          --  Update abortability of call
  385.  
  386.          pragma Assert (Old_State < Done);
  387.  
  388.          Entry_Call.State := New_State (With_Abort, Entry_Call.State);
  389.  
  390.          STPO.Unlock (Acceptor);
  391.  
  392.          if Parent_Locked then
  393.             STPO.Unlock (Parent);
  394.          end if;
  395.  
  396.          if Old_State /= Entry_Call.State and then
  397.            Entry_Call.State = Now_Abortable and then
  398.            Entry_Call.Mode > Simple_Call and then
  399.  
  400.             --  Asynchronous_Call or Conditional_Call
  401.  
  402.            Entry_Call.Self /= Self_ID
  403.  
  404.          then
  405.             --  Because of ATCB lock ordering rule
  406.  
  407.             STPO.Write_Lock (Entry_Call.Self);
  408.  
  409.             if Entry_Call.Self.Common.State = Async_Select_Sleep then
  410.  
  411.                --  Caller may not yet have reached wait-point
  412.  
  413.                STPO.Wakeup (Entry_Call.Self, Async_Select_Sleep);
  414.             end if;
  415.  
  416.             STPO.Unlock (Entry_Call.Self);
  417.          end if;
  418.  
  419.       else
  420.          --  Conditional_Call and With_Abort
  421.  
  422.          STPO.Unlock (Acceptor);
  423.  
  424.          if Parent_Locked then
  425.             STPO.Unlock (Parent);
  426.          end if;
  427.  
  428.          STPO.Write_Lock (Entry_Call.Self);
  429.  
  430.          pragma Assert (Entry_Call.State >= Was_Abortable);
  431.  
  432.          Initialization.Wakeup_Entry_Caller (Self_ID, Entry_Call, Cancelled);
  433.          STPO.Unlock (Entry_Call.Self);
  434.       end if;
  435.  
  436.       return True;
  437.    end Task_Do_Or_Queue;
  438.  
  439.    ------------------------------------
  440.    -- Setup_For_Rendezvous_With_Body --
  441.    ------------------------------------
  442.  
  443.    --  Call this only with abort deferred and holding lock of Acceptor.
  444.  
  445.    procedure Setup_For_Rendezvous_With_Body
  446.      (Entry_Call : Entry_Call_Link;
  447.       Acceptor   : Task_ID)
  448.    is
  449.    begin
  450.       Entry_Call.Acceptor_Prev_Call := Acceptor.Common.Call;
  451.       Acceptor.Common.Call := Entry_Call;
  452.  
  453.       if Entry_Call.State = Now_Abortable then
  454.          Entry_Call.State := Was_Abortable;
  455.       end if;
  456.  
  457.       Boost_Priority (Entry_Call, Acceptor);
  458.    end Setup_For_Rendezvous_With_Body;
  459.  
  460.    ----------------------
  461.    -- Call_Synchronous --
  462.    ----------------------
  463.  
  464.    --  Compiler interface.
  465.    --  Also called from inside Call_Simple and Task_Entry_Call.
  466.  
  467.    procedure Call_Synchronous
  468.      (Acceptor              : Task_ID;
  469.       E                     : Task_Entry_Index;
  470.       Uninterpreted_Data    : System.Address;
  471.       Mode                  : Call_Modes;
  472.       Rendezvous_Successful : out Boolean)
  473.    is
  474.       Self_Id    : constant Task_ID := STPO.Self;
  475.       Level      : ATC_Level;
  476.       Entry_Call : Entry_Call_Link;
  477.  
  478.    begin
  479.       pragma Assert (Mode /= Asynchronous_Call);
  480.  
  481.       Local_Defer_Abort (Self_Id);
  482.       Self_Id.ATC_Nesting_Level := Self_Id.ATC_Nesting_Level + 1;
  483.       pragma Debug
  484.         (Debug.Trace (Self_Id, "CS: entered ATC level: " &
  485.          ATC_Level'Image (Self_Id.ATC_Nesting_Level), 'A'));
  486.       Level := Self_Id.ATC_Nesting_Level;
  487.       Entry_Call := Self_Id.Entry_Calls (Level)'Access;
  488.       Entry_Call.Next := null;
  489.       Entry_Call.Mode := Mode;
  490.       Entry_Call.Cancellation_Attempted := False;
  491.  
  492.       --  If this is a call made inside of an abort deferred region,
  493.       --  the call should be never abortable.
  494.  
  495.       if Self_Id.Deferral_Level > 1 then
  496.          Entry_Call.State := Never_Abortable;
  497.       else
  498.          Entry_Call.State := Now_Abortable;
  499.       end if;
  500.  
  501.       Entry_Call.E := Entry_Index (E);
  502.       Entry_Call.Prio := Get_Priority (Self_Id);
  503.       Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
  504.       Entry_Call.Called_Task := Acceptor;
  505.       Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;
  506.  
  507.       --  Note: the caller will undefer abortion on return (see WARNING above)
  508.  
  509.       if not Task_Do_Or_Queue
  510.         (Self_Id, Entry_Call, With_Abort => True)
  511.       then
  512.          Self_Id.ATC_Nesting_Level := Self_Id.ATC_Nesting_Level - 1;
  513.          Initialization.Undefer_Abort (Self_Id);
  514.          pragma Debug
  515.            (Debug.Trace (Self_Id, "CS: exited to ATC level: " &
  516.             ATC_Level'Image (Self_Id.ATC_Nesting_Level), 'A'));
  517.          raise Tasking_Error;
  518.       end if;
  519.  
  520.       STPO.Write_Lock (Self_Id);
  521.       pragma Debug
  522.         (Debug.Trace (Self_Id, "Call_Synchronous: wait", 'R'));
  523.       Entry_Calls.Wait_For_Completion (Self_Id, Entry_Call);
  524.       pragma Debug
  525.         (Debug.Trace (Self_Id, "Call_Synchronous: done waiting", 'R'));
  526.       Rendezvous_Successful := Entry_Call.State = Done;
  527.       STPO.Unlock (Self_Id);
  528.       Local_Undefer_Abort (Self_Id);
  529.       Entry_Calls.Check_Exception (Self_Id, Entry_Call);
  530.    end Call_Synchronous;
  531.  
  532.    -----------------
  533.    -- Call_Simple --
  534.    -----------------
  535.  
  536.    --  Compiler interface only.  Do not call from within the RTS.
  537.  
  538.    procedure Call_Simple
  539.      (Acceptor           : Task_ID;
  540.       E                  : Task_Entry_Index;
  541.       Uninterpreted_Data : System.Address)
  542.    is
  543.       Rendezvous_Successful : Boolean;
  544.    begin
  545.       Call_Synchronous
  546.         (Acceptor, E, Uninterpreted_Data, Simple_Call, Rendezvous_Successful);
  547.    end Call_Simple;
  548.  
  549.    ----------------------------
  550.    -- Cancel_Task_Entry_Call --
  551.    ----------------------------
  552.  
  553.    --  Compiler interface only.  Do not call from within the RTS.
  554.    --  Call only with abort deferred.
  555.  
  556.    procedure Cancel_Task_Entry_Call (Cancelled : out Boolean) is
  557.    begin
  558.       Entry_Calls.Try_To_Cancel_Entry_Call (Cancelled);
  559.    end Cancel_Task_Entry_Call;
  560.  
  561.    ------------------------
  562.    -- Requeue_Task_Entry --
  563.    ------------------------
  564.  
  565.    --  Compiler interface only.  Do not call from within the RTS.
  566.    --  The code generation for task entry requeues is different from that
  567.    --  for protected entry requeues.  There is a "goto" that skips around
  568.    --  the call to Complete_Rendezous, so that Requeue_Task_Entry must also
  569.    --  do the work of Complete_Rendezvous.  The difference is that it does
  570.    --  not report that the call's State = Done.
  571.  
  572.    --     accept e1 do
  573.    --       ...A...
  574.    --       requeue e2;
  575.    --       ...B...
  576.    --     end e1;
  577.  
  578.    --     A62b : address;
  579.    --     L61b : label
  580.    --     begin
  581.    --        accept_call (1, A62b);
  582.    --        ...A...
  583.    --        requeue_task_entry (tTV!(t)._task_id, 2, false);
  584.    --        goto L61b;
  585.    --        ...B...
  586.    --        complete_rendezvous;
  587.    --        <<L61b>>
  588.    --     exception
  589.    --        when others =>
  590.    --           exceptional_complete_rendezvous (current_exception);
  591.    --     end;
  592.  
  593.    procedure Requeue_Task_Entry
  594.      (Acceptor   : Task_ID;
  595.       E          : Task_Entry_Index;
  596.       With_Abort : Boolean)
  597.    is
  598.       Self_Id       : constant Task_ID := STPO.Self;
  599.       Entry_Call    : constant Entry_Call_Link := Self_Id.Common.Call;
  600.  
  601.    begin
  602.       Initialization.Defer_Abort (Self_Id);
  603.       Entry_Call.Needs_Requeue := True;
  604.       Entry_Call.Requeue_With_Abort := With_Abort;
  605.       Entry_Call.E := Entry_Index (E);
  606.       Entry_Call.Called_Task := Acceptor;
  607.       Initialization.Undefer_Abort (Self_Id);
  608.    end Requeue_Task_Entry;
  609.  
  610.    -------------------------------------
  611.    -- Requeue_Protected_To_Task_Entry --
  612.    -------------------------------------
  613.  
  614.    --  Compiler interface only.  Do not call from within the RTS.
  615.  
  616.    --  entry e2 when b is
  617.    --  begin
  618.    --     b := false;
  619.    --     ...A...
  620.    --     requeue t.e2;
  621.    --  end e2;
  622.  
  623.    --  procedure rPT__E14b (O : address; P : address; E :
  624.    --    protected_entry_index) is
  625.    --     type rTVP is access rTV;
  626.    --     freeze rTVP []
  627.    --     _object : rTVP := rTVP!(O);
  628.    --  begin
  629.    --     declare
  630.    --        rR : protection renames _object._object;
  631.    --        vP : integer renames _object.v;
  632.    --        bP : boolean renames _object.b;
  633.    --     begin
  634.    --        b := false;
  635.    --        ...A...
  636.    --        requeue_protected_to_task_entry (rR'unchecked_access, tTV!(t).
  637.    --          _task_id, 2, false);
  638.    --        return;
  639.    --     end;
  640.    --     complete_entry_body (_object._object'unchecked_access, objectF =>
  641.    --       0);
  642.    --     return;
  643.    --  exception
  644.    --     when others =>
  645.    --        abort_undefer.all;
  646.    --        exceptional_complete_entry_body (_object._object'
  647.    --          unchecked_access, current_exception, objectF => 0);
  648.    --        return;
  649.    --  end rPT__E14b;
  650.  
  651.    procedure Requeue_Protected_To_Task_Entry
  652.      (Object     : STPE.Protection_Entries_Access;
  653.       Acceptor   : Task_ID;
  654.       E          : Task_Entry_Index;
  655.       With_Abort : Boolean)
  656.    is
  657.       Entry_Call : constant Entry_Call_Link := Object.Call_In_Progress;
  658.    begin
  659.       pragma Assert (STPO.Self.Deferral_Level > 0);
  660.  
  661.       Entry_Call.E := Entry_Index (E);
  662.       Entry_Call.Called_Task := Acceptor;
  663.       Entry_Call.Called_PO := Null_Address;
  664.       Entry_Call.Requeue_With_Abort := With_Abort;
  665.       Object.Call_In_Progress := null;
  666.    end Requeue_Protected_To_Task_Entry;
  667.  
  668.    ---------------------
  669.    -- Task_Entry_Call --
  670.    ---------------------
  671.  
  672.    procedure Task_Entry_Call
  673.      (Acceptor              : Task_ID;
  674.       E                     : Task_Entry_Index;
  675.       Uninterpreted_Data    : System.Address;
  676.       Mode                  : Call_Modes;
  677.       Rendezvous_Successful : out Boolean)
  678.    is
  679.       Self_Id    : constant Task_ID := STPO.Self;
  680.       Entry_Call : Entry_Call_Link;
  681.  
  682.    begin
  683.       if Mode = Simple_Call or else Mode = Conditional_Call then
  684.          Call_Synchronous
  685.            (Acceptor, E, Uninterpreted_Data, Mode, Rendezvous_Successful);
  686.  
  687.       else
  688.          --  This is an asynchronous call
  689.  
  690.          --  Abortion must already be deferred by the compiler-generated
  691.          --  code.  Without this, an abortion that occurs between the time
  692.          --  that this call is made and the time that the abortable part's
  693.          --  cleanup handler is set up might miss the cleanup handler and
  694.          --  leave the call pending.
  695.  
  696.          Self_Id.ATC_Nesting_Level := Self_Id.ATC_Nesting_Level + 1;
  697.          pragma Debug
  698.            (Debug.Trace (Self_Id, "TEC: entered ATC level: " &
  699.             ATC_Level'Image (Self_Id.ATC_Nesting_Level), 'A'));
  700.          Entry_Call := Self_Id.Entry_Calls (Self_Id.ATC_Nesting_Level)'Access;
  701.          Entry_Call.Next := null;
  702.          Entry_Call.Mode := Mode;
  703.          Entry_Call.Cancellation_Attempted := False;
  704.          Entry_Call.State := Not_Yet_Abortable;
  705.          Entry_Call.E := Entry_Index (E);
  706.          Entry_Call.Prio := Get_Priority (Self_Id);
  707.          Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
  708.          Entry_Call.Called_Task := Acceptor;
  709.          Entry_Call.Called_PO := Null_Address;
  710.          Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;
  711.  
  712.          if not Task_Do_Or_Queue
  713.            (Self_Id, Entry_Call, With_Abort => True)
  714.          then
  715.             Self_Id.ATC_Nesting_Level := Self_Id.ATC_Nesting_Level - 1;
  716.             pragma Debug
  717.               (Debug.Trace (Self_Id, "TEC: exited to ATC level: " &
  718.                ATC_Level'Image (Self_Id.ATC_Nesting_Level), 'A'));
  719.             Initialization.Undefer_Abort (Self_Id);
  720.             raise Tasking_Error;
  721.          end if;
  722.  
  723.          --  The following is special for async. entry calls.
  724.          --  If the call was not queued abortably, we need to wait until
  725.          --  it is before proceeding with the abortable part.
  726.  
  727.          --  Wait_Until_Abortable can be called unconditionally here,
  728.          --  but it is expensive.
  729.  
  730.          if Entry_Call.State < Was_Abortable then
  731.             Entry_Calls.Wait_Until_Abortable (Self_Id, Entry_Call);
  732.          end if;
  733.  
  734.          --  Note: following assignment needs to be atomic.
  735.  
  736.          Rendezvous_Successful := Entry_Call.State = Done;
  737.       end if;
  738.    end Task_Entry_Call;
  739.  
  740.    ---------------------------
  741.    -- Timed_Task_Entry_Call --
  742.    ---------------------------
  743.  
  744.    --  Compiler interface only.  Do not call from within the RTS.
  745.  
  746.    procedure Timed_Task_Entry_Call
  747.      (Acceptor              : Task_ID;
  748.       E                     : Task_Entry_Index;
  749.       Uninterpreted_Data    : System.Address;
  750.       Timeout               : Duration;
  751.       Mode                  : Delay_Modes;
  752.       Rendezvous_Successful : out Boolean)
  753.    is
  754.       Self_Id    : constant Task_ID := STPO.Self;
  755.       Level      : ATC_Level;
  756.       Entry_Call : Entry_Call_Link;
  757.  
  758.    begin
  759.       Initialization.Defer_Abort (Self_Id);
  760.       Self_Id.ATC_Nesting_Level := Self_Id.ATC_Nesting_Level + 1;
  761.  
  762.       pragma Debug
  763.         (Debug.Trace (Self_Id, "TTEC: entered ATC level: " &
  764.          ATC_Level'Image (Self_Id.ATC_Nesting_Level), 'A'));
  765.  
  766.       Level := Self_Id.ATC_Nesting_Level;
  767.       Entry_Call := Self_Id.Entry_Calls (Level)'Access;
  768.       Entry_Call.Next := null;
  769.       Entry_Call.Mode := Timed_Call;
  770.       Entry_Call.Cancellation_Attempted := False;
  771.  
  772.       --  If this is a call made inside of an abort deferred region,
  773.       --  the call should be never abortable.
  774.  
  775.       if Self_Id.Deferral_Level > 1 then
  776.          Entry_Call.State := Never_Abortable;
  777.       else
  778.          Entry_Call.State := Now_Abortable;
  779.       end if;
  780.  
  781.       Entry_Call.E := Entry_Index (E);
  782.       Entry_Call.Prio := Get_Priority (Self_Id);
  783.       Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
  784.       Entry_Call.Called_Task := Acceptor;
  785.       Entry_Call.Called_PO := Null_Address;
  786.       Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;
  787.  
  788.       --  Note: the caller will undefer abortion on return (see WARNING above)
  789.  
  790.       if not Task_Do_Or_Queue
  791.        (Self_Id, Entry_Call, With_Abort => True)
  792.       then
  793.          Self_Id.ATC_Nesting_Level := Self_Id.ATC_Nesting_Level - 1;
  794.  
  795.          pragma Debug
  796.            (Debug.Trace (Self_Id, "TTEC: exited to ATC level: " &
  797.             ATC_Level'Image (Self_Id.ATC_Nesting_Level), 'A'));
  798.  
  799.          Initialization.Undefer_Abort (Self_Id);
  800.          raise Tasking_Error;
  801.       end if;
  802.  
  803.       Entry_Calls.Wait_For_Completion_With_Timeout
  804.         (Self_Id, Entry_Call, Timeout, Mode);
  805.       Rendezvous_Successful := Entry_Call.State = Done;
  806.       Initialization.Undefer_Abort (Self_Id);
  807.       Entry_Calls.Check_Exception (Self_Id, Entry_Call);
  808.    end Timed_Task_Entry_Call;
  809.  
  810.    -----------------
  811.    -- Accept_Call --
  812.    -----------------
  813.  
  814.    --  Compiler interface only.  Do not call from within the RTS.
  815.  
  816.    --  source:
  817.    --              accept E do  ...A... end E;
  818.    --  expansion:
  819.    --              A27b : address;
  820.    --              L26b : label
  821.    --              begin
  822.    --                 accept_call (1, A27b);
  823.    --                 ...A...
  824.    --                 complete_rendezvous;
  825.    --              <<L26b>>
  826.    --              exception
  827.    --              when all others =>
  828.    --                 exceptional_complete_rendezvous (get_gnat_exception);
  829.    --              end;
  830.  
  831.    --  The handler for Abort_Signal (*all* others) is to handle the case when
  832.    --  the acceptor is aborted between Accept_Call and the corresponding
  833.    --  Complete_Rendezvous call. We need to wake up the caller in this case.
  834.  
  835.    --   See also Selective_Wait
  836.  
  837.    procedure Accept_Call
  838.      (E                  : Task_Entry_Index;
  839.       Uninterpreted_Data : out System.Address)
  840.    is
  841.       Self_Id      : constant Task_ID := STPO.Self;
  842.       Caller       : Task_ID := null;
  843.       Open_Accepts : aliased Accept_List (1 .. 1);
  844.       Entry_Call   : Entry_Call_Link;
  845.  
  846.    begin
  847.       Initialization.Defer_Abort (Self_Id);
  848.  
  849.       STPO.Write_Lock (Self_Id);
  850.  
  851.       if not Self_Id.Callable then
  852.          pragma Assert (Self_Id.Pending_ATC_Level = 0);
  853.  
  854.          pragma Assert (Self_Id.Pending_Action);
  855.  
  856.          STPO.Unlock (Self_Id);
  857.          Initialization.Undefer_Abort (Self_Id);
  858.  
  859.          --  Should never get here ???
  860.  
  861.          pragma Assert (False);
  862.          raise Standard'Abort_Signal;
  863.       end if;
  864.  
  865.       --  If someone completed this task, this task should not try to
  866.       --  access its pending entry calls or queues in this case, as they
  867.       --  are being emptied. Wait for abortion to kill us.
  868.       --  ?????
  869.       --  Recheck the correctness of the above, now that we have made
  870.       --  changes.  The logic above seems to be based on the assumption
  871.       --  that one task can safely clean up another's in-service accepts.
  872.       --  ?????
  873.       --  Why do we need to block here in this case?
  874.       --  Why not just return and let Undefer_Abort do its work?
  875.  
  876.       Queuing.Dequeue_Head (Self_Id.Entry_Queues (E), Entry_Call);
  877.  
  878.       if Entry_Call /= null then
  879.          Caller := Entry_Call.Self;
  880.          Setup_For_Rendezvous_With_Body (Entry_Call, Self_Id);
  881.          Uninterpreted_Data := Entry_Call.Uninterpreted_Data;
  882.  
  883.       else
  884.          --  Wait for a caller
  885.  
  886.          Open_Accepts (1).Null_Body := False;
  887.          Open_Accepts (1).S := E;
  888.          Self_Id.Open_Accepts := Open_Accepts'Unrestricted_Access;
  889.  
  890.          --  Wait for normal call
  891.  
  892.          pragma Debug
  893.            (Debug.Trace (Self_Id, "Accept_Call: wait", 'R'));
  894.          Wait_For_Call (Self_Id);
  895.  
  896.          pragma Assert (Self_Id.Open_Accepts = null);
  897.  
  898.          if Self_Id.Pending_ATC_Level >= Self_Id.ATC_Nesting_Level then
  899.             Caller := Self_Id.Common.Call.Self;
  900.             Uninterpreted_Data :=
  901.               Caller.Entry_Calls (Caller.ATC_Nesting_Level).Uninterpreted_Data;
  902.          end if;
  903.  
  904.          --  If this task has been aborted, skip the Uninterpreted_Data load
  905.          --  (Caller will not be reliable) and fall through to
  906.          --  Undefer_Abort which will allow the task to be killed.
  907.          --  ?????
  908.          --  Perhaps we could do the code anyway, if it has no harm, in order
  909.          --  to get better performance for the normal case.
  910.  
  911.       end if;
  912.  
  913.       --  Self_Id.Common.Call should already be updated by the Caller
  914.       --  On return, we will start the rendezvous.
  915.  
  916.       STPO.Unlock (Self_Id);
  917.       Initialization.Undefer_Abort (Self_Id);
  918.    end Accept_Call;
  919.  
  920.    --------------------
  921.    -- Accept_Trivial --
  922.    --------------------
  923.  
  924.    --  Compiler interface only.  Do not call from within the RTS.
  925.    --  This should only be called when there is no accept body,
  926.    --  or the except body is empty.
  927.  
  928.    --  source:
  929.    --               accept E;
  930.    --  expansion:
  931.    --               accept_trivial (1);
  932.  
  933.    --  The compiler is also able to recognize the following and
  934.    --  translate it the same way.
  935.  
  936.    --     accept E do null; end E;
  937.  
  938.    procedure Accept_Trivial (E : Task_Entry_Index) is
  939.       Self_Id       : constant Task_ID := STPO.Self;
  940.       Caller        : Task_ID := null;
  941.       Open_Accepts  : aliased Accept_List (1 .. 1);
  942.       Entry_Call    : Entry_Call_Link;
  943.  
  944.    begin
  945.       Initialization.Defer_Abort_Nestable (Self_Id);
  946.       STPO.Write_Lock (Self_Id);
  947.  
  948.       if not Self_Id.Callable then
  949.          pragma Assert (Self_Id.Pending_ATC_Level = 0);
  950.  
  951.          pragma Assert (Self_Id.Pending_Action);
  952.  
  953.          STPO.Unlock (Self_Id);
  954.          Initialization.Undefer_Abort_Nestable (Self_Id);
  955.  
  956.          --  Should never get here ???
  957.  
  958.          pragma Assert (False);
  959.          raise Standard'Abort_Signal;
  960.       end if;
  961.  
  962.       --  If someone completed this task, this task should not try to
  963.       --  access its pending entry calls or queues in this case, as they
  964.       --  are being emptied. Wait for abortion to kill us.
  965.       --  ?????
  966.       --  Recheck the correctness of the above, now that we have made
  967.       --  changes.
  968.  
  969.       Queuing.Dequeue_Head (Self_Id.Entry_Queues (E), Entry_Call);
  970.  
  971.       if Entry_Call = null then
  972.  
  973.          --  Need to wait for entry call
  974.  
  975.          Open_Accepts (1).Null_Body := True;
  976.          Open_Accepts (1).S := E;
  977.          Self_Id.Open_Accepts := Open_Accepts'Unrestricted_Access;
  978.  
  979.          pragma Debug
  980.           (Debug.Trace (Self_Id, "Accept_Trivial: wait", 'R'));
  981.  
  982.          Wait_For_Call (Self_Id);
  983.  
  984.          pragma Assert (Self_Id.Open_Accepts = null);
  985.  
  986.          --  No need to do anything special here for pending abort.
  987.          --  Abort_Signal will be raised by Undefer on exit.
  988.  
  989.          STPO.Unlock (Self_Id);
  990.  
  991.       else  --  found caller already waiting
  992.  
  993.          pragma Assert (Entry_Call.State < Done);
  994.  
  995.          STPO.Unlock (Self_Id);
  996.          Caller := Entry_Call.Self;
  997.  
  998.          STPO.Write_Lock (Caller);
  999.          Initialization.Wakeup_Entry_Caller (Self_Id, Entry_Call, Done);
  1000.          STPO.Unlock (Caller);
  1001.       end if;
  1002.  
  1003.       Initialization.Undefer_Abort_Nestable (Self_Id);
  1004.    end Accept_Trivial;
  1005.  
  1006.    -------------------------------------
  1007.    -- Exceptional_Complete_Rendezvous --
  1008.    -------------------------------------
  1009.  
  1010.    --  Compiler interface.
  1011.    --  Also called from Complete_Rendezvous.
  1012.    --  ?????
  1013.    --  Consider phasing out Complete_Rendezvous in favor
  1014.    --  of direct call to this with Ada.Exceptions.Null_ID.
  1015.    --  See code expansion examples for Accept_Call and Selective_Wait.
  1016.    --  ?????
  1017.    --  If we don't change the interface, consider instead
  1018.    --  putting an explicit re-raise after this call, in
  1019.    --  the generated code.  That way we could eliminate the
  1020.    --  code here that reraises the exception.
  1021.  
  1022.    --  The deferral level is critical here,
  1023.    --  since we want to raise an exception or allow abort to take
  1024.    --  place, if there is an exception or abort pending.
  1025.  
  1026.    procedure Exceptional_Complete_Rendezvous
  1027.      (Ex : Ada.Exceptions.Exception_Id)
  1028.    is
  1029.       Self_Id    : constant Task_ID := STPO.Self;
  1030.       Entry_Call : Entry_Call_Link := Self_Id.Common.Call;
  1031.       Caller     : Task_ID;
  1032.       Called_PO  : STPE.Protection_Entries_Access;
  1033.  
  1034.       Exception_To_Raise : Ada.Exceptions.Exception_Id := Ex;
  1035.       Ceiling_Violation  : Boolean;
  1036.  
  1037.       use type Ada.Exceptions.Exception_Id;
  1038.       procedure Internal_Reraise;
  1039.       pragma Import (C, Internal_Reraise, "__gnat_reraise");
  1040.  
  1041.       use type STPE.Protection_Entries_Access;
  1042.  
  1043.    begin
  1044.       pragma Debug
  1045.        (Debug.Trace (Self_Id, "Exceptional_Complete_Rendezvous", 'R'));
  1046.  
  1047.       if Ex = Ada.Exceptions.Null_Id then
  1048.          --  The call came from normal end-of-rendezvous,
  1049.          --  so abort is not yet deferred.
  1050.          Initialization.Defer_Abort_Nestable (Self_Id);
  1051.       end if;
  1052.  
  1053.       --  We need to clean up any accepts which Self may have
  1054.       --  been serving when it was aborted.
  1055.  
  1056.       if Ex = Standard'Abort_Signal'Identity then
  1057.          while Entry_Call /= null loop
  1058.             Entry_Call.Exception_To_Raise := Tasking_Error'Identity;
  1059.  
  1060.             --  All forms of accept make sure that the acceptor is not
  1061.             --  completed, before accepting further calls, so that we
  1062.             --  can be sure that no further calls are made after the
  1063.             --  current calls are purged.
  1064.  
  1065.             Caller := Entry_Call.Self;
  1066.  
  1067.             --  Take write lock. This follows the lock precedence rule that
  1068.             --  Caller may be locked while holding lock of Acceptor.
  1069.             --  Complete the call abnormally, with exception.
  1070.  
  1071.             STPO.Write_Lock (Caller);
  1072.  
  1073.             Initialization.Wakeup_Entry_Caller (Self_Id, Entry_Call, Done);
  1074.             STPO.Unlock (Caller);
  1075.             Entry_Call := Entry_Call.Acceptor_Prev_Call;
  1076.          end loop;
  1077.  
  1078.       else
  1079.          Caller := Entry_Call.Self;
  1080.  
  1081.          if Entry_Call.Needs_Requeue then
  1082.             --  We dare not lock Self_Id at the same time as Caller,
  1083.             --  for fear of deadlock.
  1084.  
  1085.             Entry_Call.Needs_Requeue := False;
  1086.             Self_Id.Common.Call := Entry_Call.Acceptor_Prev_Call;
  1087.  
  1088.             if Entry_Call.Called_Task /= null then
  1089.                --  Requeue to another task entry
  1090.  
  1091.                if not Task_Do_Or_Queue
  1092.                  (Self_Id, Entry_Call, Entry_Call.Requeue_With_Abort)
  1093.                then
  1094.                   Initialization.Undefer_Abort (Self_Id);
  1095.                   raise Tasking_Error;
  1096.                end if;
  1097.  
  1098.             else
  1099.                --  Requeue to a protected entry
  1100.  
  1101.                Called_PO := POE.To_Protection (Entry_Call.Called_PO);
  1102.                STPO.Write_Lock (Called_PO.L'Access, Ceiling_Violation);
  1103.  
  1104.                if Ceiling_Violation then
  1105.                   pragma Assert (Ex = Ada.Exceptions.Null_Id);
  1106.  
  1107.                   Exception_To_Raise := Program_Error'Identity;
  1108.                   Entry_Call.Exception_To_Raise := Exception_To_Raise;
  1109.                   STPO.Write_Lock (Caller);
  1110.                   Initialization.Wakeup_Entry_Caller
  1111.                     (Self_Id, Entry_Call, Done);
  1112.                   STPO.Unlock (Caller);
  1113.  
  1114.                else
  1115.                   POO.PO_Do_Or_Queue
  1116.                     (Self_Id, Called_PO, Entry_Call,
  1117.                      Entry_Call.Requeue_With_Abort);
  1118.                   POO.PO_Service_Entries (Self_Id, Called_PO);
  1119.                   STPE.Unlock_Entries (Called_PO);
  1120.                end if;
  1121.             end if;
  1122.  
  1123.             Entry_Calls.Reset_Priority (Entry_Call.Acceptor_Prev_Priority,
  1124.               Self_Id);
  1125.  
  1126.          else
  1127.             --  The call does not need to be requeued.
  1128.  
  1129.             Self_Id.Common.Call := Entry_Call.Acceptor_Prev_Call;
  1130.             Entry_Call.Exception_To_Raise := Ex;
  1131.             STPO.Write_Lock (Caller);
  1132.  
  1133.             --  Done with Caller locked to make sure that Wakeup is not lost.
  1134.  
  1135.             if Ex /= Ada.Exceptions.Null_Id then
  1136.                Ada.Exceptions.Save_Occurrence
  1137.                  (Caller.Common.Compiler_Data.Current_Excep,
  1138.                   Self_Id.Common.Compiler_Data.Current_Excep);
  1139.             end if;
  1140.  
  1141.             Initialization.Wakeup_Entry_Caller (Self_Id, Entry_Call, Done);
  1142.             STPO.Unlock (Caller);
  1143.             Entry_Calls.Reset_Priority (Entry_Call.Acceptor_Prev_Priority,
  1144.               Self_Id);
  1145.          end if;
  1146.       end if;
  1147.  
  1148.       Initialization.Undefer_Abort (Self_Id);
  1149.  
  1150.       if Exception_To_Raise /= Ada.Exceptions.Null_Id then
  1151.          Internal_Reraise;
  1152.       end if;
  1153.  
  1154.       --  ?????
  1155.       --  Do we need to
  1156.       --  give precedence to Program_Error that might be raised
  1157.       --  due to failure of finalization, over Tasking_Error from
  1158.       --  failure of requeue?
  1159.    end Exceptional_Complete_Rendezvous;
  1160.  
  1161.    -------------------------
  1162.    -- Complete_Rendezvous --
  1163.    -------------------------
  1164.  
  1165.    --  See comments for Exceptional_Complete_Rendezvous.
  1166.  
  1167.    procedure Complete_Rendezvous is
  1168.    begin
  1169.       Exceptional_Complete_Rendezvous (Ada.Exceptions.Null_Id);
  1170.    end Complete_Rendezvous;
  1171.  
  1172.    --------------------
  1173.    -- Selective_Wait --
  1174.    --------------------
  1175.  
  1176.    --  Compiler interface only.  Do not call from within the RTS.
  1177.    --  See comments on Accept_Call.
  1178.  
  1179.    --  source code:
  1180.  
  1181.    --     select accept e1 do
  1182.    --           ...A...
  1183.    --        end e1;
  1184.    --        ...B...
  1185.    --     or accept e2;
  1186.    --        ...C...
  1187.    --     end select;
  1188.  
  1189.    --  expansion:
  1190.  
  1191.    --     A32b : address;
  1192.    --     declare
  1193.    --        null;
  1194.    --        if accept_alternative'size * 2 >= 16#8000_0000# then
  1195.    --           raise storage_error;
  1196.    --        end if;
  1197.    --        A37b : T36b;
  1198.    --        A37b (1) := (null_body => false, s => 1);
  1199.    --        A37b (2) := (null_body => true, s => 2);
  1200.    --        if accept_alternative'size * 2 >= 16#8000_0000# then
  1201.    --           raise storage_error;
  1202.    --        end if;
  1203.    --        S0 : aliased T36b := accept_list'A37b;
  1204.    --        J1 : select_index := 0;
  1205.    --        L3 : label
  1206.    --        L1 : label
  1207.    --        L2 : label
  1208.    --        procedure e1A is
  1209.    --        begin
  1210.    --           abort_undefer.all;
  1211.    --           L31b : label
  1212.    --           ...A...
  1213.    --           <<L31b>>
  1214.    --           complete_rendezvous;
  1215.    --        exception
  1216.    --           when all others =>
  1217.    --              exceptional_complete_rendezvous (get_gnat_exception);
  1218.    --        end e1A;
  1219.    --     begin
  1220.    --        selective_wait (S0'unchecked_access, simple_mode, A32b, J1);
  1221.    --        case J1 is
  1222.    --           when 0 =>
  1223.    --              goto L3;
  1224.    --           when 1 =>
  1225.    --              e1A;
  1226.    --              goto L1;
  1227.    --           when 2 =>
  1228.    --              goto L2;
  1229.    --           when others =>
  1230.    --              goto L3;
  1231.    --        end case;
  1232.    --        <<L1>>
  1233.    --        ...B...
  1234.    --        goto L3;
  1235.    --        <<L2>>
  1236.    --        ...C...
  1237.    --        goto L3;
  1238.    --        <<L3>>
  1239.    --     end;
  1240.  
  1241.    procedure Selective_Wait
  1242.      (Open_Accepts       : Accept_List_Access;
  1243.       Select_Mode        : Select_Modes;
  1244.       Uninterpreted_Data : out System.Address;
  1245.       Index              : out Select_Index)
  1246.    is
  1247.       Self_Id          : constant Task_ID := STPO.Self;
  1248.       Entry_Call       : Entry_Call_Link;
  1249.       Treatment        : Select_Treatment;
  1250.       Caller           : Task_ID;
  1251.       Selection        : Select_Index;
  1252.       Open_Alternative : Boolean;
  1253.  
  1254.    begin
  1255.       Initialization.Defer_Abort (Self_Id);
  1256.       STPO.Write_Lock (Self_Id);
  1257.  
  1258.       if not Self_Id.Callable then
  1259.          pragma Assert (Self_Id.Pending_ATC_Level = 0);
  1260.  
  1261.          pragma Assert (Self_Id.Pending_Action);
  1262.  
  1263.          STPO.Unlock (Self_Id);
  1264.  
  1265.          --  ??? In some cases abort is deferred more than once. Need to figure
  1266.          --  out why.
  1267.  
  1268.          Self_Id.Deferral_Level := 1;
  1269.  
  1270.          Initialization.Undefer_Abort (Self_Id);
  1271.  
  1272.          --  Should never get here ???
  1273.  
  1274.          pragma Assert (False);
  1275.          raise Standard'Abort_Signal;
  1276.       end if;
  1277.  
  1278.       --  If someone completed this task, this task should not try to
  1279.       --  access its pending entry calls or queues in this case, as they
  1280.       --  are being emptied. Wait for abortion to kill us.
  1281.       --  ?????
  1282.       --  Recheck the correctness of the above, now that we have made
  1283.       --  changes.
  1284.  
  1285.       pragma Assert (Open_Accepts /= null);
  1286.  
  1287.       Queuing.Select_Task_Entry_Call
  1288.         (Self_Id, Open_Accepts, Entry_Call, Selection, Open_Alternative);
  1289.  
  1290.       --  Determine the kind and disposition of the select.
  1291.  
  1292.       Treatment := Default_Treatment (Select_Mode);
  1293.       Self_Id.Chosen_Index := No_Rendezvous;
  1294.  
  1295.       if Open_Alternative then
  1296.          if Entry_Call /= null then
  1297.             if Open_Accepts (Selection).Null_Body then
  1298.                Treatment := Accept_Alternative_Completed;
  1299.  
  1300.             else
  1301.                Setup_For_Rendezvous_With_Body (Entry_Call, Self_Id);
  1302.                Treatment := Accept_Alternative_Selected;
  1303.             end if;
  1304.  
  1305.             Self_Id.Chosen_Index := Selection;
  1306.  
  1307.          elsif Treatment = No_Alternative_Open then
  1308.             Treatment := Accept_Alternative_Open;
  1309.          end if;
  1310.       end if;
  1311.  
  1312.       --  ??????
  1313.       --  Recheck the logic above against the ARM.
  1314.  
  1315.       --  Handle the select according to the disposition selected above.
  1316.  
  1317.       case Treatment is
  1318.  
  1319.       when Accept_Alternative_Selected =>
  1320.  
  1321.          --  Ready to rendezvous
  1322.  
  1323.          Uninterpreted_Data := Self_Id.Common.Call.Uninterpreted_Data;
  1324.  
  1325.          --  In this case the accept body is not Null_Body. Defer abortion
  1326.          --  until it gets into the accept body.
  1327.  
  1328.          pragma Assert (Self_Id.Deferral_Level = 1);
  1329.  
  1330.          Initialization.Defer_Abort_Nestable (Self_Id);
  1331.          STPO.Unlock (Self_Id);
  1332.  
  1333.       when Accept_Alternative_Completed =>
  1334.  
  1335.          --  Accept body is null, so rendezvous is over immediately.
  1336.  
  1337.          STPO.Unlock (Self_Id);
  1338.          Caller := Entry_Call.Self;
  1339.  
  1340.          STPO.Write_Lock (Caller);
  1341.          Initialization.Wakeup_Entry_Caller (Self_Id, Entry_Call, Done);
  1342.          STPO.Unlock (Caller);
  1343.  
  1344.       when Accept_Alternative_Open =>
  1345.  
  1346.          --  Wait for caller.
  1347.  
  1348.          Self_Id.Open_Accepts := Open_Accepts;
  1349.          pragma Debug
  1350.            (Debug.Trace (Self_Id, "Selective_Wait: wait", 'R'));
  1351.          Wait_For_Call (Self_Id);
  1352.  
  1353.          pragma Assert (Self_Id.Open_Accepts = null);
  1354.  
  1355.          --  Self_Id.Common.Call should already be updated by the Caller if
  1356.          --  not aborted. It might also be ready to do rendezvous even if
  1357.          --  this wakes up due to an abortion.
  1358.          --  Therefore, if the call is not empty we need to do the rendezvous
  1359.          --  if the accept body is not Null_Body.
  1360.  
  1361.          --  ?????
  1362.          --  aren't the first two conditions below redundant?
  1363.  
  1364.          if Self_Id.Chosen_Index /= No_Rendezvous and then
  1365.            Self_Id.Common.Call /= null and then
  1366.            not Open_Accepts (Self_Id.Chosen_Index).Null_Body
  1367.          then
  1368.             Uninterpreted_Data := Self_Id.Common.Call.Uninterpreted_Data;
  1369.  
  1370.             pragma Assert (Self_Id.Deferral_Level = 1);
  1371.  
  1372.             Initialization.Defer_Abort_Nestable (Self_Id);
  1373.  
  1374.             --  Leave abort deferred until the accept body
  1375.          end if;
  1376.  
  1377.          STPO.Unlock (Self_Id);
  1378.  
  1379.       when Else_Selected =>
  1380.          pragma Assert (Self_Id.Open_Accepts = null);
  1381.  
  1382.          STPO.Unlock (Self_Id);
  1383.  
  1384.       when Terminate_Selected =>
  1385.  
  1386.          --  Terminate alternative is open
  1387.  
  1388.          Self_Id.Open_Accepts := Open_Accepts;
  1389.          Self_Id.Common.State := Acceptor_Sleep;
  1390.          STPO.Unlock (Self_Id);
  1391.  
  1392.          --  ?????
  1393.          --  We need to check if a signal is pending on an open interrupt
  1394.          --  entry. Otherwise this task would become potentially terminatable
  1395.          --  and, if none of the siblings are active
  1396.          --  any more, the task could not wake up any more, even though a
  1397.          --  signal might be pending on an open interrupt entry.
  1398.          --  -------------
  1399.          --  This comment paragraph does not make sense.  Is it obsolete?
  1400.          --  There was no code here to check for pending signals.
  1401.  
  1402.          --  Notify ancestors that this task is on a terminate alternative.
  1403.  
  1404.          Utilities.Make_Passive (Self_Id, Task_Completed => False);
  1405.  
  1406.          --  Wait for normal entry call or termination
  1407.  
  1408.          pragma Assert (Self_Id.ATC_Nesting_Level = 1);
  1409.  
  1410.          STPO.Write_Lock (Self_Id);
  1411.  
  1412.          loop
  1413.             Initialization.Poll_Base_Priority_Change (Self_Id);
  1414.             exit when Self_Id.Open_Accepts = null;
  1415.             Sleep (Self_Id, Acceptor_Sleep);
  1416.          end loop;
  1417.  
  1418.          Self_Id.Common.State := Runnable;
  1419.  
  1420.          pragma Assert (Self_Id.Open_Accepts = null);
  1421.  
  1422.          if Self_Id.Terminate_Alternative then
  1423.  
  1424.             --  An entry call should have reset this to False,
  1425.             --  so we must be aborted.
  1426.             --  We cannot be in an async. select, since that
  1427.             --  is not legal, so the abort must be of the entire
  1428.             --  task.  Therefore, we do not need to cancel the
  1429.             --  terminate alternative.  The cleanup will be done
  1430.             --  in Complete_Master.
  1431.  
  1432.             pragma Assert (Self_Id.Pending_ATC_Level = 0);
  1433.  
  1434.             pragma Assert (Self_Id.Awake_Count = 0);
  1435.  
  1436.             --  Trust that it is OK to fall through.
  1437.  
  1438.             null;
  1439.  
  1440.          else
  1441.             --  Self_Id.Common.Call and Self_Id.Chosen_Index
  1442.             --  should already be updated by the Caller.
  1443.  
  1444.             if Self_Id.Chosen_Index /= No_Rendezvous
  1445.               and then not Open_Accepts (Self_Id.Chosen_Index).Null_Body
  1446.             then
  1447.                Uninterpreted_Data := Self_Id.Common.Call.Uninterpreted_Data;
  1448.  
  1449.                pragma Assert (Self_Id.Deferral_Level = 1);
  1450.  
  1451.                --  We need an extra defer here, to keep abort
  1452.                --  deferred until we get into the accept body
  1453.  
  1454.                Initialization.Defer_Abort_Nestable (Self_Id);
  1455.             end if;
  1456.          end if;
  1457.  
  1458.          STPO.Unlock (Self_Id);
  1459.  
  1460.       when No_Alternative_Open =>
  1461.  
  1462.          --  In this case, Index will be No_Rendezvous on return, which
  1463.          --  should cause a Program_Error if it is not a Delay_Mode.
  1464.  
  1465.          --  If delay alternative exists (Delay_Mode) we should suspend
  1466.          --  until the delay expires.
  1467.  
  1468.          Self_Id.Open_Accepts := null;
  1469.  
  1470.          if Select_Mode = Delay_Mode then
  1471.             Self_Id.Common.State := Delay_Sleep;
  1472.  
  1473.             loop
  1474.                Initialization.Poll_Base_Priority_Change (Self_Id);
  1475.                exit when Self_Id.Pending_ATC_Level < Self_Id.ATC_Nesting_Level;
  1476.                Sleep (Self_Id, Delay_Sleep);
  1477.             end loop;
  1478.  
  1479.             Self_Id.Common.State := Runnable;
  1480.             STPO.Unlock (Self_Id);
  1481.  
  1482.          else
  1483.             STPO.Unlock (Self_Id);
  1484.             Initialization.Undefer_Abort (Self_Id);
  1485.             Ada.Exceptions.Raise_Exception (Program_Error'Identity,
  1486.               "Entry call not a delay mode");
  1487.          end if;
  1488.  
  1489.       end case;
  1490.  
  1491.       --  Caller has been chosen.
  1492.       --  Self_Id.Common.Call should already be updated by the Caller.
  1493.       --  Self_Id.Chosen_Index should either be updated by the Caller
  1494.       --  or by Test_Selective_Wait.
  1495.       --  On return, we sill start rendezvous unless the accept body is
  1496.       --  null.  In the latter case, we will have already completed the RV.
  1497.  
  1498.       Index := Self_Id.Chosen_Index;
  1499.       Initialization.Undefer_Abort_Nestable (Self_Id);
  1500.  
  1501.    end Selective_Wait;
  1502.  
  1503.    --------------------------
  1504.    -- Timed_Selective_Wait --
  1505.    --------------------------
  1506.  
  1507.    --  Compiler interface only.  Do not call from within the RTS.
  1508.  
  1509.    procedure Timed_Selective_Wait
  1510.      (Open_Accepts       : Accept_List_Access;
  1511.       Select_Mode        : Select_Modes;
  1512.       Uninterpreted_Data : out System.Address;
  1513.       Timeout            : Duration;
  1514.       Mode               : Delay_Modes;
  1515.       Index              : out Select_Index)
  1516.    is
  1517.       Self_Id          : constant Task_ID := STPO.Self;
  1518.       Treatment        : Select_Treatment;
  1519.       Entry_Call       : Entry_Call_Link;
  1520.       Caller           : Task_ID;
  1521.       Selection        : Select_Index;
  1522.       Open_Alternative : Boolean;
  1523.       Timedout         : Boolean := False;
  1524.       Yielded          : Boolean := False;
  1525.    begin
  1526.       pragma Assert (Select_Mode = Delay_Mode);
  1527.  
  1528.       Initialization.Defer_Abort (Self_Id);
  1529.  
  1530.       --  If we are aborted here, the effect will be pending
  1531.  
  1532.       STPO.Write_Lock (Self_Id);
  1533.  
  1534.       if not Self_Id.Callable then
  1535.          pragma Assert (Self_Id.Pending_ATC_Level = 0);
  1536.  
  1537.          pragma Assert (Self_Id.Pending_Action);
  1538.  
  1539.          STPO.Unlock (Self_Id);
  1540.          Initialization.Undefer_Abort (Self_Id);
  1541.  
  1542.          --  Should never get here ???
  1543.  
  1544.          pragma Assert (False);
  1545.          raise Standard'Abort_Signal;
  1546.       end if;
  1547.  
  1548.       --  If someone completed this task, this task should not try to
  1549.       --  access its pending entry calls or queues in this case, as they
  1550.       --  are being emptied. Wait for abortion to kill us.
  1551.       --  ?????
  1552.       --  Recheck the correctness of the above, now that we have made
  1553.       --  changes.
  1554.  
  1555.       pragma Assert (Open_Accepts /= null);
  1556.  
  1557.       Queuing.Select_Task_Entry_Call
  1558.         (Self_Id, Open_Accepts, Entry_Call, Selection, Open_Alternative);
  1559.  
  1560.       --  Determine the kind and disposition of the select.
  1561.  
  1562.       Treatment := Default_Treatment (Select_Mode);
  1563.       Self_Id.Chosen_Index := No_Rendezvous;
  1564.  
  1565.       if Open_Alternative then
  1566.          if Entry_Call /= null then
  1567.             if Open_Accepts (Selection).Null_Body then
  1568.                Treatment := Accept_Alternative_Completed;
  1569.  
  1570.             else
  1571.                Setup_For_Rendezvous_With_Body (Entry_Call, Self_Id);
  1572.                Treatment := Accept_Alternative_Selected;
  1573.             end if;
  1574.  
  1575.             Self_Id.Chosen_Index := Selection;
  1576.  
  1577.          elsif Treatment = No_Alternative_Open then
  1578.             Treatment := Accept_Alternative_Open;
  1579.          end if;
  1580.       end if;
  1581.  
  1582.       --  Handle the select according to the disposition selected above.
  1583.  
  1584.       case Treatment is
  1585.  
  1586.       when Accept_Alternative_Selected =>
  1587.  
  1588.          --  Ready to rendezvous
  1589.          --  In this case the accept body is not Null_Body. Defer abortion
  1590.          --  until it gets into the accept body.
  1591.  
  1592.          Uninterpreted_Data := Self_Id.Common.Call.Uninterpreted_Data;
  1593.          Initialization.Defer_Abort (Self_Id);
  1594.          STPO.Unlock (Self_Id);
  1595.  
  1596.       when Accept_Alternative_Completed =>
  1597.  
  1598.          --  Rendezvous is over
  1599.  
  1600.          STPO.Unlock (Self_Id);
  1601.          Caller := Entry_Call.Self;
  1602.  
  1603.          STPO.Write_Lock (Caller);
  1604.          Initialization.Wakeup_Entry_Caller (Self_Id, Entry_Call, Done);
  1605.          STPO.Unlock (Caller);
  1606.  
  1607.       when Accept_Alternative_Open =>
  1608.  
  1609.          --  Wait for caller.
  1610.  
  1611.          Self_Id.Open_Accepts := Open_Accepts;
  1612.  
  1613.          --  Wait for a normal call and a pending action until the
  1614.          --  Wakeup_Time is reached.
  1615.  
  1616.          Self_Id.Common.State := Acceptor_Sleep;
  1617.  
  1618.          loop
  1619.             Initialization.Poll_Base_Priority_Change (Self_Id);
  1620.             exit when Self_Id.Open_Accepts = null;
  1621.  
  1622.             if Timedout then
  1623.                Sleep (Self_Id, Acceptor_Sleep);
  1624.             else
  1625.                STPO.Timed_Sleep (Self_Id, Timeout, Mode,
  1626.                  Acceptor_Sleep, Timedout, Yielded);
  1627.             end if;
  1628.  
  1629.             if Timedout then
  1630.                Self_Id.Open_Accepts := null;
  1631.             end if;
  1632.          end loop;
  1633.  
  1634.          Self_Id.Common.State := Runnable;
  1635.  
  1636.          --  Self_Id.Common.Call should already be updated by the Caller if
  1637.          --  not aborted. It might also be ready to do rendezvous even if
  1638.          --  this wakes up due to an abortion.
  1639.          --  Therefore, if the call is not empty we need to do the rendezvous
  1640.          --  if the accept body is not Null_Body.
  1641.  
  1642.          if Self_Id.Chosen_Index /= No_Rendezvous and then
  1643.            Self_Id.Common.Call /= null and then
  1644.            not Open_Accepts (Self_Id.Chosen_Index).Null_Body
  1645.          then
  1646.             Uninterpreted_Data := Self_Id.Common.Call.Uninterpreted_Data;
  1647.  
  1648.             pragma Assert (Self_Id.Deferral_Level = 1);
  1649.  
  1650.             Initialization.Defer_Abort_Nestable (Self_Id);
  1651.  
  1652.             --  Leave abort deferred until the accept body
  1653.  
  1654.          end if;
  1655.  
  1656.          STPO.Unlock (Self_Id);
  1657.          if not Yielded then
  1658.             Yield;
  1659.          end if;
  1660.  
  1661.       when No_Alternative_Open =>
  1662.  
  1663.          --  In this case, Index will be No_Rendezvous on return. We sleep
  1664.          --  for the time we need to.
  1665.          --  Wait for a signal or timeout. A wakeup can be made
  1666.          --  for several reasons:
  1667.          --  1) Delay is expired
  1668.          --  2) Pending_Action needs to be checked
  1669.          --     (Abortion, Priority change)
  1670.          --  3) Spurious wakeup
  1671.  
  1672.          Self_Id.Open_Accepts := null;
  1673.          Self_Id.Common.State := Acceptor_Sleep;
  1674.  
  1675.          Initialization.Poll_Base_Priority_Change (Self_Id);
  1676.  
  1677.          STPO.Timed_Sleep (Self_Id, Timeout, Mode, Acceptor_Sleep,
  1678.            Timedout, Yielded);
  1679.  
  1680.          Self_Id.Common.State := Runnable;
  1681.  
  1682.          STPO.Unlock (Self_Id);
  1683.  
  1684.          if not Yielded then
  1685.             Yield;
  1686.          end if;
  1687.  
  1688.       when others =>
  1689.          --  Should never get here ???
  1690.  
  1691.          pragma Assert (False);
  1692.          null;
  1693.       end case;
  1694.  
  1695.       --  Caller has been chosen
  1696.  
  1697.       --  Self_Id.Common.Call should already be updated by the Caller
  1698.  
  1699.       --  Self_Id.Chosen_Index should either be updated by the Caller
  1700.       --  or by Test_Selective_Wait
  1701.  
  1702.       Index := Self_Id.Chosen_Index;
  1703.       Initialization.Undefer_Abort_Nestable (Self_Id);
  1704.  
  1705.       --  Start rendezvous, if not already completed
  1706.  
  1707.    end Timed_Selective_Wait;
  1708.  
  1709.    ----------------
  1710.    -- Task_Count --
  1711.    ----------------
  1712.  
  1713.    --  Compiler interface only.  Do not call from within the RTS.
  1714.  
  1715.    function Task_Count (E : Task_Entry_Index) return Natural is
  1716.       Self_Id      : constant Task_ID := STPO.Self;
  1717.       Return_Count : Natural;
  1718.  
  1719.    begin
  1720.       Initialization.Defer_Abort (Self_Id);
  1721.       STPO.Write_Lock (Self_Id);
  1722.       Return_Count := Queuing.Count_Waiting (Self_Id.Entry_Queues (E));
  1723.       STPO.Unlock (Self_Id);
  1724.       Initialization.Undefer_Abort (Self_Id);
  1725.       return Return_Count;
  1726.    end Task_Count;
  1727.  
  1728.    --------------
  1729.    -- Callable --
  1730.    --------------
  1731.  
  1732.    --  Compiler interface.
  1733.    --  Do not call from within the RTS,
  1734.    --  except for body of Ada.Task_Identification.
  1735.  
  1736.    function Callable (T : Task_ID) return Boolean is
  1737.       Result  : Boolean;
  1738.       Self_Id : constant Task_ID := STPO.Self;
  1739.  
  1740.    begin
  1741.       Initialization.Defer_Abort (Self_Id);
  1742.       STPO.Write_Lock (T);
  1743.       Result := T.Callable;
  1744.       STPO.Unlock (T);
  1745.       Initialization.Undefer_Abort (Self_Id);
  1746.       return Result;
  1747.    end Callable;
  1748.  
  1749.    -------------------
  1750.    -- Is_Entry_Open --
  1751.    -------------------
  1752.  
  1753.    --  Call this only with abort deferred and holding lock of T.
  1754.  
  1755.    function Is_Entry_Open (T : Task_ID; E : Task_Entry_Index) return Boolean is
  1756.    begin
  1757.       pragma Assert (T.Open_Accepts /= null);
  1758.  
  1759.       if T.Open_Accepts /= null then
  1760.          for J in T.Open_Accepts'Range loop
  1761.  
  1762.             pragma Assert (J > 0);
  1763.  
  1764.             if E = T.Open_Accepts (J).S then
  1765.                return True;
  1766.             end if;
  1767.          end loop;
  1768.       end if;
  1769.  
  1770.       return False;
  1771.    end Is_Entry_Open;
  1772.  
  1773.    -----------------------
  1774.    -- Task_Entry_Caller --
  1775.    -----------------------
  1776.  
  1777.    --  Compiler interface only.
  1778.  
  1779.    function Task_Entry_Caller (D : Task_Entry_Nesting_Depth) return Task_ID is
  1780.       Self_Id    : constant Task_ID := STPO.Self;
  1781.       Entry_Call : Entry_Call_Link;
  1782.  
  1783.    begin
  1784.       Entry_Call := Self_Id.Common.Call;
  1785.       for Depth in 1 .. D loop
  1786.          Entry_Call := Entry_Call.Acceptor_Prev_Call;
  1787.          pragma Assert (Entry_Call /= null);
  1788.       end loop;
  1789.  
  1790.       return Entry_Call.Self;
  1791.    end Task_Entry_Caller;
  1792.  
  1793.    -------------------
  1794.    -- Wait_For_Call --
  1795.    -------------------
  1796.  
  1797.    --  Call this only with abort deferred and holding lock of Self_Id.
  1798.    --  Wait for normal call and a pending action.
  1799.  
  1800.    procedure Wait_For_Call (Self_Id : Task_ID) is
  1801.    begin
  1802.       Self_Id.Common.State := Acceptor_Sleep;
  1803.  
  1804.       loop
  1805.          Initialization.Poll_Base_Priority_Change (Self_Id);
  1806.  
  1807.          exit when Self_Id.Open_Accepts = null;
  1808.  
  1809.          Sleep (Self_Id, Acceptor_Sleep);
  1810.       end loop;
  1811.  
  1812.       Self_Id.Common.State := Runnable;
  1813.    end Wait_For_Call;
  1814.  
  1815. end System.Tasking.Rendezvous;
  1816.