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-tasque.adb < prev    next >
Text File  |  1996-09-28  |  10KB  |  349 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 . Q U E U I N G              --
  6. --                                                                          --
  7. --                                  B o d y                                 --
  8. --                                                                          --
  9. --                             $Revision: 1.14 $                            --
  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. with System.Task_Primitives; use System.Task_Primitives;
  27.  
  28. with System.Tasking.Utilities;
  29. --  Used for Abort_To_Level
  30.  
  31. package body System.Tasking.Queuing is
  32.  
  33.    --  Entry Queues implemented as doubly linked list, priority ordered
  34.  
  35.    procedure Send_Program_Error (Entry_Call : Entry_Call_Link);
  36.    --  Raise Program_Error in the caller of the specified entry
  37.    --  call.
  38.  
  39.    ------------------------
  40.    -- Send_Program_Error --
  41.    ------------------------
  42.  
  43.    procedure Send_Program_Error (Entry_Call : Entry_Call_Link) is
  44.       Current_Task  : Task_ID;
  45.       Error : Boolean;
  46.    begin
  47.       Current_Task := Entry_Call.Self;
  48.       Entry_Call.Exception_To_Raise :=
  49.         System.Compiler_Exceptions.Program_Error_ID;
  50.       Write_Lock (Current_Task.L, Error);
  51.       Entry_Call.Done := True;
  52.       Unlock (Current_Task.L);
  53.       Utilities.Abort_To_Level
  54.         (Current_Task, Entry_Call.Level - 1);
  55.    end Send_Program_Error;
  56.  
  57.    -----------------------------
  58.    -- Broadcast_Program_Error --
  59.    -----------------------------
  60.  
  61.    procedure Broadcast_Program_Error
  62.      (Object : access Protection;
  63.       Pending_Call : Entry_Call_Link)
  64.    is
  65.       Entry_Call    : Entry_Call_Link;
  66.  
  67.    begin
  68.       if Pending_Call /= null then
  69.          Send_Program_Error (Pending_Call);
  70.       end if;
  71.  
  72.       for E in Object.Entry_Queues'Range loop
  73.          Dequeue_Head (Object.Entry_Queues (E), Entry_Call);
  74.  
  75.          while Entry_Call /= null loop
  76.             pragma Assert (Entry_Call.Mode /= Conditional_Call or else
  77.               Utilities.Runtime_Assert_Shutdown (
  78.                 "Conditional call found on entry queue."));
  79.             Send_Program_Error (Entry_Call);
  80.             Dequeue_Head (Object.Entry_Queues (E), Entry_Call);
  81.          end loop;
  82.       end loop;
  83.    end Broadcast_Program_Error;
  84.  
  85.    -------------
  86.    -- Enqueue --
  87.    -------------
  88.  
  89.    --  Enqueue call priority ordered, FIFO at same priority level
  90.  
  91.    procedure Enqueue (E : in out Entry_Queue; Call : Entry_Call_Link) is
  92.       Temp : Entry_Call_Link := E.Head;
  93.    begin
  94.       if Temp = null then
  95.          Call.Prev := Call;
  96.          Call.Next := Call;
  97.          E.Head := Call;
  98.          E.Tail := Call;
  99.       else
  100.          loop  --  find the entry that the new guy should precede
  101.             exit when Call.Prio > Temp.Prio;
  102.             Temp := Temp.Next;
  103.             if Temp = E.Head then
  104.                Temp := null;
  105.                exit;
  106.             end if;
  107.          end loop;
  108.  
  109.          if Temp = null then -- insert at tail
  110.             Call.Prev := E.Tail;
  111.             Call.Next := E.Head;
  112.             E.Tail := Call;
  113.          else
  114.             Call.Prev := Temp.Prev;
  115.             Call.Next := Temp;
  116.  
  117.             if Temp = E.Head then -- insert at head
  118.                E.Head := Call;
  119.             end if;
  120.          end if;
  121.  
  122.          Call.Prev.Next := Call;
  123.          Call.Next.Prev := Call;
  124.  
  125.       end if;
  126.    end Enqueue;
  127.  
  128.    -------------
  129.    -- Dequeue --
  130.    -------------
  131.  
  132.    --  Dequeue call from entry_queue E
  133.  
  134.    procedure Dequeue (E : in out Entry_Queue; Call : Entry_Call_Link) is
  135.       Prev : Entry_Call_Link;
  136.  
  137.    begin
  138.       --  If empty queue, simply return
  139.  
  140.       if E.Head = null then
  141.          return;
  142.       end if;
  143.  
  144.       Call.Prev.Next := Call.Next;
  145.       Call.Next.Prev := Call.Prev;
  146.  
  147.       if E.Head = Call then
  148.          if E.Tail = Call then
  149.             E.Head := null; --  case of one element
  150.             E.Tail := null;
  151.          else
  152.             E.Head := Call.Next;
  153.          end if;
  154.       elsif E.Tail = Call then
  155.          E.Tail := Call.Prev;
  156.       end if;
  157.  
  158.       --  Successfully dequeued
  159.  
  160.       Call.Prev := null;
  161.       Call.Next := null;
  162.  
  163.    end Dequeue;
  164.  
  165.    ----------
  166.    -- Head --
  167.    ----------
  168.  
  169.    --  Return the head of entry_queue E
  170.  
  171.    function Head (E : in Entry_Queue) return Entry_Call_Link is
  172.    begin
  173.       return E.Head;
  174.    end Head;
  175.  
  176.    ------------------
  177.    -- Dequeue_Head --
  178.    ------------------
  179.  
  180.    --  Remove and return the head of entry_queue E
  181.  
  182.    procedure Dequeue_Head
  183.      (E    : in out Entry_Queue;
  184.       Call : out Entry_Call_Link)
  185.    is
  186.       Temp : Entry_Call_Link;
  187.  
  188.    begin
  189.       --  If empty queue, return null pointer
  190.  
  191.       if E.Head = null then
  192.          Call := null;
  193.          return;
  194.       end if;
  195.  
  196.       Temp := E.Head;
  197.  
  198.       if E.Head = E.Tail then
  199.          E.Head := null; --  case of one element
  200.          E.Tail := null;
  201.       else
  202.          E.Head := Temp.Next;
  203.          Temp.Prev.Next := Temp.Next;
  204.          Temp.Next.Prev := Temp.Prev;
  205.       end if;
  206.  
  207.       --  Successfully dequeued
  208.  
  209.       Temp.Prev := null;
  210.       Temp.Next := null;
  211.       Call := Temp;
  212.    end Dequeue_Head;
  213.  
  214.    -------------
  215.    -- Onqueue --
  216.    -------------
  217.  
  218.    --  Return True if Call is on any entry_queue at all
  219.  
  220.    function Onqueue (Call : Entry_Call_Link) return Boolean is
  221.    begin
  222.       --  Utilize the fact that every queue is circular, so if Call
  223.       --  is on any queue at all, Call.Next must NOT be null.
  224.  
  225.       return Call.Next /= null;
  226.    end Onqueue;
  227.  
  228.    -------------------
  229.    -- Count_Waiting --
  230.    -------------------
  231.  
  232.    --  Return number of calls on the waiting queue of E
  233.  
  234.    function Count_Waiting (E : in Entry_Queue) return Natural is
  235.       Count : Natural;
  236.       Temp : Entry_Call_Link;
  237.  
  238.    begin
  239.       Count := 0;
  240.  
  241.       if E.Head /= null then
  242.          Temp := E.Head;
  243.  
  244.          loop
  245.             Count := Count + 1;
  246.             exit when E.Tail = Temp;
  247.             Temp := Temp.Next;
  248.          end loop;
  249.       end if;
  250.  
  251.       return Count;
  252.    end Count_Waiting;
  253.  
  254.    ----------------------------
  255.    -- Select_Task_Entry_Call --
  256.    ----------------------------
  257.  
  258.    --  Select an entry for rendezvous
  259.  
  260.    procedure Select_Task_Entry_Call
  261.      (Acceptor         : Task_ID;
  262.       Open_Accepts     : Accept_List_Access;
  263.       Call             : out Entry_Call_Link;
  264.       Selection        : out Select_Index;
  265.       Open_Alternative : out Boolean)
  266.    is
  267.       Entry_Call  : Entry_Call_Link;
  268.       Temp_Call   : Entry_Call_Link;
  269.       Entry_Index : Task_Entry_Index;
  270.       Temp_Entry  : Task_Entry_Index;
  271.       TAS_Result  : Boolean;
  272.    begin
  273.       Open_Alternative := False;
  274.       Entry_Call := null;
  275.  
  276.       for J in Open_Accepts'Range loop
  277.          Temp_Entry := Open_Accepts (J).S;
  278.          if Temp_Entry /= Null_Task_Entry then
  279.             Open_Alternative := True;
  280.             Temp_Call := Head (Acceptor.Entry_Queues (Temp_Entry));
  281.             if Temp_Call /= null and then
  282.               (Entry_Call = null or else
  283.                Entry_Call.Prio < Temp_Call.Prio)
  284.             then
  285.                Entry_Call := Head (Acceptor.Entry_Queues (Temp_Entry));
  286.                Entry_Index := Temp_Entry;
  287.                Selection := J;
  288.             end if;
  289.          end if;
  290.       end loop;
  291.  
  292.       if Entry_Call = null then
  293.          Selection := No_Rendezvous;
  294.       else
  295.          Dequeue_Head (Acceptor.Entry_Queues (Entry_Index), Entry_Call);
  296.          --  Guard is open
  297.       end if;
  298.  
  299.       Call := Entry_Call;
  300.    end Select_Task_Entry_Call;
  301.  
  302.    ---------------------------------
  303.    -- Select_Protected_Entry_Call --
  304.    ---------------------------------
  305.  
  306.    --  Select an entry of a protected object
  307.  
  308.    procedure Select_Protected_Entry_Call
  309.      (Object    : access Protection;
  310.       Call      : out Entry_Call_Link)
  311.    is
  312.       Entry_Call  : Entry_Call_Link;
  313.       Temp_Call   : Entry_Call_Link;
  314.       Entry_Index : Protected_Entry_Index;
  315.       TAS_Result  : Boolean;
  316.    begin
  317.       Entry_Call := null;
  318.  
  319.       begin
  320.  
  321.          for J in Object.Entry_Queues'Range loop
  322.             Temp_Call := Head (Object.Entry_Queues (J));
  323.             if Temp_Call /= null and then
  324.               Object.Entry_Bodies (J).Barrier (Object.Compiler_Info, J)
  325.             then
  326.                if (Entry_Call = null or else
  327.                  Entry_Call.Prio < Temp_Call.Prio)
  328.                then
  329.                   Entry_Call := Temp_Call;
  330.                   Entry_Index := J;
  331.                end if;
  332.             end if;
  333.          end loop;
  334.  
  335.       exception
  336.       when others =>
  337.          Broadcast_Program_Error (Object, null);
  338.       end;
  339.  
  340.       --  If a call was selected, dequeue it and return it for service.
  341.       if Entry_Call /= null then
  342.          Dequeue_Head (Object.Entry_Queues (Entry_Index), Entry_Call);
  343.       end if;
  344.  
  345.       Call := Entry_Call;
  346.    end Select_Protected_Entry_Call;
  347.  
  348. end System.Tasking.Queuing;
  349.