OSDN Git Service

* doc/install.texi (xtensa-*-elf): New target.
[pf3gnuchains/gcc-fork.git] / gcc / ada / 5zintman.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                GNU ADA 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 --                             $Revision: 1.11 $
10 --                                                                          --
11 --             Copyright (C) 1991-2001 Florida State University             --
12 --                                                                          --
13 -- GNARL is free software; you can  redistribute it  and/or modify it under --
14 -- terms of the  GNU General Public License as published  by the Free Soft- --
15 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
16 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
19 -- for  more details.  You should have  received  a copy of the GNU General --
20 -- Public License  distributed with GNARL; see file COPYING.  If not, write --
21 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
22 -- MA 02111-1307, USA.                                                      --
23 --                                                                          --
24 -- As a special exception,  if other files  instantiate  generics from this --
25 -- unit, or you link  this unit with other files  to produce an executable, --
26 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
27 -- covered  by the  GNU  General  Public  License.  This exception does not --
28 -- however invalidate  any other reasons why  the executable file  might be --
29 -- covered by the  GNU Public License.                                      --
30 --                                                                          --
31 -- GNARL was developed by the GNARL team at Florida State University. It is --
32 -- now maintained by Ada Core Technologies Inc. in cooperation with Florida --
33 -- State University (http://www.gnat.com).                                  --
34 --                                                                          --
35 ------------------------------------------------------------------------------
36
37 --  This is the VxWorks version of this package.
38
39 --  It is likely to need tailoring to fit each operating system
40 --  and machine architecture.
41
42 --  PLEASE DO NOT add any dependences on other packages.
43 --  This package is designed to work with or without tasking support.
44
45 --  See the other warnings in the package specification before making
46 --  any modifications to this file.
47
48 --  Make a careful study of all signals available under the OS,
49 --  to see which need to be reserved, kept always unmasked,
50 --  or kept always unmasked.
51 --  Be on the lookout for special signals that
52 --  may be used by the thread library.
53
54 with Interfaces.C;
55 --  used for int and other types
56
57 with System.Error_Reporting;
58 pragma Warnings (Off, System.Error_Reporting);
59 --  used for Shutdown
60
61 with System.OS_Interface;
62 --  used for various Constants, Signal and types
63
64 with Unchecked_Conversion;
65
66 package body System.Interrupt_Management is
67
68    use Interfaces.C;
69    use System.Error_Reporting;
70    use System.OS_Interface;
71
72    function To_Isr is new Unchecked_Conversion (Long_Integer, isr_address);
73
74    type Interrupt_List is array (Interrupt_ID range <>) of Interrupt_ID;
75    Exception_Interrupts : constant Interrupt_List :=
76      (SIGFPE, SIGILL, SIGSEGV, SIGBUS);
77
78    --  Keep these variables global so that they are initialized only once.
79
80    Exception_Action : aliased struct_sigaction;
81    Default_Action : aliased struct_sigaction;
82
83    --  ????? Use these horrible imports here to solve elaboration order
84    --  problems.
85
86    type Task_Id is access all Integer;
87
88    Interrupt_ID_Map : array (Interrupt_ID) of Task_Id;
89    pragma Import (Ada, Interrupt_ID_Map,
90      "system__task_primitives__interrupt_operations__interrupt_id_map");
91
92    ----------------------
93    -- Notify_Exception --
94    ----------------------
95
96    procedure Notify_Exception (signo : Signal);
97    --  Identify the Ada exception to be raised using
98    --  the information when the system received a synchronous signal.
99
100    procedure Notify_Exception (signo : Signal) is
101       Mask   : aliased sigset_t;
102       Result : Interfaces.C.int;
103       My_Id  : pthread_t;
104    begin
105       --  VxWorks will always mask out the signal during the signal
106       --  handler and will reenable it on a longjmp.  GNAT does
107       --  not generate a longjmp to return from a signal handler
108       --  so the signal will still be masked unless we unmask it.
109       Result := pthread_sigmask (SIG_SETMASK, null, Mask'Unchecked_Access);
110       Result := sigdelset (Mask'Access, signo);
111       Result := pthread_sigmask (SIG_SETMASK, Mask'Unchecked_Access, null);
112
113       --  VxWorks will suspend the task when it gets a hardware
114       --  exception.  We take the liberty of resuming the task
115       --  for the application.
116       My_Id := taskIdSelf;
117       if taskIsSuspended (My_Id) /= 0 then
118          Result := taskResume (My_Id);
119       end if;
120
121       --  As long as we are using a longjmp to return control to the
122       --  exception handler on the runtime stack, we are safe. The original
123       --  signal mask (the one we had before coming into this signal catching
124       --  function) will be restored by the longjmp. Therefore, raising
125       --  an exception in this handler should be a safe operation.
126
127       --  Check that treatment of exception propagation here
128       --  is consistent with treatment of the abort signal in
129       --  System.Task_Primitives.Operations.
130
131       --  How can SIGSEGV be split into constraint and storage errors?
132       --  What should SIGILL really raise ? Some implementations have
133       --  codes for different types of SIGILL and some raise Storage_Error.
134       --  What causes SIGBUS and should it be caught?
135       --  Peter Burwood
136
137       case signo is
138          when SIGFPE =>
139             raise Constraint_Error;
140          when SIGILL =>
141             raise Constraint_Error;
142          when SIGSEGV =>
143             raise Program_Error;
144          when SIGBUS =>
145             raise Program_Error;
146          when others =>
147             pragma Assert (Shutdown ("Unexpected signal"));
148             null;
149       end case;
150    end Notify_Exception;
151
152    -------------------
153    -- Notify_Signal --
154    -------------------
155
156    --  VxWorks needs a special casing here. Each VxWorks task has a completely
157    --  separate signal handling, so the usual signal masking can't work.
158    --  This idea is to handle all the signals in all the tasks, and when
159    --  such a signal occurs, redirect it to the dedicated task (if any) or
160    --  reraise it.
161
162    procedure Notify_Signal (signo : Signal);
163
164    procedure Notify_Signal (signo : Signal) is
165       Mask    : aliased sigset_t;
166       Result  : Interfaces.C.int;
167       My_Id   : pthread_t;
168       old_isr : isr_address;
169
170       function Get_Thread_Id (T : Task_Id) return pthread_t;
171       pragma Import (Ada, Get_Thread_Id,
172         "system__task_primitives__operations__get_thread_id");
173
174    begin
175       --  VxWorks will always mask out the signal during the signal
176       --  handler and will reenable it on a longjmp.  GNAT does
177       --  not generate a longjmp to return from a signal handler
178       --  so the signal will still be masked unless we unmask it.
179       Result := pthread_sigmask (SIG_SETMASK, null, Mask'Unchecked_Access);
180       Result := sigdelset (Mask'Access, signo);
181       Result := pthread_sigmask (SIG_SETMASK, Mask'Unchecked_Access, null);
182
183       --  VxWorks will suspend the task when it gets a hardware
184       --  exception.  We take the liberty of resuming the task
185       --  for the application.
186       My_Id := taskIdSelf;
187       if taskIsSuspended (My_Id) /= 0 then
188          Result := taskResume (My_Id);
189       end if;
190
191       --  ??? Need a lock around this, in case the handler is detached
192       --  between the two following statements.
193
194       if Interrupt_ID_Map (Interrupt_ID (signo)) /= null then
195          Result :=
196            kill (Get_Thread_Id (Interrupt_ID_Map (Interrupt_ID (signo))),
197              Signal (signo));
198       else
199          old_isr := c_signal (signo, To_Isr (SIG_DFL));
200          Result := kill (My_Id, Signal (signo));
201       end if;
202    end Notify_Signal;
203
204    ---------------------------
205    -- Initialize_Interrupts --
206    ---------------------------
207
208    --  Since there is no signal inheritance between VxWorks tasks, we need
209    --  to initialize signal handling in each task.
210
211    procedure Initialize_Interrupts is
212       old_act : aliased struct_sigaction;
213       Result  : Interfaces.C.int;
214
215    begin
216       for J in Interrupt_ID'First + 1 .. Interrupt_ID'Last loop
217          if J /= Abort_Task_Interrupt then
218             Result := sigaction (Signal (J), Default_Action'Access,
219               old_act'Unchecked_Access);
220             pragma Assert (Result = 0);
221          end if;
222       end loop;
223
224       for J in Exception_Interrupts'Range loop
225          Keep_Unmasked (Exception_Interrupts (J)) := True;
226          Result :=
227            sigaction
228              (Signal (Exception_Interrupts (J)), Exception_Action'Access,
229               old_act'Unchecked_Access);
230          pragma Assert (Result = 0);
231       end loop;
232    end Initialize_Interrupts;
233
234 begin
235    declare
236       mask         : aliased sigset_t;
237       default_mask : aliased sigset_t;
238       Result       : Interfaces.C.int;
239
240    begin
241       --  The VxWorks POSIX threads library currently needs initialization.
242       --  We wish it could be in System.OS_Interface, but that would
243       --  cause an elaboration problem.
244
245       pthread_init;
246
247       Abort_Task_Interrupt := SIGABRT;
248       --  Change this if you want to use another signal for task abort.
249       --  SIGTERM might be a good one.
250
251       Exception_Action.sa_handler := Notify_Exception'Address;
252       Default_Action.sa_handler   := Notify_Signal'Address;
253
254       Exception_Action.sa_flags := SA_SIGINFO + SA_ONSTACK;
255       Default_Action.sa_flags := SA_SIGINFO + SA_ONSTACK;
256       --  Send us extra signal information (SA_SIGINFO) on the
257       --  stack (SA_ONSTACK).
258       --  There is no SA_NODEFER in VxWorks.  The signal mask is
259       --  restored after a longjmp so the SA_NODEFER option is
260       --  not needed.  - Dan Eischen
261
262       Result := sigemptyset (mask'Access);
263       pragma Assert (Result = 0);
264       Result := sigemptyset (default_mask'Access);
265       pragma Assert (Result = 0);
266
267       for J in Interrupt_ID'First + 1 .. Interrupt_ID'Last loop
268          Result := sigaddset (default_mask'Access, Signal (J));
269          pragma Assert (Result = 0);
270       end loop;
271
272       for J in Exception_Interrupts'Range loop
273          Result := sigaddset (mask'Access, Signal (Exception_Interrupts (J)));
274          pragma Assert (Result = 0);
275          Result :=
276            sigdelset (default_mask'Access, Signal (Exception_Interrupts (J)));
277          pragma Assert (Result = 0);
278       end loop;
279
280       Exception_Action.sa_mask := mask;
281       Default_Action.sa_mask := default_mask;
282
283       --  Initialize_Interrupts is called for each task in Enter_Task
284
285       Keep_Unmasked (Abort_Task_Interrupt) := True;
286
287       Reserve := Reserve or Keep_Unmasked or Keep_Masked;
288
289       Reserve (0) := True;
290       --  We do not have Signal 0 in reality. We just use this value
291       --  to identify non-existent signals (see s-intnam.ads). Therefore,
292       --  Signal 0 should not be used in all signal related operations hence
293       --  mark it as reserved.
294    end;
295 end System.Interrupt_Management;