OSDN Git Service

2008-04-08 Ed Schonberg <schonberg@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-interr-vxworks.adb
index 5898e6d..fac4cfc 100644 (file)
@@ -1,12 +1,12 @@
 ------------------------------------------------------------------------------
 --                                                                          --
---                GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS               --
+--                 GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                 --
 --                                                                          --
 --                     S Y S T E M . I N T E R R U P T S                    --
 --                                                                          --
 --                                  B o d y                                 --
 --                                                                          --
---         Copyright (C) 1992-2004, Free Software Foundation, Inc.          --
+--         Copyright (C) 1992-2008, Free Software Foundation, Inc.          --
 --                                                                          --
 -- GNARL is free software; you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -16,8 +16,8 @@
 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
 -- for  more details.  You should have  received  a copy of the GNU General --
 -- Public License  distributed with GNARL; see file COPYING.  If not, write --
--- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
--- MA 02111-1307, USA.                                                      --
+-- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
+-- Boston, MA 02110-1301, USA.                                              --
 --                                                                          --
 -- As a special exception,  if other files  instantiate  generics from this --
 -- unit, or you link  this unit with other files  to produce an executable, --
 
 --  Invariants:
 
---  All user-handleable signals are masked at all times in all
---  tasks/threads except possibly for the Interrupt_Manager task.
+--  All user-handleable signals are masked at all times in all tasks/threads
+--  except possibly for the Interrupt_Manager task.
 
---  When a user task wants to have the effect of masking/unmasking an
---  signal, it must call Block_Interrupt/Unblock_Interrupt, which
---  will have the effect of unmasking/masking the signal in the
---  Interrupt_Manager task.  These comments do not apply to vectored
---  hardware interrupts, which may be masked or unmasked using routined
---  interfaced to the relevant VxWorks system calls.
+--  When a user task wants to have the effect of masking/unmasking an signal,
+--  it must call Block_Interrupt/Unblock_Interrupt, which will have the effect
+--  of unmasking/masking the signal in the Interrupt_Manager task. These
+--  comments do not apply to vectored hardware interrupts, which may be masked
+--  or unmasked using routined interfaced to the relevant VxWorks system
+--  calls.
 
---  Once we associate a Signal_Server_Task with an signal, the task never
---  goes away, and we never remove the association. On the other hand, it
---  is more convenient to terminate an associated Interrupt_Server_Task
---  for a vectored hardware interrupt (since we use a binary semaphore
---  for synchronization with the umbrella handler).
+--  Once we associate a Signal_Server_Task with an signal, the task never goes
+--  away, and we never remove the association. On the other hand, it is more
+--  convenient to terminate an associated Interrupt_Server_Task for a vectored
+--  hardware interrupt (since we use a binary semaphore for synchronization
+--  with the umbrella handler).
 
 --  There is no more than one signal per Signal_Server_Task and no more than
---  one Signal_Server_Task per signal.  The same relation holds for hardware
---  interrupts and Interrupt_Server_Task's at any given time.  That is,
---  only one non-terminated Interrupt_Server_Task exists for a give
---  interrupt at any time.
+--  one Signal_Server_Task per signal. The same relation holds for hardware
+--  interrupts and Interrupt_Server_Task's at any given time. That is, only
+--  one non-terminated Interrupt_Server_Task exists for a give interrupt at
+--  any time.
 
 --  Within this package, the lock L is used to protect the various status
---  tables. If there is a Server_Task associated with a signal or interrupt,
---  we use the per-task lock of the Server_Task instead so that we protect the
---  status between Interrupt_Manager and Server_Task. Protection among
---  service requests are ensured via user calls to the Interrupt_Manager
---  entries.
+--  tables. If there is a Server_Task associated with a signal or interrupt, we
+--  use the per-task lock of the Server_Task instead so that we protect the
+--  status between Interrupt_Manager and Server_Task. Protection among service
+--  requests are ensured via user calls to the Interrupt_Manager entries.
 
 --  This is the VxWorks version of this package, supporting vectored hardware
 --  interrupts.
 
