1 ------------------------------------------------------------------------------
3 -- GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS --
5 -- S Y S T E M . I N T E R R U P T S --
9 -- Copyright (C) 1992-2002, 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 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, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
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. --
29 -- GNARL was developed by the GNARL team at Florida State University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
36 -- All user-handleable signals are masked at all times in all
37 -- tasks/threads except possibly for the Interrupt_Manager task.
39 -- When a user task wants to have the effect of masking/unmasking an
40 -- signal, it must call Block_Interrupt/Unblock_Interrupt, which
41 -- will have the effect of unmasking/masking the signal in the
42 -- Interrupt_Manager task. These comments do not apply to vectored
43 -- hardware interrupts, which may be masked or unmasked using routined
44 -- interfaced to the relevant VxWorks system calls.
46 -- Once we associate a Signal_Server_Task with an signal, the task never
47 -- goes away, and we never remove the association. On the other hand, it
48 -- is more convenient to terminate an associated Interrupt_Server_Task
49 -- for a vectored hardware interrupt (since we use a binary semaphore
50 -- for synchronization with the umbrella handler).
52 -- There is no more than one signal per Signal_Server_Task and no more than
53 -- one Signal_Server_Task per signal. The same relation holds for hardware
54 -- interrupts and Interrupt_Server_Task's at any given time. That is,
55 -- only one non-terminated Interrupt_Server_Task exists for a give
56 -- interrupt at any time.
58 -- Within this package, the lock L is used to protect the various status
59 -- tables. If there is a Server_Task associated with a signal or interrupt,
60 -- we use the per-task lock of the Server_Task instead so that we protect the
61 -- status between Interrupt_Manager and Server_Task. Protection among
62 -- service requests are ensured via user calls to the Interrupt_Manager
65 -- This is the VxWorks version of this package, supporting vectored hardware
68 with Unchecked_Conversion
;
70 with System
.OS_Interface
; use System
.OS_Interface
;
72 with Interfaces
.VxWorks
;
74 with Ada
.Task_Identification
;
75 -- used for Task_ID type
78 -- used for Raise_Exception
80 with System
.Task_Primitives
.Operations
;
81 -- used for Write_Lock
88 with System
.Storage_Elements
;
89 -- used for To_Address
98 -- Interrupt_Manager_ID
100 with System
.Tasking
.Utilities
;
101 -- used for Make_Independent
103 with System
.Tasking
.Rendezvous
;
104 -- used for Call_Simple
105 pragma Elaborate_All
(System
.Tasking
.Rendezvous
);
107 package body System
.Interrupts
is
112 package PRI
renames System
.Task_Primitives
;
113 package POP
renames System
.Task_Primitives
.Operations
;
115 function To_Ada
is new Unchecked_Conversion
116 (System
.Tasking
.Task_ID
, Ada
.Task_Identification
.Task_Id
);
118 function To_System
is new Unchecked_Conversion
119 (Ada
.Task_Identification
.Task_Id
, Task_ID
);
125 -- WARNING: System.Tasking.Stages performs calls to this task
126 -- with low-level constructs. Do not change this spec without synchro-
129 task Interrupt_Manager
is
130 entry Detach_Interrupt_Entries
(T
: Task_ID
);
133 (New_Handler
: Parameterless_Handler
;
134 Interrupt
: Interrupt_ID
;
136 Restoration
: Boolean := False);
138 entry Exchange_Handler
139 (Old_Handler
: out Parameterless_Handler
;
140 New_Handler
: Parameterless_Handler
;
141 Interrupt
: Interrupt_ID
;
145 (Interrupt
: Interrupt_ID
;
148 entry Bind_Interrupt_To_Entry
150 E
: Task_Entry_Index
;
151 Interrupt
: Interrupt_ID
);
153 pragma Interrupt_Priority
(System
.Interrupt_Priority
'First);
154 end Interrupt_Manager
;
156 task type Interrupt_Server_Task
157 (Interrupt
: Interrupt_ID
; Int_Sema
: SEM_ID
) is
158 -- Server task for vectored hardware interrupt handling
159 pragma Interrupt_Priority
(System
.Interrupt_Priority
'First + 2);
160 end Interrupt_Server_Task
;
162 type Interrupt_Task_Access
is access Interrupt_Server_Task
;
164 -------------------------------
165 -- Local Types and Variables --
166 -------------------------------
168 type Entry_Assoc
is record
170 E
: Task_Entry_Index
;
173 type Handler_Assoc
is record
174 H
: Parameterless_Handler
;
175 Static
: Boolean; -- Indicates static binding;
178 User_Handler
: array (Interrupt_ID
) of Handler_Assoc
:=
179 (others => (null, Static
=> False));
180 pragma Volatile_Components
(User_Handler
);
181 -- Holds the protected procedure handler (if any) and its Static
182 -- information for each interrupt or signal. A handler is static
183 -- iff it is specified through the pragma Attach_Handler.
185 User_Entry
: array (Interrupt_ID
) of Entry_Assoc
:=
186 (others => (T
=> Null_Task
, E
=> Null_Task_Entry
));
187 pragma Volatile_Components
(User_Entry
);
188 -- Holds the task and entry index (if any) for each interrupt / signal
190 -- Type and Head, Tail of the list containing Registered Interrupt
191 -- Handlers. These definitions are used to register the handlers
192 -- specified by the pragma Interrupt_Handler.
194 type Registered_Handler
;
195 type R_Link
is access all Registered_Handler
;
197 type Registered_Handler
is record
198 H
: System
.Address
:= System
.Null_Address
;
199 Next
: R_Link
:= null;
202 Registered_Handler_Head
: R_Link
:= null;
203 Registered_Handler_Tail
: R_Link
:= null;
205 Server_ID
: array (Interrupt_ID
) of System
.Tasking
.Task_ID
:=
206 (others => System
.Tasking
.Null_Task
);
207 pragma Atomic_Components
(Server_ID
);
208 -- Holds the Task_ID of the Server_Task for each interrupt / signal.
209 -- Task_ID is needed to accomplish locking per interrupt base. Also
210 -- is needed to determine whether to create a new Server_Task.
212 Semaphore_ID_Map
: array
213 (Interrupt_ID
range 0 .. System
.OS_Interface
.Max_HW_Interrupt
)
214 of SEM_ID
:= (others => 0);
215 -- Array of binary semaphores associated with vectored interrupts
216 -- Note that the last bound should be Max_HW_Interrupt, but this will raise
217 -- Storage_Error if Num_HW_Interrupts is null, so use an extra 4 bytes
220 Interrupt_Access_Hold
: Interrupt_Task_Access
;
221 -- Variable for allocating an Interrupt_Server_Task
223 Default_Handler
: array (HW_Interrupt
) of Interfaces
.VxWorks
.VOIDFUNCPTR
;
224 -- Vectored interrupt handlers installed prior to program startup.
225 -- These are saved only when the umbrella handler is installed for
226 -- a given interrupt number.
228 -----------------------
229 -- Local Subprograms --
230 -----------------------
232 procedure Check_Reserved_Interrupt
(Interrupt
: Interrupt_ID
);
233 -- Check if Id is a reserved interrupt, and if so raise Program_Error
234 -- with an appropriate message, otherwise return.
236 procedure Finalize_Interrupt_Servers
;
237 -- Unbind the handlers for hardware interrupt server tasks at program
240 function Is_Registered
(Handler
: Parameterless_Handler
) return Boolean;
241 -- See if Handler has been "pragma"ed using Interrupt_Handler.
242 -- Always consider a null handler as registered.
244 procedure Notify_Interrupt
(Param
: System
.Address
);
245 -- Umbrella handler for vectored interrupts (not signals)
247 procedure Install_Default_Action
(Interrupt
: HW_Interrupt
);
248 -- Restore a handler that was in place prior to program execution
250 procedure Install_Umbrella_Handler
251 (Interrupt
: HW_Interrupt
;
252 Handler
: Interfaces
.VxWorks
.VOIDFUNCPTR
);
253 -- Install the runtime umbrella handler for a vectored hardware
256 procedure Unimplemented
(Feature
: String);
257 pragma No_Return
(Unimplemented
);
258 -- Used to mark a call to an unimplemented function. Raises Program_Error
259 -- with an appropriate message noting that Feature is unimplemented.
265 -- Calling this procedure with New_Handler = null and Static = True
266 -- means we want to detach the current handler regardless of the
267 -- previous handler's binding status (ie. do not care if it is a
268 -- dynamic or static handler).
270 -- This option is needed so that during the finalization of a PO, we
271 -- can detach handlers attached through pragma Attach_Handler.
273 procedure Attach_Handler
274 (New_Handler
: Parameterless_Handler
;
275 Interrupt
: Interrupt_ID
;
276 Static
: Boolean := False) is
278 Check_Reserved_Interrupt
(Interrupt
);
279 Interrupt_Manager
.Attach_Handler
(New_Handler
, Interrupt
, Static
);
282 -----------------------------
283 -- Bind_Interrupt_To_Entry --
284 -----------------------------
286 -- This procedure raises a Program_Error if it tries to
287 -- bind an interrupt to which an Entry or a Procedure is
290 procedure Bind_Interrupt_To_Entry
292 E
: Task_Entry_Index
;
293 Int_Ref
: System
.Address
)
295 Interrupt
: constant Interrupt_ID
:=
296 Interrupt_ID
(Storage_Elements
.To_Integer
(Int_Ref
));
299 Check_Reserved_Interrupt
(Interrupt
);
300 Interrupt_Manager
.Bind_Interrupt_To_Entry
(T
, E
, Interrupt
);
301 end Bind_Interrupt_To_Entry
;
303 ---------------------
304 -- Block_Interrupt --
305 ---------------------
307 procedure Block_Interrupt
(Interrupt
: Interrupt_ID
) is
309 Unimplemented
("Block_Interrupt");
312 ------------------------------
313 -- Check_Reserved_Interrupt --
314 ------------------------------
316 procedure Check_Reserved_Interrupt
(Interrupt
: Interrupt_ID
) is
318 if Is_Reserved
(Interrupt
) then
320 (Program_Error
'Identity,
321 "Interrupt" & Interrupt_ID
'Image (Interrupt
) & " is reserved");
325 end Check_Reserved_Interrupt
;
327 ---------------------
328 -- Current_Handler --
329 ---------------------
331 function Current_Handler
332 (Interrupt
: Interrupt_ID
) return Parameterless_Handler
is
334 Check_Reserved_Interrupt
(Interrupt
);
336 -- ??? Since Parameterless_Handler is not Atomic, the
337 -- current implementation is wrong. We need a new service in
338 -- Interrupt_Manager to ensure atomicity.
340 return User_Handler
(Interrupt
).H
;
347 -- Calling this procedure with Static = True means we want to Detach the
348 -- current handler regardless of the previous handler's binding status
349 -- (i.e. do not care if it is a dynamic or static handler).
351 -- This option is needed so that during the finalization of a PO, we can
352 -- detach handlers attached through pragma Attach_Handler.
354 procedure Detach_Handler
355 (Interrupt
: Interrupt_ID
;
356 Static
: Boolean := False) is
358 Check_Reserved_Interrupt
(Interrupt
);
359 Interrupt_Manager
.Detach_Handler
(Interrupt
, Static
);
362 ------------------------------
363 -- Detach_Interrupt_Entries --
364 ------------------------------
366 procedure Detach_Interrupt_Entries
(T
: Task_ID
) is
368 Interrupt_Manager
.Detach_Interrupt_Entries
(T
);
369 end Detach_Interrupt_Entries
;
371 ----------------------
372 -- Exchange_Handler --
373 ----------------------
375 -- Calling this procedure with New_Handler = null and Static = True
376 -- means we want to detach the current handler regardless of the
377 -- previous handler's binding status (ie. do not care if it is a
378 -- dynamic or static handler).
380 -- This option is needed so that during the finalization of a PO, we
381 -- can detach handlers attached through pragma Attach_Handler.
383 procedure Exchange_Handler
384 (Old_Handler
: out Parameterless_Handler
;
385 New_Handler
: Parameterless_Handler
;
386 Interrupt
: Interrupt_ID
;
387 Static
: Boolean := False) is
389 Check_Reserved_Interrupt
(Interrupt
);
390 Interrupt_Manager
.Exchange_Handler
391 (Old_Handler
, New_Handler
, Interrupt
, Static
);
392 end Exchange_Handler
;
398 procedure Finalize
(Object
: in out Static_Interrupt_Protection
) is
400 -- ??? loop to be executed only when we're not doing library level
401 -- finalization, since in this case all interrupt / signal tasks are
404 if not Interrupt_Manager
'Terminated then
405 for N
in reverse Object
.Previous_Handlers
'Range loop
406 Interrupt_Manager
.Attach_Handler
407 (New_Handler
=> Object
.Previous_Handlers
(N
).Handler
,
408 Interrupt
=> Object
.Previous_Handlers
(N
).Interrupt
,
409 Static
=> Object
.Previous_Handlers
(N
).Static
,
410 Restoration
=> True);
414 Tasking
.Protected_Objects
.Entries
.Finalize
415 (Tasking
.Protected_Objects
.Entries
.Protection_Entries
(Object
));
418 --------------------------------
419 -- Finalize_Interrupt_Servers --
420 --------------------------------
422 -- Restore default handlers for interrupt servers.
423 -- This is called by the Interrupt_Manager task when it receives the abort
424 -- signal during program finalization.
426 procedure Finalize_Interrupt_Servers
is
428 if HW_Interrupt
'Last >= 0 then
429 for Int
in HW_Interrupt
loop
430 if Server_ID
(Interrupt_ID
(Int
)) /= null
432 not Ada
.Task_Identification
.Is_Terminated
433 (To_Ada
(Server_ID
(Interrupt_ID
(Int
))))
435 Interrupt_Manager
.Attach_Handler
436 (New_Handler
=> null,
437 Interrupt
=> Interrupt_ID
(Int
),
439 Restoration
=> True);
443 end Finalize_Interrupt_Servers
;
445 -------------------------------------
446 -- Has_Interrupt_Or_Attach_Handler --
447 -------------------------------------
449 function Has_Interrupt_Or_Attach_Handler
450 (Object
: access Dynamic_Interrupt_Protection
) return Boolean is
453 end Has_Interrupt_Or_Attach_Handler
;
455 function Has_Interrupt_Or_Attach_Handler
456 (Object
: access Static_Interrupt_Protection
) return Boolean is
459 end Has_Interrupt_Or_Attach_Handler
;
461 ----------------------
462 -- Ignore_Interrupt --
463 ----------------------
465 procedure Ignore_Interrupt
(Interrupt
: Interrupt_ID
) is
467 Unimplemented
("Ignore_Interrupt");
468 end Ignore_Interrupt
;
470 ----------------------------
471 -- Install_Default_Action --
472 ----------------------------
474 procedure Install_Default_Action
(Interrupt
: HW_Interrupt
) is
476 -- Restore original interrupt handler
478 Interfaces
.VxWorks
.intVecSet
479 (Interfaces
.VxWorks
.INUM_TO_IVEC
(Integer (Interrupt
)),
480 Default_Handler
(Interrupt
));
481 Default_Handler
(Interrupt
) := null;
482 end Install_Default_Action
;
484 ----------------------
485 -- Install_Handlers --
486 ----------------------
488 procedure Install_Handlers
489 (Object
: access Static_Interrupt_Protection
;
490 New_Handlers
: New_Handler_Array
) is
492 for N
in New_Handlers
'Range loop
493 -- We need a lock around this ???
495 Object
.Previous_Handlers
(N
).Interrupt
:= New_Handlers
(N
).Interrupt
;
496 Object
.Previous_Handlers
(N
).Static
:= User_Handler
497 (New_Handlers
(N
).Interrupt
).Static
;
499 -- We call Exchange_Handler and not directly Interrupt_Manager.
500 -- Exchange_Handler so we get the Is_Reserved check.
503 (Old_Handler
=> Object
.Previous_Handlers
(N
).Handler
,
504 New_Handler
=> New_Handlers
(N
).Handler
,
505 Interrupt
=> New_Handlers
(N
).Interrupt
,
508 end Install_Handlers
;
510 ------------------------------
511 -- Install_Umbrella_Handler --
512 ------------------------------
514 procedure Install_Umbrella_Handler
515 (Interrupt
: HW_Interrupt
;
516 Handler
: Interfaces
.VxWorks
.VOIDFUNCPTR
)
518 use Interfaces
.VxWorks
;
520 Vec
: constant Interrupt_Vector
:=
521 INUM_TO_IVEC
(Interfaces
.VxWorks
.int
(Interrupt
));
522 Old_Handler
: constant VOIDFUNCPTR
:=
523 intVecGet
(INUM_TO_IVEC
(Interfaces
.VxWorks
.int
(Interrupt
)));
524 Stat
: Interfaces
.VxWorks
.STATUS
;
527 -- Only install umbrella handler when no Ada handler has already been
528 -- installed. Note that the interrupt number is passed as a parameter
529 -- when an interrupt occurs, so the umbrella handler has a different
530 -- wrapper generated by intConnect for each interrupt number.
532 if Default_Handler
(Interrupt
) = null then
534 intConnect
(Vec
, VOIDFUNCPTR
(Handler
), System
.Address
(Interrupt
));
535 Default_Handler
(Interrupt
) := Old_Handler
;
537 end Install_Umbrella_Handler
;
543 function Is_Blocked
(Interrupt
: Interrupt_ID
) return Boolean is
545 Unimplemented
("Is_Blocked");
549 -----------------------
550 -- Is_Entry_Attached --
551 -----------------------
553 function Is_Entry_Attached
(Interrupt
: Interrupt_ID
) return Boolean is
555 Check_Reserved_Interrupt
(Interrupt
);
556 return User_Entry
(Interrupt
).T
/= Null_Task
;
557 end Is_Entry_Attached
;
559 -------------------------
560 -- Is_Handler_Attached --
561 -------------------------
563 function Is_Handler_Attached
(Interrupt
: Interrupt_ID
) return Boolean is
565 Check_Reserved_Interrupt
(Interrupt
);
566 return User_Handler
(Interrupt
).H
/= null;
567 end Is_Handler_Attached
;
573 function Is_Ignored
(Interrupt
: Interrupt_ID
) return Boolean is
575 Unimplemented
("Is_Ignored");
583 function Is_Registered
(Handler
: Parameterless_Handler
) return Boolean is
584 type Fat_Ptr
is record
585 Object_Addr
: System
.Address
;
586 Handler_Addr
: System
.Address
;
589 function To_Fat_Ptr
is new Unchecked_Conversion
590 (Parameterless_Handler
, Fat_Ptr
);
596 if Handler
= null then
600 Fat
:= To_Fat_Ptr
(Handler
);
602 Ptr
:= Registered_Handler_Head
;
604 while (Ptr
/= null) loop
605 if Ptr
.H
= Fat
.Handler_Addr
then
619 function Is_Reserved
(Interrupt
: Interrupt_ID
) return Boolean is
624 ----------------------
625 -- Notify_Interrupt --
626 ----------------------
628 -- Umbrella handler for vectored hardware interrupts (as opposed to
629 -- signals and exceptions). As opposed to the signal implementation,
630 -- this handler is only installed in the vector table while there is
631 -- an active association of an Ada handler to the interrupt.
633 -- Otherwise, the handler that existed prior to program startup is
634 -- in the vector table. This ensures that handlers installed by
635 -- the BSP are active unless explicitly replaced in the program text.
637 -- Each Interrupt_Server_Task has an associated binary semaphore
638 -- on which it pends once it's been started. This routine determines
639 -- The appropriate semaphore and and issues a semGive call, waking
640 -- the server task. When a handler is unbound,
641 -- System.Interrupts.Unbind_Handler issues a semFlush, and the
642 -- server task deletes its semaphore and terminates.
644 procedure Notify_Interrupt
(Param
: System
.Address
) is
645 Interrupt
: Interrupt_ID
:= Interrupt_ID
(Param
);
646 Discard_Result
: STATUS
;
649 Discard_Result
:= semGive
(Semaphore_ID_Map
(Interrupt
));
650 end Notify_Interrupt
;
656 function Reference
(Interrupt
: Interrupt_ID
) return System
.Address
is
658 Check_Reserved_Interrupt
(Interrupt
);
659 return Storage_Elements
.To_Address
660 (Storage_Elements
.Integer_Address
(Interrupt
));
663 --------------------------------
664 -- Register_Interrupt_Handler --
665 --------------------------------
667 procedure Register_Interrupt_Handler
(Handler_Addr
: System
.Address
) is
668 New_Node_Ptr
: R_Link
;
670 -- This routine registers a handler as usable for dynamic
671 -- interrupt handler association. Routines attaching and detaching
672 -- handlers dynamically should determine whether the handler is
673 -- registered. Program_Error should be raised if it is not registered.
675 -- Pragma Interrupt_Handler can only appear in a library
676 -- level PO definition and instantiation. Therefore, we do not need
677 -- to implement an unregister operation. Nor do we need to
678 -- protect the queue structure with a lock.
680 pragma Assert
(Handler_Addr
/= System
.Null_Address
);
682 New_Node_Ptr
:= new Registered_Handler
;
683 New_Node_Ptr
.H
:= Handler_Addr
;
685 if Registered_Handler_Head
= null then
686 Registered_Handler_Head
:= New_Node_Ptr
;
687 Registered_Handler_Tail
:= New_Node_Ptr
;
690 Registered_Handler_Tail
.Next
:= New_Node_Ptr
;
691 Registered_Handler_Tail
:= New_Node_Ptr
;
693 end Register_Interrupt_Handler
;
695 -----------------------
696 -- Unblock_Interrupt --
697 -----------------------
699 procedure Unblock_Interrupt
(Interrupt
: Interrupt_ID
) is
701 Unimplemented
("Unblock_Interrupt");
702 end Unblock_Interrupt
;
708 function Unblocked_By
709 (Interrupt
: Interrupt_ID
) return System
.Tasking
.Task_ID
is
711 Unimplemented
("Unblocked_By");
715 ------------------------
716 -- Unignore_Interrupt --
717 ------------------------
719 procedure Unignore_Interrupt
(Interrupt
: Interrupt_ID
) is
721 Unimplemented
("Unignore_Interrupt");
722 end Unignore_Interrupt
;
728 procedure Unimplemented
(Feature
: String) is
731 (Program_Error
'Identity,
732 Feature
& " not implemented on VxWorks");
735 -----------------------
736 -- Interrupt_Manager --
737 -----------------------
739 task body Interrupt_Manager
is
740 ---------------------
741 -- Local Variables --
742 ---------------------
744 Self_Id
: constant Task_ID
:= POP
.Self
;
750 procedure Bind_Handler
(Interrupt
: Interrupt_ID
);
751 -- This procedure does not do anything if a signal is blocked.
752 -- Otherwise, we have to interrupt Server_Task for status change through
755 procedure Unbind_Handler
(Interrupt
: Interrupt_ID
);
756 -- This procedure does not do anything if a signal is blocked.
757 -- Otherwise, we have to interrupt Server_Task for status change
758 -- through an abort signal.
760 procedure Unprotected_Exchange_Handler
761 (Old_Handler
: out Parameterless_Handler
;
762 New_Handler
: Parameterless_Handler
;
763 Interrupt
: Interrupt_ID
;
765 Restoration
: Boolean := False);
767 procedure Unprotected_Detach_Handler
768 (Interrupt
: Interrupt_ID
;
775 procedure Bind_Handler
(Interrupt
: Interrupt_ID
) is
777 Install_Umbrella_Handler
778 (HW_Interrupt
(Interrupt
), Notify_Interrupt
'Access);
785 procedure Unbind_Handler
(Interrupt
: Interrupt_ID
) is
790 -- Hardware interrupt
792 Install_Default_Action
(HW_Interrupt
(Interrupt
));
794 -- Flush server task off semaphore, allowing it to terminate
796 S
:= semFlush
(Semaphore_ID_Map
(Interrupt
));
797 pragma Assert
(S
= 0);
800 --------------------------------
801 -- Unprotected_Detach_Handler --
802 --------------------------------
804 procedure Unprotected_Detach_Handler
805 (Interrupt
: Interrupt_ID
;
808 Old_Handler
: Parameterless_Handler
;
810 if User_Entry
(Interrupt
).T
/= Null_Task
then
811 -- If an interrupt entry is installed raise
812 -- Program_Error. (propagate it to the caller).
814 Raise_Exception
(Program_Error
'Identity,
815 "An interrupt entry is already installed");
818 -- Note : Static = True will pass the following check. This is the
819 -- case when we want to detach a handler regardless of the static
820 -- status of the Current_Handler.
822 if not Static
and then User_Handler
(Interrupt
).Static
then
823 -- Trying to detach a static Interrupt Handler.
824 -- raise Program_Error.
826 Raise_Exception
(Program_Error
'Identity,
827 "Trying to detach a static Interrupt Handler");
830 Old_Handler
:= User_Handler
(Interrupt
).H
;
834 User_Handler
(Interrupt
).H
:= null;
835 User_Handler
(Interrupt
).Static
:= False;
837 if Old_Handler
/= null then
838 Unbind_Handler
(Interrupt
);
840 end Unprotected_Detach_Handler
;
842 ----------------------------------
843 -- Unprotected_Exchange_Handler --
844 ----------------------------------
846 procedure Unprotected_Exchange_Handler
847 (Old_Handler
: out Parameterless_Handler
;
848 New_Handler
: Parameterless_Handler
;
849 Interrupt
: Interrupt_ID
;
851 Restoration
: Boolean := False) is
853 if User_Entry
(Interrupt
).T
/= Null_Task
then
854 -- If an interrupt entry is already installed, raise
855 -- Program_Error. (propagate it to the caller).
858 (Program_Error
'Identity,
859 "An interrupt is already installed");
862 -- Note : A null handler with Static = True will
863 -- pass the following check. This is the case when we want to
864 -- detach a handler regardless of the Static status
865 -- of Current_Handler.
866 -- We don't check anything if Restoration is True, since we
867 -- may be detaching a static handler to restore a dynamic one.
869 if not Restoration
and then not Static
870 and then (User_Handler
(Interrupt
).Static
872 -- Trying to overwrite a static Interrupt Handler with a
875 -- The new handler is not specified as an
876 -- Interrupt Handler by a pragma.
878 or else not Is_Registered
(New_Handler
))
881 (Program_Error
'Identity,
882 "Trying to overwrite a static Interrupt Handler with a " &
886 -- Save the old handler
888 Old_Handler
:= User_Handler
(Interrupt
).H
;
892 User_Handler
(Interrupt
).H
:= New_Handler
;
894 if New_Handler
= null then
896 -- The null handler means we are detaching the handler.
898 User_Handler
(Interrupt
).Static
:= False;
901 User_Handler
(Interrupt
).Static
:= Static
;
904 -- Invoke a corresponding Server_Task if not yet created.
905 -- Place Task_ID info in Server_ID array.
907 if New_Handler
/= null
909 (Server_ID
(Interrupt
) = Null_Task
911 Ada
.Task_Identification
.Is_Terminated
912 (To_Ada
(Server_ID
(Interrupt
))))
914 Interrupt_Access_Hold
:=
915 new Interrupt_Server_Task
916 (Interrupt
, semBCreate
(SEM_Q_FIFO
, SEM_EMPTY
));
917 Server_ID
(Interrupt
) :=
918 To_System
(Interrupt_Access_Hold
.all'Identity);
921 if (New_Handler
= null) and then Old_Handler
/= null then
922 -- Restore default handler
924 Unbind_Handler
(Interrupt
);
926 elsif Old_Handler
= null then
927 -- Save default handler
929 Bind_Handler
(Interrupt
);
931 end Unprotected_Exchange_Handler
;
933 -- Start of processing for Interrupt_Manager
936 -- By making this task independent of any master, when the process
937 -- goes away, the Interrupt_Manager will terminate gracefully.
939 System
.Tasking
.Utilities
.Make_Independent
;
942 -- A block is needed to absorb Program_Error exception
945 Old_Handler
: Parameterless_Handler
;
949 accept Attach_Handler
950 (New_Handler
: Parameterless_Handler
;
951 Interrupt
: Interrupt_ID
;
953 Restoration
: Boolean := False)
955 Unprotected_Exchange_Handler
956 (Old_Handler
, New_Handler
, Interrupt
, Static
, Restoration
);
960 accept Exchange_Handler
961 (Old_Handler
: out Parameterless_Handler
;
962 New_Handler
: Parameterless_Handler
;
963 Interrupt
: Interrupt_ID
;
966 Unprotected_Exchange_Handler
967 (Old_Handler
, New_Handler
, Interrupt
, Static
);
968 end Exchange_Handler
;
971 accept Detach_Handler
972 (Interrupt
: Interrupt_ID
;
975 Unprotected_Detach_Handler
(Interrupt
, Static
);
978 accept Bind_Interrupt_To_Entry
980 E
: Task_Entry_Index
;
981 Interrupt
: Interrupt_ID
)
983 -- If there is a binding already (either a procedure or an
984 -- entry), raise Program_Error (propagate it to the caller).
986 if User_Handler
(Interrupt
).H
/= null
987 or else User_Entry
(Interrupt
).T
/= Null_Task
990 (Program_Error
'Identity,
991 "A binding for this interrupt is already present");
994 User_Entry
(Interrupt
) := Entry_Assoc
' (T => T, E => E);
996 -- Indicate the attachment of interrupt entry in the ATCB.
997 -- This is needed so when an interrupt entry task terminates
998 -- the binding can be cleaned. The call to unbinding must be
999 -- make by the task before it terminates.
1001 T.Interrupt_Entry := True;
1003 -- Invoke a corresponding Server_Task if not yet created.
1004 -- Place Task_ID info in Server_ID array.
1006 if Server_ID (Interrupt) = Null_Task
1008 Ada.Task_Identification.Is_Terminated
1009 (To_Ada (Server_ID (Interrupt)))
1011 Interrupt_Access_Hold := new Interrupt_Server_Task
1012 (Interrupt, semBCreate (SEM_Q_FIFO, SEM_EMPTY));
1013 Server_ID (Interrupt) :=
1014 To_System (Interrupt_Access_Hold.all'Identity);
1017 Bind_Handler (Interrupt);
1018 end Bind_Interrupt_To_Entry;
1021 accept Detach_Interrupt_Entries (T : Task_ID) do
1022 for Int in Interrupt_ID'Range loop
1023 if not Is_Reserved (Int) then
1024 if User_Entry (Int).T = T then
1025 User_Entry (Int) := Entry_Assoc'
1026 (T
=> Null_Task
, E
=> Null_Task_Entry
);
1027 Unbind_Handler
(Int
);
1032 -- Indicate in ATCB that no interrupt entries are attached.
1034 T
.Interrupt_Entry
:= False;
1035 end Detach_Interrupt_Entries
;
1039 -- If there is a Program_Error we just want to propagate it to
1040 -- the caller and do not want to stop this task.
1042 when Program_Error
=>
1046 pragma Assert
(False);
1052 when Standard
'Abort_Signal =>
1053 -- Flush interrupt server semaphores, so they can terminate
1054 Finalize_Interrupt_Servers
;
1056 end Interrupt_Manager
;
1058 ---------------------------
1059 -- Interrupt_Server_Task --
1060 ---------------------------
1062 -- Server task for vectored hardware interrupt handling
1064 task body Interrupt_Server_Task
is
1065 Self_Id
: constant Task_ID
:= Self
;
1066 Tmp_Handler
: Parameterless_Handler
;
1068 Tmp_Entry_Index
: Task_Entry_Index
;
1074 System
.Tasking
.Utilities
.Make_Independent
;
1075 Semaphore_ID_Map
(Interrupt
) := Int_Sema
;
1078 -- Pend on semaphore that will be triggered by the
1079 -- umbrella handler when the associated interrupt comes in
1081 S
:= semTake
(Int_Sema
, WAIT_FOREVER
);
1082 pragma Assert
(S
= 0);
1084 if User_Handler
(Interrupt
).H
/= null then
1086 -- Protected procedure handler
1088 Tmp_Handler
:= User_Handler
(Interrupt
).H
;
1091 elsif User_Entry
(Interrupt
).T
/= Null_Task
then
1093 -- Interrupt entry handler
1095 Tmp_ID
:= User_Entry
(Interrupt
).T
;
1096 Tmp_Entry_Index
:= User_Entry
(Interrupt
).E
;
1097 System
.Tasking
.Rendezvous
.Call_Simple
1098 (Tmp_ID
, Tmp_Entry_Index
, System
.Null_Address
);
1101 -- Semaphore has been flushed by an unbind operation in
1102 -- the Interrupt_Manager. Terminate the server task.
1104 -- Wait for the Interrupt_Manager to complete its work
1106 POP
.Write_Lock
(Self_Id
);
1108 -- Delete the associated semaphore
1110 S
:= semDelete
(Int_Sema
);
1112 pragma Assert
(S
= 0);
1114 -- Set status for the Interrupt_Manager
1116 Semaphore_ID_Map
(Interrupt
) := 0;
1117 Server_ID
(Interrupt
) := Null_Task
;
1118 POP
.Unlock
(Self_Id
);
1123 end Interrupt_Server_Task
;
1126 -- Get Interrupt_Manager's ID so that Abort_Interrupt can be sent.
1128 Interrupt_Manager_ID
:= To_System
(Interrupt_Manager
'Identity);
1129 end System
.Interrupts
;