diff options
Diffstat (limited to 'gcc/ada/5zintman.adb')
-rw-r--r-- | gcc/ada/5zintman.adb | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/gcc/ada/5zintman.adb b/gcc/ada/5zintman.adb new file mode 100644 index 00000000000..2f58cc2b86f --- /dev/null +++ b/gcc/ada/5zintman.adb @@ -0,0 +1,295 @@ +------------------------------------------------------------------------------ +-- -- +-- GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS -- +-- -- +-- S Y S T E M . I N T E R R U P T _ M A N A G E M E N T -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.11 $ +-- -- +-- Copyright (C) 1991-2001 Florida State University -- +-- -- +-- GNARL is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 2, or (at your option) any later ver- -- +-- sion. GNARL is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. 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. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +-- -- +-- GNARL was developed by the GNARL team at Florida State University. It is -- +-- now maintained by Ada Core Technologies Inc. in cooperation with Florida -- +-- State University (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +-- This is the VxWorks version of this package. + +-- It is likely to need tailoring to fit each operating system +-- and machine architecture. + +-- PLEASE DO NOT add any dependences on other packages. +-- This package is designed to work with or without tasking support. + +-- See the other warnings in the package specification before making +-- any modifications to this file. + +-- Make a careful study of all signals available under the OS, +-- to see which need to be reserved, kept always unmasked, +-- or kept always unmasked. +-- Be on the lookout for special signals that +-- may be used by the thread library. + +with Interfaces.C; +-- used for int and other types + +with System.Error_Reporting; +pragma Warnings (Off, System.Error_Reporting); +-- used for Shutdown + +with System.OS_Interface; +-- used for various Constants, Signal and types + +with Unchecked_Conversion; + +package body System.Interrupt_Management is + + use Interfaces.C; + use System.Error_Reporting; + use System.OS_Interface; + + function To_Isr is new Unchecked_Conversion (Long_Integer, isr_address); + + type Interrupt_List is array (Interrupt_ID range <>) of Interrupt_ID; + Exception_Interrupts : constant Interrupt_List := + (SIGFPE, SIGILL, SIGSEGV, SIGBUS); + + -- Keep these variables global so that they are initialized only once. + + Exception_Action : aliased struct_sigaction; + Default_Action : aliased struct_sigaction; + + -- ????? Use these horrible imports here to solve elaboration order + -- problems. + + type Task_Id is access all Integer; + + Interrupt_ID_Map : array (Interrupt_ID) of Task_Id; + pragma Import (Ada, Interrupt_ID_Map, + "system__task_primitives__interrupt_operations__interrupt_id_map"); + + ---------------------- + -- Notify_Exception -- + ---------------------- + + procedure Notify_Exception (signo : Signal); + -- Identify the Ada exception to be raised using + -- the information when the system received a synchronous signal. + + procedure Notify_Exception (signo : Signal) is + Mask : aliased sigset_t; + Result : Interfaces.C.int; + My_Id : pthread_t; + begin + -- VxWorks will always mask out the signal during the signal + -- handler and will reenable it on a longjmp. GNAT does + -- not generate a longjmp to return from a signal handler + -- so the signal will still be masked unless we unmask it. + Result := pthread_sigmask (SIG_SETMASK, null, Mask'Unchecked_Access); + Result := sigdelset (Mask'Access, signo); + Result := pthread_sigmask (SIG_SETMASK, Mask'Unchecked_Access, null); + + -- VxWorks will suspend the task when it gets a hardware + -- exception. We take the liberty of resuming the task + -- for the application. + My_Id := taskIdSelf; + if taskIsSuspended (My_Id) /= 0 then + Result := taskResume (My_Id); + end if; + + -- As long as we are using a longjmp to return control to the + -- exception handler on the runtime stack, we are safe. The original + -- signal mask (the one we had before coming into this signal catching + -- function) will be restored by the longjmp. Therefore, raising + -- an exception in this handler should be a safe operation. + + -- Check that treatment of exception propagation here + -- is consistent with treatment of the abort signal in + -- System.Task_Primitives.Operations. + + -- How can SIGSEGV be split into constraint and storage errors? + -- What should SIGILL really raise ? Some implementations have + -- codes for different types of SIGILL and some raise Storage_Error. + -- What causes SIGBUS and should it be caught? + -- Peter Burwood + + case signo is + when SIGFPE => + raise Constraint_Error; + when SIGILL => + raise Constraint_Error; + when SIGSEGV => + raise Program_Error; + when SIGBUS => + raise Program_Error; + when others => + pragma Assert (Shutdown ("Unexpected signal")); + null; + end case; + end Notify_Exception; + + ------------------- + -- Notify_Signal -- + ------------------- + + -- VxWorks needs a special casing here. Each VxWorks task has a completely + -- separate signal handling, so the usual signal masking can't work. + -- This idea is to handle all the signals in all the tasks, and when + -- such a signal occurs, redirect it to the dedicated task (if any) or + -- reraise it. + + procedure Notify_Signal (signo : Signal); + + procedure Notify_Signal (signo : Signal) is + Mask : aliased sigset_t; + Result : Interfaces.C.int; + My_Id : pthread_t; + old_isr : isr_address; + + function Get_Thread_Id (T : Task_Id) return pthread_t; + pragma Import (Ada, Get_Thread_Id, + "system__task_primitives__operations__get_thread_id"); + + begin + -- VxWorks will always mask out the signal during the signal + -- handler and will reenable it on a longjmp. GNAT does + -- not generate a longjmp to return from a signal handler + -- so the signal will still be masked unless we unmask it. + Result := pthread_sigmask (SIG_SETMASK, null, Mask'Unchecked_Access); + Result := sigdelset (Mask'Access, signo); + Result := pthread_sigmask (SIG_SETMASK, Mask'Unchecked_Access, null); + + -- VxWorks will suspend the task when it gets a hardware + -- exception. We take the liberty of resuming the task + -- for the application. + My_Id := taskIdSelf; + if taskIsSuspended (My_Id) /= 0 then + Result := taskResume (My_Id); + end if; + + -- ??? Need a lock around this, in case the handler is detached + -- between the two following statements. + + if Interrupt_ID_Map (Interrupt_ID (signo)) /= null then + Result := + kill (Get_Thread_Id (Interrupt_ID_Map (Interrupt_ID (signo))), + Signal (signo)); + else + old_isr := c_signal (signo, To_Isr (SIG_DFL)); + Result := kill (My_Id, Signal (signo)); + end if; + end Notify_Signal; + + --------------------------- + -- Initialize_Interrupts -- + --------------------------- + + -- Since there is no signal inheritance between VxWorks tasks, we need + -- to initialize signal handling in each task. + + procedure Initialize_Interrupts is + old_act : aliased struct_sigaction; + Result : Interfaces.C.int; + + begin + for J in Interrupt_ID'First + 1 .. Interrupt_ID'Last loop + if J /= Abort_Task_Interrupt then + Result := sigaction (Signal (J), Default_Action'Access, + old_act'Unchecked_Access); + pragma Assert (Result = 0); + end if; + end loop; + + for J in Exception_Interrupts'Range loop + Keep_Unmasked (Exception_Interrupts (J)) := True; + Result := + sigaction + (Signal (Exception_Interrupts (J)), Exception_Action'Access, + old_act'Unchecked_Access); + pragma Assert (Result = 0); + end loop; + end Initialize_Interrupts; + +begin + declare + mask : aliased sigset_t; + default_mask : aliased sigset_t; + Result : Interfaces.C.int; + + begin + -- The VxWorks POSIX threads library currently needs initialization. + -- We wish it could be in System.OS_Interface, but that would + -- cause an elaboration problem. + + pthread_init; + + Abort_Task_Interrupt := SIGABRT; + -- Change this if you want to use another signal for task abort. + -- SIGTERM might be a good one. + + Exception_Action.sa_handler := Notify_Exception'Address; + Default_Action.sa_handler := Notify_Signal'Address; + + Exception_Action.sa_flags := SA_SIGINFO + SA_ONSTACK; + Default_Action.sa_flags := SA_SIGINFO + SA_ONSTACK; + -- Send us extra signal information (SA_SIGINFO) on the + -- stack (SA_ONSTACK). + -- There is no SA_NODEFER in VxWorks. The signal mask is + -- restored after a longjmp so the SA_NODEFER option is + -- not needed. - Dan Eischen + + Result := sigemptyset (mask'Access); + pragma Assert (Result = 0); + Result := sigemptyset (default_mask'Access); + pragma Assert (Result = 0); + + for J in Interrupt_ID'First + 1 .. Interrupt_ID'Last loop + Result := sigaddset (default_mask'Access, Signal (J)); + pragma Assert (Result = 0); + end loop; + + for J in Exception_Interrupts'Range loop + Result := sigaddset (mask'Access, Signal (Exception_Interrupts (J))); + pragma Assert (Result = 0); + Result := + sigdelset (default_mask'Access, Signal (Exception_Interrupts (J))); + pragma Assert (Result = 0); + end loop; + + Exception_Action.sa_mask := mask; + Default_Action.sa_mask := default_mask; + + -- Initialize_Interrupts is called for each task in Enter_Task + + Keep_Unmasked (Abort_Task_Interrupt) := True; + + Reserve := Reserve or Keep_Unmasked or Keep_Masked; + + Reserve (0) := True; + -- We do not have Signal 0 in reality. We just use this value + -- to identify non-existent signals (see s-intnam.ads). Therefore, + -- Signal 0 should not be used in all signal related operations hence + -- mark it as reserved. + end; +end System.Interrupt_Management; |