-with Unchecked_Conversion;
-
-with System.OS_Interface; use System.OS_Interface;
-
-with Interfaces.VxWorks;
-
+with Ada.Unchecked_Conversion;
 with Ada.Task_Identification;
---  used for Task_ID type
 
-with Ada.Exceptions;
---  used for Raise_Exception
+with Interfaces.VxWorks;
 
+with System.OS_Interface; use System.OS_Interface;
 with System.Interrupt_Management;
---  used for Reserve
-
 with System.Task_Primitives.Operations;
---  used for Write_Lock
---           Unlock
---           Abort
---           Wakeup_Task
---           Sleep
---           Initialize_Lock
-
 with System.Storage_Elements;
---  used for To_Address
---           To_Integer
---           Integer_Address
-
-with System.Tasking;
---  used for Task_ID
---           Task_Entry_Index
---           Null_Task
---           Self
---           Interrupt_Manager_ID
-
 with System.Tasking.Utilities;
---  used for Make_Independent
 
 with System.Tasking.Rendezvous;
---  used for Call_Simple
 pragma Elaborate_All (System.Tasking.Rendezvous);
 
 package body System.Interrupts is
 
    use Tasking;
-   use Ada.Exceptions;
 
    package POP renames System.Task_Primitives.Operations;
 
-   function To_Ada is new Unchecked_Conversion
-     (System.Tasking.Task_ID, Ada.Task_Identification.Task_Id);
+   function To_Ada is new Ada.Unchecked_Conversion
+     (System.Tasking.Task_Id, Ada.Task_Identification.Task_Id);
 
-   function To_System is new Unchecked_Conversion
-     (Ada.Task_Identification.Task_Id, Task_ID);
+   function To_System is new Ada.Unchecked_Conversion
+     (Ada.Task_Identification.Task_Id, Task_Id);
 
    -----------------
    -- Local Tasks --
    -----------------
 
-   --  WARNING: System.Tasking.Stages performs calls to this task
-   --  with low-level constructs. Do not change this spec without synchro-
-   --  nizing it.
+   --  WARNING: System.Tasking.Stages performs calls to this task with
+   --  low-level constructs. Do not change this spec without synchronizing it.
 
    task Interrupt_Manager is
-      entry Detach_Interrupt_Entries (T : Task_ID);
+      entry Detach_Interrupt_Entries (T : Task_Id);
 
       entry Attach_Handler
         (New_Handler : Parameterless_Handler;
@@ -148,7 +117,7 @@ package body System.Interrupts is
          Static    : Boolean);
 
       entry Bind_Interrupt_To_Entry
