1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
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 --
9 -- Copyright (C) 2014-2024, Free Software Foundation, Inc. --
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. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
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. --
27 -- GNARL was developed by the GNARL team at Florida State University. --
28 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
30 ------------------------------------------------------------------------------
32 -- This is the Android version of this package
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.
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.
42 -- This file assumes that:
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
50 -- SIGINT exists and will be kept unmasked unless the pragma
51 -- Unreserve_All_Interrupts is specified anywhere in the application.
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
58 -- Reserved: the OS specific set of signals that are reserved.
60 with System
.Task_Primitives
;
62 package body System
.Interrupt_Management
is
65 use System
.OS_Interface
;
67 type Interrupt_List
is array (Interrupt_ID
range <>) of Interrupt_ID
;
68 Exception_Interrupts
: constant Interrupt_List
:=
69 (SIGFPE
, SIGILL
, SIGSEGV
, SIGBUS
);
71 Unreserve_All_Interrupts
: constant Interfaces
.C
.int
;
73 (C
, Unreserve_All_Interrupts
, "__gl_unreserve_all_interrupts");
75 -----------------------
76 -- Local Subprograms --
77 -----------------------
79 procedure Signal_Trampoline
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
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:
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.
107 siginfo
: System
.Address
;
108 ucontext
: System
.Address
)
110 pragma Unreferenced
(siginfo
);
111 pragma Unreferenced
(ucontext
);
114 -- Check that treatment of exception propagation here is consistent with
115 -- treatment of the abort signal in System.Task_Primitives.Operations.
118 when SIGFPE
=> raise Constraint_Error
;
119 when SIGILL
=> raise Program_Error
;
120 when SIGSEGV
=> raise Storage_Error
;
121 when SIGBUS
=> raise Storage_Error
;
126 ----------------------
127 -- Notify_Exception --
128 ----------------------
130 User
: constant Character := 'u';
131 Runtime
: constant Character := 'r';
132 Default
: constant Character := 's';
133 -- 'n' this interrupt not set by any Interrupt_State pragma
134 -- 'u' Interrupt_State pragma set state to User
135 -- 'r' Interrupt_State pragma set state to Runtime
136 -- 's' Interrupt_State pragma set state to System (use "default"
139 procedure Notify_Exception
141 siginfo
: System
.Address
;
142 ucontext
: System
.Address
);
143 -- This function is the signal handler and calls a trampoline subprogram
144 -- that adjusts the unwind information so the ARM unwinder can find it's
145 -- way back to the context of the originating subprogram. Compare with
146 -- __gnat_error_handler for non-tasking programs.
148 ----------------------
149 -- Notify_Exception --
150 ----------------------
152 Signal_Mask
: aliased sigset_t
;
153 -- The set of signals handled by Notify_Exception
155 procedure Notify_Exception
157 siginfo
: System
.Address
;
158 ucontext
: System
.Address
)
160 Result
: Interfaces
.C
.int
;
163 -- With the __builtin_longjmp, the signal mask is not restored, so we
164 -- need to restore it explicitly. ??? We don't use __builtin_longjmp
165 -- anymore, so do we still need this? */
167 Result
:= pthread_sigmask
(SIG_UNBLOCK
, Signal_Mask
'Access, null);
168 pragma Assert
(Result
= 0);
170 -- Perform the necessary context adjustments prior to calling the
171 -- trampoline subprogram with the "real" signal handler.
173 Adjust_Context_For_Raise
(signo
, ucontext
);
175 Signal_Trampoline
(signo
, siginfo
, ucontext
, Map_Signal
'Address);
176 end Notify_Exception
;
182 Initialized
: Boolean := False;
184 procedure Initialize
is
185 act
: aliased struct_sigaction
;
186 old_act
: aliased struct_sigaction
;
187 Result
: System
.OS_Interface
.int
;
189 Use_Alternate_Stack
: constant Boolean :=
190 System
.Task_Primitives
.Alternate_Stack_Size
/= 0;
191 -- Whether to use an alternate signal stack for stack overflows
200 -- Need to call pthread_init very early because it is doing signal
205 Abort_Task_Interrupt
:= SIGADAABORT
;
207 act
.sa_handler
:= Notify_Exception
'Address;
209 -- Setting SA_SIGINFO asks the kernel to pass more than just the signal
210 -- number argument to the handler when it is called. The set of extra
211 -- parameters includes a pointer to the interrupted context, which the
212 -- ZCX propagation scheme needs.
214 -- Most man pages for sigaction mention that sa_sigaction should be set
215 -- instead of sa_handler when SA_SIGINFO is on. In practice, the two
216 -- fields are actually union'ed and located at the same offset.
218 -- On some targets, we set sa_flags to SA_NODEFER so that during the
219 -- handler execution we do not change the Signal_Mask to be masked for
222 -- This is a temporary fix to the problem that the Signal_Mask is not
223 -- restored after the exception (longjmp) from the handler. The right
224 -- fix should be made in sigsetjmp so that we save the Signal_Set and
225 -- restore it after a longjmp.
227 -- We set SA_NODEFER to be compatible with what is done in
228 -- __gnat_error_handler.
230 Result
:= sigemptyset
(Signal_Mask
'Access);
231 pragma Assert
(Result
= 0);
233 -- Add signals that map to Ada exceptions to the mask
235 for J
in Exception_Interrupts
'Range loop
236 if State
(Exception_Interrupts
(J
)) /= Default
then
239 (Signal_Mask
'Access, Signal
(Exception_Interrupts
(J
)));
240 pragma Assert
(Result
= 0);
244 act
.sa_mask
:= Signal_Mask
;
246 pragma Assert
(Keep_Unmasked
= (Interrupt_ID
'Range => False));
247 pragma Assert
(Reserve
= (Interrupt_ID
'Range => False));
249 -- Process state of exception signals
251 for J
in Exception_Interrupts
'Range loop
252 if State
(Exception_Interrupts
(J
)) /= User
then
253 Keep_Unmasked
(Exception_Interrupts
(J
)) := True;
254 Reserve
(Exception_Interrupts
(J
)) := True;
256 if State
(Exception_Interrupts
(J
)) /= Default
then
257 act
.sa_flags
:= SA_NODEFER
+ SA_RESTART
+ SA_SIGINFO
;
259 if Use_Alternate_Stack
260 and then Exception_Interrupts
(J
) = SIGSEGV
262 act
.sa_flags
:= act
.sa_flags
+ SA_ONSTACK
;
267 (Signal
(Exception_Interrupts
(J
)), act
'Unchecked_Access,
268 old_act
'Unchecked_Access);
269 pragma Assert
(Result
= 0);
274 if State
(Abort_Task_Interrupt
) /= User
then
275 Keep_Unmasked
(Abort_Task_Interrupt
) := True;
276 Reserve
(Abort_Task_Interrupt
) := True;
279 -- Set SIGINT to unmasked state as long as it is not in "User" state.
280 -- Check for Unreserve_All_Interrupts last.
282 if State
(SIGINT
) /= User
then
283 Keep_Unmasked
(SIGINT
) := True;
284 Reserve
(SIGINT
) := True;
287 -- Check all signals for state that requires keeping them unmasked and
290 for J
in Interrupt_ID
'Range loop
291 if State
(J
) = Default
or else State
(J
) = Runtime
then
292 Keep_Unmasked
(J
) := True;
297 -- Add the set of signals that must always be unmasked for this target
299 for J
in Unmasked
'Range loop
300 Keep_Unmasked
(Interrupt_ID
(Unmasked
(J
))) := True;
301 Reserve
(Interrupt_ID
(Unmasked
(J
))) := True;
304 -- Add target-specific reserved signals
306 for J
in Reserved
'Range loop
307 Reserve
(Interrupt_ID
(Reserved
(J
))) := True;
310 -- Process pragma Unreserve_All_Interrupts. This overrides any settings
311 -- due to pragma Interrupt_State:
313 if Unreserve_All_Interrupts
/= 0 then
314 Keep_Unmasked
(SIGINT
) := False;
315 Reserve
(SIGINT
) := False;
318 -- We do not really have Signal 0. We just use this value to identify
319 -- non-existent signals (see s-intnam.ads). Therefore, Signal should not
320 -- be used in all signal related operations hence mark it as reserved.
325 end System
.Interrupt_Management
;