File : s-intman-android.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                 GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                 --
   4 --                                                                          --
   5 --           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          --
   6 --                                                                          --
   7 --                                  B o d y                                 --
   8 --                                                                          --
   9 --          Copyright (C) 2014-2016, Free Software Foundation, Inc.         --
  10 --                                                                          --
  11 -- GNARL is free software; you can  redistribute it  and/or modify it under --
  12 -- terms of the  GNU General Public License as published  by the Free Soft- --
  13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
  14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  16 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
  17 --                                                                          --
  18 --                                                                          --
  19 --                                                                          --
  20 --                                                                          --
  21 --                                                                          --
  22 -- In particular,  you can freely  distribute your programs  built with the --
  23 -- GNAT Pro compiler, including any required library run-time units,  using --
  24 -- any licensing terms  of your choosing.  See the AdaCore Software License --
  25 -- for full details.                                                        --
  26 --                                                                          --
  27 -- GNARL was developed by the GNARL team at Florida State University.       --
  28 -- Extensive contributions were provided by Ada Core Technologies, Inc.     --
  29 --                                                                          --
  30 ------------------------------------------------------------------------------
  31 
  32 --  This is the Android version of this package
  33 
  34 --  Make a careful study of all signals available under the OS, to see which
  35 --  need to be reserved, kept always unmasked, or kept always unmasked. Be on
  36 --  the lookout for special signals that may be used by the thread library.
  37 
  38 --  Since this is a multi target file, the signal <-> exception mapping
  39 --  is simple minded. If you need a more precise and target specific
  40 --  signal handling, create a new s-intman.adb that will fit your needs.
  41 
  42 --  This file assumes that:
  43 
  44 --    SIGFPE, SIGILL, SIGSEGV and SIGBUS exist. They are mapped as follows:
  45 --      SIGPFE  => Constraint_Error
  46 --      SIGILL  => Program_Error
  47 --      SIGSEGV => Storage_Error
  48 --      SIGBUS  => Storage_Error
  49 
  50 --    SIGINT exists and will be kept unmasked unless the pragma
  51 --     Unreserve_All_Interrupts is specified anywhere in the application.
  52 
  53 --    System.OS_Interface contains the following:
  54 --      SIGADAABORT: the signal that will be used to abort tasks.
  55 --      Unmasked: the OS specific set of signals that should be unmasked in
  56 --                all the threads. SIGADAABORT is unmasked by
  57 --                default
  58 --      Reserved: the OS specific set of signals that are reserved.
  59 
  60 with System.Task_Primitives;
  61 
  62 package body System.Interrupt_Management is
  63 
  64    use Interfaces.C;
  65    use System.OS_Interface;
  66 
  67    type Interrupt_List is array (Interrupt_ID range <>) of Interrupt_ID;
  68    Exception_Interrupts : constant Interrupt_List :=
  69      (SIGFPE, SIGILL, SIGSEGV, SIGBUS);
  70 
  71    Unreserve_All_Interrupts : Interfaces.C.int;
  72    pragma Import
  73      (C, Unreserve_All_Interrupts, "__gl_unreserve_all_interrupts");
  74 
  75    -----------------------
  76    -- Local Subprograms --
  77    -----------------------
  78 
  79    procedure Signal_Trampoline
  80      (signo    : Signal;
  81       siginfo  : System.Address;
  82       ucontext : System.Address;
  83       handler  : System.Address);
  84    pragma Import (C, Signal_Trampoline, "__gnat_sigtramp");
  85    --  Pass the real handler to a speical function that handles unwinding by
  86    --  skipping over the kernel signal frame (which doesn't contain any unwind
  87    --  information).
  88 
  89    function State (Int : Interrupt_ID) return Character;
  90    pragma Import (C, State, "__gnat_get_interrupt_state");
  91    --  Get interrupt state. Defined in init.c The input argument is the
  92    --  interrupt number, and the result is one of the following:
  93 
  94    procedure Map_Signal
  95      (signo    : Signal;
  96       siginfo  : System.Address;
  97       ucontext : System.Address);
  98    --  This function identifies the Ada exception to be raised using the
  99    --  information when the system received a synchronous signal.
 100 
 101 ----------------
 102 -- Map_Signal --
 103 ----------------
 104 
 105    procedure Map_Signal
 106      (signo    : Signal;
 107       siginfo  : System.Address;
 108       ucontext : System.Address)
 109    is
 110       pragma Unreferenced (siginfo);
 111       pragma Unreferenced (ucontext);
 112 
 113    begin
 114 
 115       --  Check that treatment of exception propagation here is consistent with
 116       --  treatment of the abort signal in System.Task_Primitives.Operations.
 117 
 118       case signo is
 119          when SIGFPE =>
 120             raise Constraint_Error;
 121          when SIGILL =>
 122             raise Program_Error;
 123          when SIGSEGV =>
 124             raise Storage_Error;
 125          when SIGBUS =>
 126             raise Storage_Error;
 127          when others =>
 128             null;
 129       end case;
 130    end Map_Signal;
 131 
 132 ----------------------
 133 -- Notify_Exception --
 134 ----------------------
 135 
 136    User    : constant Character := 'u';
 137    Runtime : constant Character := 'r';
 138    Default : constant Character := 's';
 139    --    'n'   this interrupt not set by any Interrupt_State pragma
 140    --    'u'   Interrupt_State pragma set state to User
 141    --    'r'   Interrupt_State pragma set state to Runtime
 142    --    's'   Interrupt_State pragma set state to System (use "default"
 143    --           system handler)
 144 
 145    procedure Notify_Exception
 146      (signo    : Signal;
 147       siginfo  : System.Address;
 148       ucontext : System.Address);
 149    --  This function is the signal handler and calls a trampoline subprogram
 150    --  that adjusts the unwind information so the ARM unwinder can find it's
 151    --  way back to the context of the originating subprogram. Compare with
 152    --  __gnat_error_handler for non-tasking programs.
 153 
 154    ----------------------
 155    -- Notify_Exception --
 156    ----------------------
 157 
 158    Signal_Mask : aliased sigset_t;
 159    --  The set of signals handled by Notify_Exception
 160 
 161    procedure Notify_Exception
 162      (signo    : Signal;
 163       siginfo  : System.Address;
 164       ucontext : System.Address)
 165    is
 166       Result : Interfaces.C.int;
 167 
 168    begin
 169       --  With the __builtin_longjmp, the signal mask is not restored, so we
 170       --  need to restore it explicitly.  ??? We don't use __builtin_longjmp
 171       --  anymore, so do we still need this?   */
 172 
 173       Result := pthread_sigmask (SIG_UNBLOCK, Signal_Mask'Access, null);
 174       pragma Assert (Result = 0);
 175 
 176       --  Perform the necessary context adjustments prior to calling the
 177       --  trampoline subprogram with the "real" signal handler.
 178 
 179       Adjust_Context_For_Raise (signo, ucontext);
 180 
 181       Signal_Trampoline (signo, siginfo, ucontext, Map_Signal'Address);
 182    end Notify_Exception;
 183 
 184    ----------------
 185    -- Initialize --
 186    ----------------
 187 
 188    Initialized : Boolean := False;
 189 
 190    procedure Initialize is
 191       act     : aliased struct_sigaction;
 192       old_act : aliased struct_sigaction;
 193       Result  : System.OS_Interface.int;
 194 
 195       Use_Alternate_Stack : constant Boolean :=
 196                               System.Task_Primitives.Alternate_Stack_Size /= 0;
 197       --  Whether to use an alternate signal stack for stack overflows
 198 
 199    begin
 200       if Initialized then
 201          return;
 202       end if;
 203 
 204       Initialized := True;
 205 
 206       --  Need to call pthread_init very early because it is doing signal
 207       --  initializations.
 208 
 209       pthread_init;
 210 
 211       Abort_Task_Interrupt := SIGADAABORT;
 212 
 213       act.sa_handler := Notify_Exception'Address;
 214 
 215       --  Setting SA_SIGINFO asks the kernel to pass more than just the signal
 216       --  number argument to the handler when it is called. The set of extra
 217       --  parameters includes a pointer to the interrupted context, which the
 218       --  ZCX propagation scheme needs.
 219 
 220       --  Most man pages for sigaction mention that sa_sigaction should be set
 221       --  instead of sa_handler when SA_SIGINFO is on.  In practice, the two
 222       --  fields are actually union'ed and located at the same offset.
 223 
 224       --  On some targets, we set sa_flags to SA_NODEFER so that during the
 225       --  handler execution we do not change the Signal_Mask to be masked for
 226       --  the Signal.
 227 
 228       --  This is a temporary fix to the problem that the Signal_Mask is not
 229       --  restored after the exception (longjmp) from the handler. The right
 230       --  fix should be made in sigsetjmp so that we save the Signal_Set and
 231       --  restore it after a longjmp.
 232 
 233       --  We set SA_NODEFER to be compatible with what is done in
 234       --  __gnat_error_handler.
 235 
 236       Result := sigemptyset (Signal_Mask'Access);
 237       pragma Assert (Result = 0);
 238 
 239       --  Add signals that map to Ada exceptions to the mask
 240 
 241       for J in Exception_Interrupts'Range loop
 242          if State (Exception_Interrupts (J)) /= Default then
 243             Result :=
 244               sigaddset
 245                 (Signal_Mask'Access, Signal (Exception_Interrupts (J)));
 246             pragma Assert (Result = 0);
 247          end if;
 248       end loop;
 249 
 250       act.sa_mask := Signal_Mask;
 251 
 252       pragma Assert (Keep_Unmasked = (Interrupt_ID'Range => False));
 253       pragma Assert (Reserve = (Interrupt_ID'Range => False));
 254 
 255       --  Process state of exception signals
 256 
 257       for J in Exception_Interrupts'Range loop
 258          if State (Exception_Interrupts (J)) /= User then
 259             Keep_Unmasked (Exception_Interrupts (J)) := True;
 260             Reserve (Exception_Interrupts (J)) := True;
 261 
 262             if State (Exception_Interrupts (J)) /= Default then
 263                act.sa_flags := SA_NODEFER + SA_RESTART + SA_SIGINFO;
 264 
 265                if Use_Alternate_Stack
 266                  and then Exception_Interrupts (J) = SIGSEGV
 267                then
 268                   act.sa_flags := act.sa_flags + SA_ONSTACK;
 269                end if;
 270 
 271                Result :=
 272                  sigaction
 273                    (Signal (Exception_Interrupts (J)), act'Unchecked_Access,
 274                     old_act'Unchecked_Access);
 275                pragma Assert (Result = 0);
 276             end if;
 277          end if;
 278       end loop;
 279 
 280       if State (Abort_Task_Interrupt) /= User then
 281          Keep_Unmasked (Abort_Task_Interrupt) := True;
 282          Reserve (Abort_Task_Interrupt) := True;
 283       end if;
 284 
 285       --  Set SIGINT to unmasked state as long as it is not in "User" state.
 286       --  Check for Unreserve_All_Interrupts last.
 287 
 288       if State (SIGINT) /= User then
 289          Keep_Unmasked (SIGINT) := True;
 290          Reserve (SIGINT) := True;
 291       end if;
 292 
 293       --  Check all signals for state that requires keeping them unmasked and
 294       --  reserved.
 295 
 296       for J in Interrupt_ID'Range loop
 297          if State (J) = Default or else State (J) = Runtime then
 298             Keep_Unmasked (J) := True;
 299             Reserve (J) := True;
 300          end if;
 301       end loop;
 302 
 303       --  Add the set of signals that must always be unmasked for this target
 304 
 305       for J in Unmasked'Range loop
 306          Keep_Unmasked (Interrupt_ID (Unmasked (J))) := True;
 307          Reserve (Interrupt_ID (Unmasked (J))) := True;
 308       end loop;
 309 
 310       --  Add target-specific reserved signals
 311 
 312       for J in Reserved'Range loop
 313          Reserve (Interrupt_ID (Reserved (J))) := True;
 314       end loop;
 315 
 316       --  Process pragma Unreserve_All_Interrupts. This overrides any settings
 317       --  due to pragma Interrupt_State:
 318 
 319       if Unreserve_All_Interrupts /= 0 then
 320          Keep_Unmasked (SIGINT) := False;
 321          Reserve (SIGINT) := False;
 322       end if;
 323 
 324       --  We do not really have Signal 0. We just use this value to identify
 325       --  non-existent signals (see s-intnam.ads). Therefore, Signal should not
 326       --  be used in all signal related operations hence mark it as reserved.
 327 
 328       Reserve (0) := True;
 329    end Initialize;
 330 
 331 end System.Interrupt_Management;