-        (T         : Task_ID;
+        (T         : Task_Id;
          E         : Task_Entry_Index;
          Interrupt : Interrupt_ID);
 
@@ -168,7 +137,7 @@ package body System.Interrupts is
    -------------------------------
 
    type Entry_Assoc is record
-      T : Task_ID;
+      T : Task_Id;
       E : Task_Entry_Index;
    end record;
 
@@ -204,11 +173,11 @@ package body System.Interrupts is
    Registered_Handler_Head : R_Link := null;
    Registered_Handler_Tail : R_Link := null;
 
-   Server_ID : array (Interrupt_ID) of System.Tasking.Task_ID :=
+   Server_ID : array (Interrupt_ID) of System.Tasking.Task_Id :=
      (others => System.Tasking.Null_Task);
    pragma Atomic_Components (Server_ID);
-   --  Holds the Task_ID of the Server_Task for each interrupt / signal.
-   --  Task_ID is needed to accomplish locking per interrupt base. Also
+   --  Holds the Task_Id of the Server_Task for each interrupt / signal.
+   --  Task_Id is needed to accomplish locking per interrupt base. Also
    --  is needed to determine whether to create a new Server_Task.
 
    Semaphore_ID_Map : array
@@ -222,10 +191,10 @@ package body System.Interrupts is
    Interrupt_Access_Hold : Interrupt_Task_Access;
    --  Variable for allocating an Interrupt_Server_Task
 
-   Default_Handler : array (HW_Interrupt) of Interfaces.VxWorks.VOIDFUNCPTR;
-   --  Vectored interrupt handlers installed prior to program startup.
-   --  These are saved only when the umbrella handler is installed for
-   --  a given interrupt number.
+   Handler_Installed : array (HW_Interrupt) of Boolean := (others => False);
+   --  True if Notify_Interrupt was connected to the interrupt.  Handlers
+   --  can be connected but disconnection is not possible on VxWorks.
+   --  Therefore we ensure Notify_Installed is connected at most once.
 
    -----------------------
    -- Local Subprograms --
@@ -246,9 +215,6 @@ package body System.Interrupts is
    procedure Notify_Interrupt (Param : System.Address);
    --  Umbrella handler for vectored interrupts (not signals)
 
-   procedure Install_Default_Action (Interrupt : HW_Interrupt);
-   --  Restore a handler that was in place prior to program execution
-
    procedure Install_Umbrella_Handler
      (Interrupt : HW_Interrupt;
       Handler   : Interfaces.VxWorks.VOIDFUNCPTR);
@@ -290,7 +256,7 @@ package body System.Interrupts is
    --  already bound.
 
    procedure Bind_Interrupt_To_Entry
-     (T       : Task_ID;
+     (T       : Task_Id;
       E       : Task_Entry_Index;
       Int_Ref : System.Address)
    is
@@ -318,9 +284,8 @@ package body System.Interrupts is
    procedure Check_Reserved_Interrupt (Interrupt : Interrupt_ID) is
    begin
       if Is_Reserved (Interrupt) then
-         Raise_Exception
-           (Program_Error'Identity,
-            "Interrupt" & Interrupt_ID'Image (Interrupt) & " is reserved");
+         raise Program_Error with
+           "Interrupt" & Interrupt_ID'Image (Interrupt) & " is reserved";
       else
          return;
       end if;
@@ -331,7 +296,8 @@ package body System.Interrupts is
    ---------------------
 
    function Current_Handler
-     (Interrupt : Interrupt_ID) return Parameterless_Handler is
+     (Interrupt : Interrupt_ID) return Parameterless_Handler
+   is
    begin
       Check_Reserved_Interrupt (Interrupt);
 
@@ -365,7 +331,7 @@ package body System.Interrupts is
    -- Detach_Interrupt_Entries --
    ------------------------------
 
-   procedure Detach_Interrupt_Entries (T : Task_ID) is
+   procedure Detach_Interrupt_Entries (T : Task_Id) is
    begin
       Interrupt_Manager.Detach_Interrupt_Entries (T);
    end Detach_Interrupt_Entries;
@@ -386,7 +352,8 @@ package body System.Interrupts is
      (Old_Handler : out Parameterless_Handler;
       New_Handler : Parameterless_Handler;
       Interrupt   : Interrupt_ID;
-      Static      : Boolean := False) is
+      Static      : Boolean := False)
+   is
    begin
       Check_Reserved_Interrupt (Interrupt);
       Interrupt_Manager.Exchange_Handler
@@ -421,7 +388,7 @@ package body System.Interrupts is
    -- Finalize_Interrupt_Servers --
    --------------------------------
 
-   --  Restore default handlers for interrupt servers.
+   --  Restore default handlers for interrupt servers
 
    --  This is called by the Interrupt_Manager task when it receives the abort
    --  signal during program finalization.
@@ -456,7 +423,6 @@ package body System.Interrupts is
       return   Boolean
    is
       pragma Unreferenced (Object);
-
    begin
       return True;
    end Has_Interrupt_Or_Attach_Handler;
@@ -466,7 +432,6 @@ package body System.Interrupts is
       return   Boolean
    is
       pragma Unreferenced (Object);
-
    begin
       return True;
    end Has_Interrupt_Or_Attach_Handler;
@@ -480,29 +445,17 @@ package body System.Interrupts is
       Unimplemented ("Ignore_Interrupt");
    end Ignore_Interrupt;
 
-   ----------------------------
-   -- Install_Default_Action --
-   ----------------------------
-
-   procedure Install_Default_Action (Interrupt : HW_Interrupt) is
-   begin
-      --  Restore original interrupt handler
-
-      Interfaces.VxWorks.intVecSet
-        (Interfaces.VxWorks.INUM_TO_IVEC (Integer (Interrupt)),
-         Default_Handler (Interrupt));
-      Default_Handler (Interrupt) := null;
-   end Install_Default_Action;
-
    ----------------------
    -- Install_Handlers --
    ----------------------
 
    procedure Install_Handlers
      (Object       : access Static_Interrupt_Protection;
-      New_Handlers : New_Handler_Array) is
+      New_Handlers : New_Handler_Array)
+   is
    begin
       for N in New_Handlers'Range loop
+
          --  We need a lock around this ???
 
          Object.Previous_Handlers (N).Interrupt := New_Handlers (N).Interrupt;
@@ -520,6 +473,17 @@ package body System.Interrupts is
       end loop;
    end Install_Handlers;
 
+   ---------------------------------
+   -- Install_Restricted_Handlers --
+   ---------------------------------
+
+   procedure Install_Restricted_Handlers (Handlers : New_Handler_Array) is
+   begin
+      for N in Handlers'Range loop
+         Attach_Handler (Handlers (N).Handler, Handlers (N).Interrupt, True);
+      end loop;
+   end Install_Restricted_Handlers;
+
    ------------------------------
    -- Install_Umbrella_Handler --
    ------------------------------
@@ -533,10 +497,6 @@ package body System.Interrupts is
       Vec : constant Interrupt_Vector :=
               INUM_TO_IVEC (Interfaces.VxWorks.int (Interrupt));
 
-      Old_Handler : constant VOIDFUNCPTR :=
-                      intVecGet
-                        (INUM_TO_IVEC (Interfaces.VxWorks.int (Interrupt)));
-
       Stat : Interfaces.VxWorks.STATUS;
       pragma Unreferenced (Stat);
       --  ??? shouldn't we test Stat at least in a pragma Assert?
@@ -547,10 +507,9 @@ package body System.Interrupts is
       --  when an interrupt occurs, so the umbrella handler has a different
       --  wrapper generated by intConnect for each interrupt number.
 
-      if Default_Handler (Interrupt) = null then
-         Stat :=
-           intConnect (Vec, Handler, System.Address (Interrupt));
-         Default_Handler (Interrupt) := Old_Handler;
+      if not Handler_Installed (Interrupt) then
+         Stat := intConnect (Vec, Handler, System.Address (Interrupt));
+         Handler_Installed (Interrupt) := True;
       end if;
    end Install_Umbrella_Handler;
 
@@ -604,7 +563,7 @@ package body System.Interrupts is
          Handler_Addr : System.Address;
       end record;
 
-      function To_Fat_Ptr is new Unchecked_Conversion
+      function To_Fat_Ptr is new Ada.Unchecked_Conversion
         (Parameterless_Handler, Fat_Ptr);
 
       Ptr : R_Link;
@@ -646,8 +605,10 @@ package body System.Interrupts is
 
    --  Umbrella handler for vectored hardware interrupts (as opposed to
    --  signals and exceptions).  As opposed to the signal implementation,
-   --  this handler is only installed in the vector table while there is
-   --  an active association of an Ada handler to the interrupt.
+   --  this handler is installed in the vector table when the first Ada
+   --  handler is attached to the interrupt.  However because VxWorks don't
+   --  support disconnecting handlers, this subprogram always test wether
+   --  or not an Ada handler is effectively attached.
 
    --  Otherwise, the handler that existed prior to program startup is
    --  in the vector table.  This ensures that handlers installed by
@@ -663,11 +624,15 @@ package body System.Interrupts is
    procedure Notify_Interrupt (Param : System.Address) is
       Interrupt : constant Interrupt_ID := Interrupt_ID (Param);
 
+      Id : constant SEM_ID := Semaphore_ID_Map (Interrupt);
+
       Discard_Result : STATUS;
       pragma Unreferenced (Discard_Result);
 
    begin
-      Discard_Result := semGive (Semaphore_ID_Map (Interrupt));
+      if Id /= 0 then
+         Discard_Result := semGive (Id);
+      end if;
    end Notify_Interrupt;
 
    ---------------
@@ -687,6 +652,7 @@ package body System.Interrupts is
 
    procedure Register_Interrupt_Handler (Handler_Addr : System.Address) is
       New_Node_Ptr : R_Link;
+
    begin
       --  This routine registers a handler as usable for dynamic
       --  interrupt handler association. Routines attaching and detaching
@@ -727,7 +693,8 @@ package body System.Interrupts is
    ------------------
 
    function Unblocked_By
-     (Interrupt : Interrupt_ID) return System.Tasking.Task_ID is
+     (Interrupt : Interrupt_ID) return System.Tasking.Task_Id
+   is
    begin
       Unimplemented ("Unblocked_By");
       return Null_Task;
@@ -748,9 +715,7 @@ package body System.Interrupts is
 
    procedure Unimplemented (Feature : String) is
    begin
-      Raise_Exception
-        (Program_Error'Identity,
-         Feature & " not implemented on VxWorks");
+      raise Program_Error with Feature & " not implemented on VxWorks";
    end Unimplemented;
 
    -----------------------
@@ -803,9 +768,6 @@ package body System.Interrupts is
          use type STATUS;
 
       begin
-         --  Hardware interrupt
-
-         Install_Default_Action (HW_Interrupt (Interrupt));
 
          --  Flush server task off semaphore, allowing it to terminate
 
@@ -827,8 +789,8 @@ package body System.Interrupts is
             --  If an interrupt entry is installed raise
             --  Program_Error. (propagate it to the caller).
 
-            Raise_Exception (Program_Error'Identity,
-              "An interrupt entry is already installed");
+            raise Program_Error with
+              "An interrupt entry is already installed";
          end if;
 
          --  Note : Static = True will pass the following check. This is the
@@ -836,11 +798,12 @@ package body System.Interrupts is
          --  status of the Current_Handler.
 
          if not Static and then User_Handler (Interrupt).Static then
-            --  Trying to detach a static Interrupt Handler.
-            --  raise Program_Error.
 
-            Raise_Exception (Program_Error'Identity,
-              "Trying to detach a static Interrupt Handler");
+            --  Trying to detach a static Interrupt Handler. raise
+            --  Program_Error.
+
+            raise Program_Error with
+              "Trying to detach a static Interrupt Handler";
          end if;
 
          Old_Handler := User_Handler (Interrupt).H;
@@ -864,15 +827,15 @@ package body System.Interrupts is
          New_Handler : Parameterless_Handler;
          Interrupt   : Interrupt_ID;
          Static      : Boolean;
-         Restoration : Boolean := False) is
+         Restoration : Boolean := False)
+      is
       begin
          if User_Entry (Interrupt).T /= Null_Task then
