home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / s-tasuti.adb < prev    next >
Text File  |  1996-09-28  |  23KB  |  703 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                 GNU ADA RUNTIME LIBRARY (GNARL) COMPONENTS               --
  4. --                                                                          --
  5. --              S Y S T E M . T A S K I N G . U T I L I T I E S             --
  6. --                                                                          --
  7. --                                  B o d y                                 --
  8. --                                                                          --
  9. --                             $Revision: 1.15 $                            --
  10. --                                                                          --
  11. --     Copyright (c) 1991,1992,1993,1994,1995 FSU, All Rights Reserved      --
  12. --                                                                          --
  13. -- GNARL is free software; you can redistribute it  and/or modify it  under --
  14. -- terms  of  the  GNU  Library General Public License  as published by the --
  15. -- Free Software  Foundation;  either version 2, or (at  your  option)  any --
  16. -- later  version.  GNARL is distributed  in the hope that  it will be use- --
  17. -- ful, but but WITHOUT ANY WARRANTY;  without even the implied warranty of --
  18. -- MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Gen- --
  19. -- eral Library Public License  for more details.  You should have received --
  20. -- a  copy of the GNU Library General Public License along with GNARL;  see --
  21. -- file COPYING.LIB.  If not,  write to the  Free Software Foundation,  675 --
  22. -- Mass Ave, Cambridge, MA 02139, USA.                                      --
  23. --                                                                          --
  24. ------------------------------------------------------------------------------
  25.  
  26. --  This package provides RTS Internal Declarations.
  27. --  These declarations are not part of the GNARLI
  28.  
  29. with System.Task_Primitives;  use System.Task_Primitives;
  30.  
  31. with System.Compiler_Exceptions;
  32. --  Used for, Tasking_Error_ID
  33.  
  34. with System.Tasking.Abortion;
  35. --  Used for, Undefer_Abortion,
  36. --            Abort_To_Level
  37.  
  38. with System.Tasking.Queuing; use System.Tasking.Queuing;
  39. --  Used for, Queuing.Dequeue_Head
  40.  
  41. with System.Tasking.Entry_Calls;
  42. --  Used for, Lock_Server
  43. --            Unlock_Server
  44. --            Dequeue_Call
  45.  
  46. with System.Tasking.Initialization;
  47. --  Used for, Remove_From_All_Tasks_List
  48. --            All_Tasks_L
  49. --            All_Tasks_List
  50.  
  51. package body System.Tasking.Utilities is
  52.  
  53.    -----------------------
  54.    -- Local Subprograms --
  55.    -----------------------
  56.  
  57.    procedure Make_Passive
  58.      (T : Task_ID);
  59.    --  Record that task T is passive.
  60.  
  61.    procedure Close_Entries (Target : Task_ID);
  62.    --  Close entries, purge entry queues (called by Task_Stages.Complete)
  63.    --  T.Stage must be Completing before this is called.
  64.  
  65.    ------------------------------------
  66.    -- Vulnerable_Complete_Activation --
  67.    ------------------------------------
  68.  
  69.    --  WARNING : Only call this procedure with abortion deferred.
  70.    --  That's why the name has "Vulnerable" in it.
  71.  
  72.    procedure Vulnerable_Complete_Activation
  73.      (T : Task_ID;
  74.       Completed : Boolean)
  75.    is
  76.       Activator : Task_ID;
  77.       Error     : Boolean;
  78.  
  79.    begin
  80.       Activator := T.Activator;
  81.  
  82.       if Activator /= Null_Task then
  83.       --  Should only be null for the environment task.
  84.  
  85.          --  Decrement the count of tasks to be activated by the
  86.          --  activator and wake it up so it can check to see if
  87.          --  all tasks have been activated. Note that the locks
  88.          --  of the activator and created task are locked here.
  89.          --  This is necessary because C.Stage and
  90.          --  T.Activation_Count have to be synchronized. This is
  91.          --  also done in Activate_Tasks and Init_Abortion. So
  92.          --  long as the activator lock is always locked first,
  93.          --  this cannot lead to deadlock.
  94.  
  95.          Write_Lock (Activator.L, Error);
  96.          Write_Lock (T.L, Error);
  97.  
  98.          if T.Stage = Can_Activate then
  99.             T.Stage := Active;
  100.             Activator.Activation_Count := Activator.Activation_Count - 1;
  101.             Cond_Signal (Activator.Cond);
  102.             if Completed then
  103.                Activator.Exception_To_Raise :=
  104.                  Compiler_Exceptions.Tasking_Error_ID;
  105.             end if;
  106.          end if;
  107.          Unlock (T.L);
  108.          Unlock (Activator.L);
  109.  
  110.       end if;
  111.  
  112.    end Vulnerable_Complete_Activation;
  113.  
  114.    --  PO related routines
  115.  
  116.    ---------------------
  117.    -- Check_Exception --
  118.    ---------------------
  119.  
  120.    procedure Check_Exception is
  121.       T  : Task_ID := Self;
  122.       Ex : System.Compiler_Exceptions.Exception_ID := T.Exception_To_Raise;
  123.  
  124.    begin
  125.       T.Exception_To_Raise := System.Compiler_Exceptions.Null_Exception;
  126.       System.Compiler_Exceptions.Raise_Exception (Ex);
  127.    end Check_Exception;
  128.  
  129.    --  Rendezvous related routines
  130.  
  131.    -------------------
  132.    -- Close_Entries --
  133.    -------------------
  134.  
  135.    procedure Close_Entries (Target : Task_ID) is
  136.       T                : Task_ID := Target;
  137.       Temp_Call        : Entry_Call_Link;
  138.       Null_Call        : Entry_Call_Link := null;
  139.       Temp_Caller      : Task_ID;
  140.       Temp_Called_Task : Task_ID;
  141.       TAS_Result       : Boolean;
  142.       Error            : Boolean;
  143.  
  144.    begin
  145.       --  Purging pending callers that are in the middle of rendezvous
  146.  
  147.       Temp_Call := T.Call;
  148.  
  149.       while Temp_Call /= null loop
  150.          Temp_Call.Exception_To_Raise := Compiler_Exceptions.Tasking_Error_ID;
  151.  
  152.          Temp_Caller := Temp_Call.Self;
  153.  
  154.          --  All forms of accept make sure that the acceptor is not
  155.          --  begin completed before accepting further calls, so that we
  156.          --  can be sure that no further calls are made after the the
  157.          --  current calls are purged.
  158.  
  159.          Write_Lock (Temp_Caller.L, Error);
  160.          Temp_Call.Done := True;
  161.          Unlock (Temp_Caller.L);
  162.  
  163.          --  Cancel the call.
  164.  
  165.          Abort_To_Level (Temp_Caller, Temp_Call.Level - 1);
  166.  
  167.  
  168.          Temp_Call := Temp_Call.Acceptor_Prev_Call;
  169.       end loop;
  170.  
  171.       --  Purging entry queues
  172.  
  173.       Write_Lock (T.L, Error);
  174.       for J in 1 .. T.Entry_Num loop
  175.          Dequeue_Head (T.Entry_Queues (J), Temp_Call);
  176.          while Temp_Call /= Null_Call loop
  177.             Temp_Caller := Temp_Call.Self;
  178.             Temp_Call.Exception_To_Raise :=
  179.               Compiler_Exceptions.Tasking_Error_ID;
  180.             Abort_To_Level (Temp_Caller, Temp_Call.Level - 1);
  181.             Dequeue_Head (T.Entry_Queues (J), Temp_Call);
  182.          end loop;
  183.       end loop;
  184.       Unlock (T.L);
  185.  
  186.       --  If T is calling an entry, an immediate attempt must be made
  187.       --  to cancel the call.  This can only occur if T is being aborted,
  188.       --  and abortion itself amounts to an immediate attempt to cancel
  189.       --  the call.  T will cancel the call (if possible) when awakened by
  190.       --  the abortion.  There is no way for the application code to tell
  191.       --  whether this happened immediately; all that matters is that
  192.       --  the call not succeed if it is queued abortably at this point.
  193.  
  194.       --  ??? The above is nonsense.  Another task can tell by checking
  195.       --      'Count of the called entries.
  196.  
  197.    end Close_Entries;
  198.  
  199.    ----------------------------
  200.    -- Complete_On_Sync_Point --
  201.    ----------------------------
  202.  
  203.    procedure Complete_on_Sync_Point (T : Task_ID) is
  204.       Target    : Task_ID := T;
  205.       Call      : Entry_Call_Link;
  206.       Error     : Boolean;
  207.       No_Server : Boolean;
  208.  
  209.    begin
  210.       Write_Lock (Target.L, Error);
  211.  
  212.       --  If the target is waiting to accept an entry call, complete it.
  213.  
  214.       if Target.Accepting /= Not_Accepting then
  215.          Unlock (Target.L);
  216.          Complete (T);
  217.       else
  218.          Unlock (Target.L);
  219.       end if;
  220.  
  221.       --  Abort all pending entry calls in LIFO order until a non-abortable
  222.       --  one is found.
  223.  
  224.       for Level in reverse
  225.         ATC_Level_Index'First .. Target.ATC_Nesting_Level
  226.       loop
  227.          Call := Target.Entry_Calls (Level)'Access;
  228.          System.Tasking.Entry_Calls.Lock_Server (Call, No_Server);
  229.          if not No_Server then
  230.             if Call.Abortable then
  231.                System.Tasking.Entry_Calls.Dequeue_Call (Call);
  232.                System.Tasking.Entry_Calls.Unlock_And_Update_Server (Call);
  233.             else
  234.                System.Tasking.Entry_Calls.Unlock_Server (Call);
  235.                exit;
  236.             end if;
  237.          end if;
  238.       end loop;
  239.  
  240.    end Complete_on_Sync_Point;
  241.  
  242.    --------------------
  243.    -- Reset_Priority --
  244.    --------------------
  245.  
  246.    procedure Reset_Priority
  247.      (Acceptor_Prev_Priority : Rendezvous_Priority;
  248.        Acceptor              : Task_ID)
  249.    is
  250.       Acceptor_ATCB : Task_ID := Acceptor;
  251.  
  252.    begin
  253.       if Acceptor_Prev_Priority /= Priority_Not_Boosted then
  254.          Acceptor_ATCB.Current_Priority := Acceptor_Prev_Priority;
  255.          Set_Priority
  256.            (Acceptor_ATCB.LL_TCB'Access, Acceptor_ATCB.Current_Priority);
  257.       end if;
  258.    end Reset_Priority;
  259.  
  260.    ---------------------------
  261.    -- Terminate_Alternative --
  262.    ---------------------------
  263.  
  264.    --  WARNING : Only call this procedure with abortion deferred. This
  265.    --  procedure needs to have abortion deferred while it has the current
  266.    --  task's lock locked. Since it is called from two procedures which
  267.    --  also need abortion deferred, it is left controlled on entry to
  268.    --  this procedure.
  269.  
  270.    procedure Terminate_Alternative is
  271.       T     : Task_ID := Self;
  272.       Taken : Boolean;
  273.       Error : Boolean;
  274.  
  275.    begin
  276.       Make_Passive (T);
  277.  
  278.       --  Note that abortion is deferred here (see WARNING above)
  279.  
  280.       Write_Lock (T.L, Error);
  281.  
  282.       T.Terminate_Alternative := true;
  283.  
  284.       while T.Accepting /= Not_Accepting
  285.         and then T.Stage /= Complete
  286.         and then T.Pending_ATC_Level >= T.ATC_Nesting_Level
  287.       loop
  288.          Cond_Wait (T.Cond, T.L);
  289.       end loop;
  290.  
  291.       if T.Stage = Complete then
  292.          Unlock (T.L);
  293.  
  294.          if T.Pending_ATC_Level < T.ATC_Nesting_Level then
  295.             Abortion.Undefer_Abortion;
  296.             pragma Assert
  297.               (Runtime_Assert_Shutdown ("Continuing after being aborted!"));
  298.          end if;
  299.  
  300.          Abort_To_Level (T, 0);
  301.          Abortion.Undefer_Abortion;
  302.          pragma Assert
  303.            (Runtime_Assert_Shutdown ("Continuing after being aborted!"));
  304.       end if;
  305.  
  306.       T.Terminate_Alternative := false;
  307.  
  308.       Unlock (T.L);
  309.  
  310.    end Terminate_Alternative;
  311.  
  312.    --------------
  313.    -- Complete --
  314.    --------------
  315.  
  316.    procedure Complete (Target : Task_ID) is
  317.       T      : Task_ID := Target;
  318.       Caller : Task_ID := Self;
  319.       Task1  : Task_ID;
  320.       Task2  : Task_ID;
  321.       Error  : Boolean;
  322.  
  323.    begin
  324.       Make_Passive (T);
  325.       Write_Lock (T.L, Error);
  326.  
  327.       if T.Stage < Completing then
  328.          T.Stage := Completing;
  329.          T.Accepting := Not_Accepting;
  330.          T.Awaited_Dependent_Count := 0;
  331.          Unlock (T.L);
  332.          Close_Entries (T);
  333.          T.Stage := Complete;
  334.  
  335.          --  Wake up all the pending calls on Aborter_Link list
  336.  
  337.          Task1 := T.Aborter_Link;
  338.          T.Aborter_Link := Null_Task;
  339.  
  340.          while (Task1 /= Null_Task) loop
  341.             Task2 := Task1;
  342.             Task1 := Task1.Aborter_Link;
  343.             Task2.Aborter_Link := Null_Task;
  344.             Cond_Signal (Task2.Cond);
  345.          end loop;
  346.  
  347.       else
  348.          --  Some other task is completing this task. So just wait until
  349.          --  the completion is done. A list of such waiting tasks is
  350.          --  maintained by Aborter_Link in ATCB.
  351.  
  352.          while T.Stage < Complete loop
  353.             if T.Aborter_Link /= Null_Task then
  354.                Caller.Aborter_Link := T.Aborter_Link;
  355.             end if;
  356.  
  357.             T.Aborter_Link := Caller;
  358.             Cond_Wait (Caller.Cond, T.L);
  359.          end loop;
  360.  
  361.          Unlock (T.L);
  362.       end if;
  363.    end Complete;
  364.  
  365.    --  Task_Stage related routines
  366.  
  367.    ----------------------
  368.    -- Make_Independent --
  369.    ----------------------
  370.  
  371.    procedure Make_Independent is
  372.       T : Task_ID := Self;
  373.       P : Task_ID;
  374.       Result : Boolean;
  375.       Error  : Boolean;
  376.    begin
  377.       Write_Lock (T.L, Error);
  378.       P := T.Parent;
  379.       Unlock (T.L);
  380.  
  381.       Write_Lock (P.L, Error);
  382.       Write_Lock (T.L, Error);
  383.  
  384.       T.Master_of_Task := Master_ID (0);
  385.  
  386.       if P.Awake_Count > 1 then
  387.          P.Awake_Count := P.Awake_Count - 1;
  388.       end if;
  389.  
  390.       Unlock (T.L);
  391.       Unlock (P.L);
  392.  
  393.       System.Tasking.Initialization.Remove_From_All_Tasks_List (T, Result);
  394.       pragma Assert (
  395.         Result or else Runtime_Assert_Shutdown (
  396.           "Failed to delete an entry from All_Tasks_List"));
  397.  
  398.    end Make_Independent;
  399.  
  400.    --  Task Abortion related routines
  401.  
  402.    --------------------
  403.    -- Abort_To_Level --
  404.    --------------------
  405.  
  406.    procedure Abort_To_Level
  407.      (Target : Task_ID;
  408.       L      : ATC_Level)
  409.    is
  410.       T      : Task_ID := Target;
  411.       Error  : Boolean;
  412.  
  413.    begin
  414.       Write_Lock (T.L, Error);
  415.  
  416.       --  If the task is suspended on a condition variable, it will
  417.       --  be in an abort-deferred region, and will not be awakened
  418.       --  by abortion. Such an abort deferral is just to protect
  419.       --  the low-level operations, and not to enforce Ada semantics.
  420.       --  Wake the task up and let it decide if it wants to
  421.       --  complete the aborted construct immediately.  This is done
  422.       --  unconditionally, since a Cond_Signal is not persistent, and
  423.       --  is needed even if the task has been aborted before.
  424.  
  425.       Cond_Signal (T.Cond);
  426.  
  427.       if T.Pending_ATC_Level > L then
  428.          T.Pending_ATC_Level := L;
  429.          T.Pending_Action := True;
  430.  
  431.          if not T.Aborting then
  432.             T.Aborting := True;
  433.  
  434.             --  If this task is aborting itself, it should unlock itself
  435.             --  before calling abort, as it is unlikely to have the
  436.             --  opportunity to do so afterwords. On the other hand, if
  437.             --  another task is being aborted, we want to make sure it is
  438.             --  not terminated, since there is no need to abort a terminated
  439.             --  task, and it may be illegal if it has stopped executing.
  440.             --  In this case, the Abort_Task must take place under the
  441.             --  protection of the mutex, so we know that Stage/=Terminated.
  442.  
  443.             if Target =  Self then
  444.                Unlock (T.L);
  445.                Abort_Task (T.LL_TCB'Access);
  446.                return;
  447.  
  448.             elsif T.Stage /= Terminated then
  449.                Abort_Task (T.LL_TCB'Access);
  450.             end if;
  451.  
  452.          end if;
  453.       end if;
  454.  
  455.       Unlock (T.L);
  456.  
  457.    end Abort_To_Level;
  458.  
  459.    -------------------
  460.    -- Abort_Handler --
  461.    -------------------
  462.  
  463.    procedure Abort_Handler
  464.      (Context : Task_Primitives.Pre_Call_State)
  465.    is
  466.       T : Task_ID := Self;
  467.  
  468.    begin
  469.       if T.Deferral_Level = 0
  470.         and then T.Pending_ATC_Level < T.ATC_Nesting_Level
  471.       then
  472.  
  473.          --  ???  This is implementation dependent.  Some implementations
  474.          --       might not allow an exception to be propagated out of a
  475.          --       handler, and others might leave the signal or interrupt
  476.          --       that invoked this handler masked after the exceptional
  477.          --       return to the application code.
  478.          --       GNAT exceptions are originally implemented using
  479.          --       setjmp()/longjmp().  On most UNIX systems, this will
  480.          --       allow transfer out of a signal handler, which is
  481.          --       usually the only mechanism available for implementing
  482.          --       asynchronous handlers of this kind.  However, some
  483.          --       systems do not restore the signal mask, leaving the
  484.          --       abortion signal masked.
  485.          --       Possible solutions:
  486.          --
  487.          --       1. Change the PC saved in the system-dependent Context
  488.          --          parameter to point to code that raises the exception.
  489.          --          Normal return from this handler will then raise
  490.          --          the exception after the mask and other system state has
  491.          --          been restored.
  492.          --       2. Use siglongjmp()/sigsetjmp() to implement exceptions.
  493.          --       3. Unmask the signal in the Abortion exception handler
  494.          --          (in the RTS).
  495.  
  496.          raise Standard'Abort_Signal;
  497.  
  498.       end if;
  499.    end Abort_Handler;
  500.  
  501.    ----------------------
  502.    -- Abort_Dependents --
  503.    ----------------------
  504.  
  505.    --  Process abortion of child tasks.
  506.  
  507.    --  Abortion should be dererred when calling this routine.
  508.    --  No mutexes should be locked when calling this routine.
  509.  
  510.    procedure Abort_Dependents (Abortee : Task_ID) is
  511.       Temp_T                : Task_ID;
  512.       Temp_P                : Task_ID;
  513.       Old_Pending_ATC_Level : ATC_Level_Base;
  514.       TAS_Result            : Boolean;
  515.       A                     : Task_ID := Abortee;
  516.       Error                 : Boolean;
  517.  
  518.    begin
  519.       Write_Lock (System.Tasking.Initialization.All_Tasks_L, Error);
  520.       Temp_T := System.Tasking.Initialization.All_Tasks_List;
  521.  
  522.       while Temp_T /= Null_Task loop
  523.          Temp_P := Temp_T.Parent;
  524.  
  525.          while Temp_P /= Null_Task loop
  526.             exit when Temp_P = A;
  527.             Temp_P := Temp_P.Parent;
  528.          end loop;
  529.  
  530.          if Temp_P = A then
  531.             Temp_T.Accepting := Not_Accepting;
  532.  
  533.             --  Send cancel signal.
  534.             Complete_on_Sync_Point (Temp_T);
  535.             Abort_To_Level (Temp_T, 0);
  536.          end if;
  537.  
  538.          Temp_T := Temp_T.All_Tasks_Link;
  539.       end loop;
  540.  
  541.       Unlock (System.Tasking.Initialization.All_Tasks_L);
  542.  
  543.    end Abort_Dependents;
  544.  
  545.    ------------------
  546.    -- Make_Passive --
  547.    ------------------
  548.  
  549.    --  If T is the last dependent of some master in task P to become passive,
  550.    --  then release P. A special case of this is when T has no dependents
  551.    --  and is completed. In this case, T itself should be released.
  552.  
  553.    --  If the parent is made passive, this is repeated recursively, with C
  554.    --  being the previous parent and P being the next parent up.
  555.  
  556.    --  Note that we have to hold the locks of both P and C (locked in that
  557.    --  order) so that the Awake_Count of C and the Awaited_Dependent_Count of
  558.    --  P will be synchronized. Otherwise, an attempt by P to terminate can
  559.    --  preempt this routine after C's Awake_Count has been decremented to zero
  560.    --  but before C has checked the Awaited_Dependent_Count of P. P would not
  561.    --  count C in its Awaited_Dependent_Count since it is not awake, but it
  562.    --  might count other awake dependents. When C gained control again, it
  563.    --  would decrement P's Awaited_Dependent_Count to indicate that it is
  564.    --  passive, even though it was never counted as active. This would cause
  565.    --  P to wake up before all of its dependents are passive.
  566.  
  567.    --  Note : Any task with an interrupt entry should never become passive.
  568.    --  Support for this feature needs to be added here.
  569.  
  570.    procedure Make_Passive (T : Task_ID) is
  571.       P : Task_ID;
  572.       --  Task whose Awaited_Dependent_Count may be decremented.
  573.  
  574.       C : Task_ID;
  575.       --  Task whose awake-count gets decremented.
  576.  
  577.       H : Task_ID;
  578.       --  Highest task that is ready to terminate dependents.
  579.  
  580.       Taken     : Boolean;
  581.       Activator : Task_ID;
  582.       Error     : Boolean;
  583.  
  584.    begin
  585.       Utilities.Vulnerable_Complete_Activation (T, Completed => False);
  586.  
  587.       Write_Lock (T.L, Error);
  588.  
  589.       if T.Stage >= Passive then
  590.          Unlock (T.L);
  591.          return;
  592.       else
  593.          T.Stage := Passive;
  594.          Unlock (T.L);
  595.       end if;
  596.  
  597.       H := Null_Task;
  598.       P := T.Parent;
  599.       C := T;
  600.  
  601.       while C /= Null_Task loop
  602.  
  603.          if P /= Null_Task then
  604.             Write_Lock (P.L, Error);
  605.             Write_Lock (C.L, Error);
  606.  
  607.             C.Awake_Count := C.Awake_Count - 1;
  608.  
  609.             if C.Awake_Count /= 0 then
  610.  
  611.                --  C is not passive; we cannot make anything above this point
  612.                --  passive.
  613.  
  614.                Unlock (C.L);
  615.                Unlock (P.L);
  616.                exit;
  617.             end if;
  618.  
  619.             if P.Awaited_Dependent_Count /= 0 then
  620.  
  621.                --  We have hit a non-task master; we will not be able to make
  622.                --  anything above this point passive.
  623.  
  624.                P.Awake_Count := P.Awake_Count - 1;
  625.  
  626.                if C.Master_of_Task = P.Master_Within then
  627.                   P.Awaited_Dependent_Count := P.Awaited_Dependent_Count - 1;
  628.  
  629.                   if P.Awaited_Dependent_Count = 0 then
  630.                      H := P;
  631.                   end if;
  632.                end if;
  633.  
  634.                Unlock (C.L);
  635.                Unlock (P.L);
  636.                exit;
  637.             end if;
  638.  
  639.             if C.Stage = Complete then
  640.  
  641.                --  C is both passive (Awake_Count = 0) and complete; wake it
  642.                --  up to await termination of its dependents. It will not be
  643.                --  complete if it is waiting on a terminate alternative. Such
  644.                --  a task is not ready to wait for its dependents to terminate,
  645.                --  though one of its ancestors may be.
  646.  
  647.                H := C;
  648.             end if;
  649.  
  650.             Unlock (C.L);
  651.             Unlock (P.L);
  652.             C := P;
  653.             P := C.Parent;
  654.  
  655.          else
  656.             Write_Lock (C.L, Error);
  657.             C.Awake_Count := C.Awake_Count - 1;
  658.  
  659.             if C.Awake_Count /= 0 then
  660.  
  661.                --  C is not passive; we cannot make anything above
  662.                --  this point passive.
  663.  
  664.                Unlock (C.L);
  665.                exit;
  666.             end if;
  667.  
  668.             if C.Stage = Complete then
  669.  
  670.                --  C is both passive (Awake_Count = 0) and complete; wake it
  671.                --  up to await termination of its dependents. It will not be
  672.                --  complete if it is waiting on a terminate alternative. Such
  673.                --  a task is not ready to wait for its dependents to terminate,
  674.                --  though one of its ancestors may be.
  675.  
  676.                H := C;
  677.             end if;
  678.  
  679.             Unlock (C.L);
  680.             C := P;
  681.          end if;
  682.  
  683.       end loop;
  684.  
  685.       if H /= Null_Task then
  686.          Cond_Signal (H.Cond);
  687.       end if;
  688.  
  689.    end Make_Passive;
  690.  
  691.    -----------------------------
  692.    -- Runtime_Assert_Shutdown --
  693.    -----------------------------
  694.  
  695.    function Runtime_Assert_Shutdown (Msg : in String) return boolean is
  696.    begin
  697.       LL_Assert (false, Msg);
  698.       --  This call should never return
  699.       return false;
  700.    end Runtime_Assert_Shutdown;
  701.  
  702. end System.Tasking.Utilities;
  703.