OSDN Git Service

gcc/ada/
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-intman-solaris.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) 1992-2007, 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 2,  or (at your option) any later ver- --
14 -- sion. GNARL 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.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNARL; see file COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- GNARL was developed by the GNARL team at Florida State University.       --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc.     --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 --  This is a Solaris version of this package
35
36 --  Make a careful study of all signals available under the OS, to see which
37 --  need to be reserved, kept always unmasked, or kept always unmasked.
38
39 --  Be on the lookout for special signals that may be used by the thread
40 --  library.
41
42 package body System.Interrupt_Management is
43
44    use Interfaces.C;
45    use System.OS_Interface;
46
47    type Interrupt_List is array (Interrupt_ID range <>) of Interrupt_ID;
48
49    Exception_Interrupts : constant Interrupt_List :=
50      (SIGFPE, SIGILL, SIGSEGV, SIGBUS);
51
52    Unreserve_All_Interrupts : Interfaces.C.int;
53    pragma Import
54      (C, Unreserve_All_Interrupts, "__gl_unreserve_all_interrupts");
55
56    function State (Int : Interrupt_ID) return Character;
57    pragma Import (C, State, "__gnat_get_interrupt_state");
58    --  Get interrupt state.  Defined in init.c
59    --  The input argument is the interrupt number,
60    --  and the result is one of the following:
61
62    User    : constant Character := 'u';
63    Runtime : constant Character := 'r';
64    Default : constant Character := 's';
65    --    'n'   this interrupt not set by any Interrupt_State pragma
66    --    'u'   Interrupt_State pragma set state to User
67    --    'r'   Interrupt_State pragma set state to Runtime
68    --    's'   Interrupt_State pragma set state to System (use "default"
69    --           system handler)
70
71    ----------------------
72    -- Notify_Exception --
73    ----------------------
74
75    --  This function identifies the Ada exception to be raised using the
76    --  information when the system received a synchronous signal. Since this
77    --  function is machine and OS dependent, different code has to be provided
78    --  for different target.
79
80    procedure Notify_Exception
81      (signo   : Signal;
82       info    : access siginfo_t;
83       context : access ucontext_t);
84
85    ----------------------
86    -- Notify_Exception --
87    ----------------------
88
89    procedure Notify_Exception
90      (signo   : Signal;
91       info    : access siginfo_t;
92       context : access ucontext_t)
93    is
94    begin
95       --  Perform the necessary context adjustments prior to a raise
96       --  from a signal handler.
97
98       Adjust_Context_For_Raise (signo, context.all'Address);
99
100       --  Check that treatment of exception propagation here
101       --  is consistent with treatment of the abort signal in
102       --  System.Task_Primitives.Operations.
103
104       case signo is
105          when SIGFPE =>
106             case info.si_code is
107                when  FPE_INTDIV |
108                      FPE_INTOVF |
109                      FPE_FLTDIV |
110                      FPE_FLTOVF |
111                      FPE_FLTUND |
112                      FPE_FLTRES |
113                      FPE_FLTINV |
114                      FPE_FLTSUB =>
115
116                   raise Constraint_Error;
117
118                when others =>
119                   pragma Assert (False);
120                   null;
121             end case;
122
123          when SIGILL | SIGSEGV | SIGBUS  =>
124             raise Storage_Error;
125
126          when others =>
127             pragma Assert (False);
128             null;
129       end case;
130    end Notify_Exception;
131
132    ----------------
133    -- Initialize --
134    ----------------
135
136    Initialized : Boolean := False;
137
138    procedure Initialize is
139       act     : aliased struct_sigaction;
140       old_act : aliased struct_sigaction;
141       mask    : aliased sigset_t;
142       Result  : Interfaces.C.int;
143
144    begin
145       if Initialized then
146          return;
147       end if;
148
149       Initialized := True;
150
151       --  Need to call pthread_init very early because it is doing signal
152       --  initializations.
153
154       pthread_init;
155
156       --  Change this if you want to use another signal for task abort.
157       --  SIGTERM might be a good one.
158
159       Abort_Task_Interrupt := SIGABRT;
160
161       act.sa_handler := Notify_Exception'Address;
162
163       --  Set sa_flags to SA_NODEFER so that during the handler execution
164       --  we do not change the Signal_Mask to be masked for the Signal.
165       --  This is a temporary fix to the problem that the Signal_Mask is
166       --  not restored after the exception (longjmp) from the handler.
167       --  The right fix should be made in sigsetjmp so that we save
168       --  the Signal_Set and restore it after a longjmp.
169
170       --  In that case, this field should be changed back to 0. ??? (Dong-Ik)
171
172       act.sa_flags := 16;
173
174       Result := sigemptyset (mask'Access);
175       pragma Assert (Result = 0);
176
177       --  ??? For the same reason explained above, we can't mask these signals
178       --  because otherwise we won't be able to catch more than one signal.
179
180       act.sa_mask := mask;
181
182       pragma Assert (Keep_Unmasked = (Interrupt_ID'Range => False));
183       pragma Assert (Reserve = (Interrupt_ID'Range => False));
184
185       for J in Exception_Interrupts'Range loop
186          if State (Exception_Interrupts (J)) /= User then
187             Keep_Unmasked (Exception_Interrupts (J)) := True;
188             Reserve (Exception_Interrupts (J)) := True;
189
190             if State (Exception_Interrupts (J)) /= Default then
191                Result :=
192                  sigaction
193                  (Signal (Exception_Interrupts (J)), act'Unchecked_Access,
194                   old_act'Unchecked_Access);
195                pragma Assert (Result = 0);
196             end if;
197          end if;
198       end loop;
199
200       if State (Abort_Task_Interrupt) /= User then
201          Keep_Unmasked (Abort_Task_Interrupt) := True;
202          Reserve (Abort_Task_Interrupt) := True;
203       end if;
204
205       --  Set SIGINT to unmasked state as long as it's
206       --  not in "User" state.  Check for Unreserve_All_Interrupts last
207
208       if State (SIGINT) /= User then
209          Keep_Unmasked (SIGINT) := True;
210          Reserve (SIGINT) := True;
211       end if;
212
213       --  Check all signals for state that requires keeping them
214       --  unmasked and reserved
215
216       for J in Interrupt_ID'Range loop
217          if State (J) = Default or else State (J) = Runtime then
218             Keep_Unmasked (J) := True;
219             Reserve (J) := True;
220          end if;
221       end loop;
222
223       --  Add the set of signals that must always be unmasked for this target
224
225       for J in Unmasked'Range loop
226          Keep_Unmasked (Interrupt_ID (Unmasked (J))) := True;
227          Reserve (Interrupt_ID (Unmasked (J))) := True;
228       end loop;
229
230       --  Add target-specific reserved signals
231
232       for J in Reserved'Range loop
233          Reserve (Interrupt_ID (Reserved (J))) := True;
234       end loop;
235
236       --  Process pragma Unreserve_All_Interrupts. This overrides any
237       --  settings due to pragma Interrupt_State:
238
239       if Unreserve_All_Interrupts /= 0 then
240          Keep_Unmasked (SIGINT) := False;
241          Reserve (SIGINT) := False;
242       end if;
243
244       --  We do not have Signal 0 in reality. We just use this value to
245       --  identify not existing signals (see s-intnam.ads). Therefore, Signal 0
246       --  should not be used in all signal related operations hence mark it as
247       --  reserved.
248
249       Reserve (0) := True;
250    end Initialize;
251
252 end System.Interrupt_Management;