+
             --  If an interrupt entry is already installed, raise
             --  Program_Error. (propagate it to the caller).
 
-            Raise_Exception
-              (Program_Error'Identity,
-               "An interrupt is already installed");
+            raise Program_Error with "An interrupt is already installed";
          end if;
 
          --  Note : A null handler with Static = True will
@@ -893,10 +856,9 @@ package body System.Interrupts is
 
            or else not Is_Registered (New_Handler))
          then
-            Raise_Exception
-              (Program_Error'Identity,
+            raise Program_Error with
                "Trying to overwrite a static Interrupt Handler with a " &
-               "dynamic Handler");
+               "dynamic Handler";
          end if;
 
          --  Save the old handler
@@ -909,7 +871,7 @@ package body System.Interrupts is
 
          if New_Handler = null then
 
-            --  The null handler means we are detaching the handler.
+            --  The null handler means we are detaching the handler
 
             User_Handler (Interrupt).Static := False;
 
@@ -918,7 +880,7 @@ package body System.Interrupts is
          end if;
 
          --  Invoke a corresponding Server_Task if not yet created.
-         --  Place Task_ID info in Server_ID array.
+         --  Place Task_Id info in Server_ID array.
 
          if New_Handler /= null
            and then
@@ -935,11 +897,13 @@ package body System.Interrupts is
          end if;
 
          if (New_Handler = null) and then Old_Handler /= null then
+
             --  Restore default handler
 
             Unbind_Handler (Interrupt);
 
          elsif Old_Handler = null then
+
             --  Save default handler
 
             Bind_Handler (Interrupt);
@@ -992,7 +956,7 @@ package body System.Interrupts is
                end Detach_Handler;
             or
                accept Bind_Interrupt_To_Entry
-                 (T       : Task_ID;
+                 (T       : Task_Id;
                   E       : Task_Entry_Index;
                   Interrupt : Interrupt_ID)
                do
@@ -1002,9 +966,8 @@ package body System.Interrupts is
                   if User_Handler (Interrupt).H /= null
                     or else User_Entry (Interrupt).T /= Null_Task
                   then
-                     Raise_Exception
-                       (Program_Error'Identity,
-                        "A binding for this interrupt is already present");
+                     raise Program_Error with
+                       "A binding for this interrupt is already present";
                   end if;
 
                   User_Entry (Interrupt) := Entry_Assoc'(T => T, E => E);
@@ -1017,7 +980,7 @@ package body System.Interrupts is
                   T.Interrupt_Entry := True;
 
                   --  Invoke a corresponding Server_Task if not yet created.
-                  --  Place Task_ID info in Server_ID array.
+                  --  Place Task_Id info in Server_ID array.
 
                   if Server_ID (Interrupt) = Null_Task
                     or else
@@ -1034,7 +997,7 @@ package body System.Interrupts is
                end Bind_Interrupt_To_Entry;
 
             or
-               accept Detach_Interrupt_Entries (T : Task_ID) do
+               accept Detach_Interrupt_Entries (T : Task_Id) do
                   for Int in Interrupt_ID'Range loop
                      if not Is_Reserved (Int) then
                         if User_Entry (Int).T = T then
@@ -1046,7 +1009,7 @@ package body System.Interrupts is
                      end if;
                   end loop;
 
-                  --  Indicate in ATCB that no interrupt entries are attached.
+                  --  Indicate in ATCB that no interrupt entries are attached
 
                   T.Interrupt_Entry := False;
                end Detach_Interrupt_Entries;
@@ -1079,9 +1042,9 @@ package body System.Interrupts is
    --  Server task for vectored hardware interrupt handling
 
    task body Interrupt_Server_Task is
-      Self_Id         : constant Task_ID := Self;
+      Self_Id         : constant Task_Id := Self;
       Tmp_Handler     : Parameterless_Handler;
-      Tmp_ID          : Task_ID;
+      Tmp_ID          : Task_Id;
       Tmp_Entry_Index : Task_Entry_Index;
       S               : STATUS;
 
@@ -1122,6 +1085,10 @@ package body System.Interrupts is
 
             POP.Write_Lock (Self_Id);
 
+            --  Unassociate the interrupt handler.
+
+            Semaphore_ID_Map (Interrupt) := 0;
+
             --  Delete the associated semaphore
 
             S := semDelete (Int_Sema);
@@ -1130,7 +1097,6 @@ package body System.Interrupts is
 
             --  Set status for the Interrupt_Manager
 
-            Semaphore_ID_Map (Interrupt) := 0;
             Server_ID (Interrupt) := Null_Task;
             POP.Unlock (Self_Id);
 
@@ -1140,7 +1106,7 @@ package body System.Interrupts is
    end Interrupt_Server_Task;
 
 begin
-   --  Get Interrupt_Manager's ID so that Abort_Interrupt can be sent.
+   --  Get Interrupt_Manager's ID so that Abort_Interrupt can be sent
 
    Interrupt_Manager_ID := To_System (Interrupt_Manager'Identity);
 end System.Interrupts;