1 ------------------------------------------------------------------------------
3 -- GNAT 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-2006, 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, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, 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 tasks/threads
37 -- except possibly for the Interrupt_Manager task.
39 -- When a user task wants to have the effect of masking/unmasking an signal,
40 -- it must call Block_Interrupt/Unblock_Interrupt, which will have the effect
41 -- of unmasking/masking the signal in the Interrupt_Manager task. These
42 -- comments do not apply to vectored hardware interrupts, which may be masked
43 -- or unmasked using routined interfaced to the relevant VxWorks system
46 -- Once we associate a Signal_Server_Task with an signal, the task never goes
47 -- away, and we never remove the association. On the other hand, it is more
48 -- convenient to terminate an associated Interrupt_Server_Task for a vectored
49 -- hardware interrupt (since we use a binary semaphore for synchronization
50 -- 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, only
55 -- one non-terminated Interrupt_Server_Task exists for a give interrupt at
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
.Interrupt_Management
;
83 with System
.Task_Primitives
.Operations
;
84 -- used for Write_Lock
91 with System
.Storage_Elements
;
92 -- used for To_Address
96 with System
.Tasking
.Utilities
;
97 -- used for Make_Independent
99 with System
.Tasking
.Rendezvous
;
100 -- used for Call_Simple
101 pragma Elaborate_All
(System
.Tasking
.Rendezvous
);
103 package body System
.Interrupts
is
108 package POP
renames System
.Task_Primitives
.Operations
;
110 function To_Ada
is new Unchecked_Conversion
111 (System
.Tasking
.Task_Id
, Ada
.Task_Identification
.Task_Id
);
113 function To_System
is new Unchecked_Conversion
114 (Ada
.Task_Identification
.Task_Id
, Task_Id
);
120 -- WARNING: System.Tasking.Stages performs calls to this task with
121 -- low-level constructs. Do not change this spec without synchronizing it.
123 task Interrupt_Manager
is
124 entry Detach_Interrupt_Entries
(T
: Task_Id
);
127 (New_Handler
: Parameterless_Handler
;
128 Interrupt
: Interrupt_ID
;
130 Restoration
: Boolean := False);
132 entry Exchange_Handler
133 (Old_Handler
: out Parameterless_Handler
;
134 New_Handler
: Parameterless_Handler
;
135 Interrupt
: Interrupt_ID
;
139 (Interrupt
: Interrupt_ID
;
142 entry Bind_Interrupt_To_Entry
144 E
: Task_Entry_Index
;
145 Interrupt
: Interrupt_ID
);
147 pragma Interrupt_Priority
(System
.Interrupt_Priority
'First);
148 end Interrupt_Manager
;
150 task type Interrupt_Server_Task
151 (Interrupt
: Interrupt_ID
; Int_Sema
: SEM_ID
) is
152 -- Server task for vectored hardware interrupt handling
153 pragma Interrupt_Priority
(System
.Interrupt_Priority
'First + 2);
154 end Interrupt_Server_Task
;
156 type Interrupt_Task_Access
is access Interrupt_Server_Task
;
158 -------------------------------
159 -- Local Types and Variables --
160 -------------------------------
162 type Entry_Assoc
is record
164 E
: Task_Entry_Index
;
167 type Handler_Assoc
is record
168 H
: Parameterless_Handler
;
169 Static
: Boolean; -- Indicates static binding;
172 User_Handler
: array (Interrupt_ID
) of Handler_Assoc
:=
173 (others => (null, Static
=> False));
174 pragma Volatile_Components
(User_Handler
);
175 -- Holds the protected procedure handler (if any) and its Static
176 -- information for each interrupt or signal. A handler is static
177 -- iff it is specified through the pragma Attach_Handler.
179 User_Entry
: array (Interrupt_ID
) of Entry_Assoc
:=
180 (others => (T
=> Null_Task
, E
=> Null_Task_Entry
));
181 pragma Volatile_Components
(User_Entry
);
182 -- Holds the task and entry index (if any) for each interrupt / signal
184 -- Type and Head, Tail of the list containing Registered Interrupt
185 -- Handlers. These definitions are used to register the handlers
186 -- specified by the pragma Interrupt_Handler.
188 type Registered_Handler
;
189 type R_Link
is access all Registered_Handler
;
191 type Registered_Handler
is record
192 H
: System
.Address
:= System
.Null_Address
;
193 Next
: R_Link
:= null;
196 Registered_Handler_Head
: R_Link
:= null;
197 Registered_Handler_Tail
: R_Link
:= null;
199 Server_ID
: array (Interrupt_ID
) of System
.Tasking
.Task_Id
:=
200 (others => System
.Tasking
.Null_Task
);
201 pragma Atomic_Components
(Server_ID
);
202 -- Holds the Task_Id of the Server_Task for each interrupt / signal.
203 -- Task_Id is needed to accomplish locking per interrupt base. Also
204 -- is needed to determine whether to create a new Server_Task.
206 Semaphore_ID_Map
: array
207 (Interrupt_ID
range 0 .. System
.OS_Interface
.Max_HW_Interrupt
)
208 of SEM_ID
:= (others => 0);
209 -- Array of binary semaphores associated with vectored interrupts
210 -- Note that the last bound should be Max_HW_Interrupt, but this will raise
211 -- Storage_Error if Num_HW_Interrupts is null, so use an extra 4 bytes
214 Interrupt_Access_Hold
: Interrupt_Task_Access
;
215 -- Variable for allocating an Interrupt_Server_Task
217 Default_Handler
: array (HW_Interrupt
) of Interfaces
.VxWorks
.VOIDFUNCPTR
;
218 -- Vectored interrupt handlers installed prior to program startup.
219 -- These are saved only when the umbrella handler is installed for
220 -- a given interrupt number.
222 -----------------------
223 -- Local Subprograms --
224 -----------------------
226 procedure Check_Reserved_Interrupt
(Interrupt
: Interrupt_ID
);
227 -- Check if Id is a reserved interrupt, and if so raise Program_Error
228 -- with an appropriate message, otherwise return.
230 procedure Finalize_Interrupt_Servers
;
231 -- Unbind the handlers for hardware interrupt server tasks at program
234 function Is_Registered
(Handler
: Parameterless_Handler
) return Boolean;
235 -- See if Handler has been "pragma"ed using Interrupt_Handler.
236 -- Always consider a null handler as registered.
238 procedure Notify_Interrupt
(Param
: System
.Address
);
239 -- Umbrella handler for vectored interrupts (not signals)
241 procedure Install_Default_Action
(Interrupt
: HW_Interrupt
);
242 -- Restore a handler that was in place prior to program execution
244 procedure Install_Umbrella_Handler
245 (Interrupt
: HW_Interrupt
;
246 Handler
: Interfaces
.VxWorks
.VOIDFUNCPTR
);
247 -- Install the runtime umbrella handler for a vectored hardware
250 procedure Unimplemented
(Feature
: String);
251 pragma No_Return
(Unimplemented
);
252 -- Used to mark a call to an unimplemented function. Raises Program_Error
253 -- with an appropriate message noting that Feature is unimplemented.
259 -- Calling this procedure with New_Handler = null and Static = True
260 -- means we want to detach the current handler regardless of the
261 -- previous handler's binding status (ie. do not care if it is a
262 -- dynamic or static handler).
264 -- This option is needed so that during the finalization of a PO, we
265 -- can detach handlers attached through pragma Attach_Handler.
267 procedure Attach_Handler
268 (New_Handler
: Parameterless_Handler
;
269 Interrupt
: Interrupt_ID
;
270 Static
: Boolean := False) is
272 Check_Reserved_Interrupt
(Interrupt
);
273 Interrupt_Manager
.Attach_Handler
(New_Handler
, Interrupt
, Static
);
276 -----------------------------
277 -- Bind_Interrupt_To_Entry --
278 -----------------------------
280 -- This procedure raises a Program_Error if it tries to
281 -- bind an interrupt to which an Entry or a Procedure is
284 procedure Bind_Interrupt_To_Entry
286 E
: Task_Entry_Index
;
287 Int_Ref
: System
.Address
)
289 Interrupt
: constant Interrupt_ID
:=
290 Interrupt_ID
(Storage_Elements
.To_Integer
(Int_Ref
));
293 Check_Reserved_Interrupt
(Interrupt
);
294 Interrupt_Manager
.Bind_Interrupt_To_Entry
(T
, E
, Interrupt
);
295 end Bind_Interrupt_To_Entry
;
297 ---------------------
298 -- Block_Interrupt --
299 ---------------------
301 procedure Block_Interrupt
(Interrupt
: Interrupt_ID
) is
303 Unimplemented
("Block_Interrupt");
306 ------------------------------
307 -- Check_Reserved_Interrupt --
308 ------------------------------
310 procedure Check_Reserved_Interrupt
(Interrupt
: Interrupt_ID
) is
312 if Is_Reserved
(Interrupt
) then
314 (Program_Error
'Identity,
315 "Interrupt" & Interrupt_ID
'Image (Interrupt
) & " is reserved");
319 end Check_Reserved_Interrupt
;
321 ---------------------
322 -- Current_Handler --
323 ---------------------
325 function Current_Handler
326 (Interrupt
: Interrupt_ID
) return Parameterless_Handler
329 Check_Reserved_Interrupt
(Interrupt
);
331 -- ??? Since Parameterless_Handler is not Atomic, the
332 -- current implementation is wrong. We need a new service in
333 -- Interrupt_Manager to ensure atomicity.
335 return User_Handler
(Interrupt
).H
;
342 -- Calling this procedure with Static = True means we want to Detach the
343 -- current handler regardless of the previous handler's binding status
344 -- (i.e. do not care if it is a dynamic or static handler).
346 -- This option is needed so that during the finalization of a PO, we can
347 -- detach handlers attached through pragma Attach_Handler.
349 procedure Detach_Handler
350 (Interrupt
: Interrupt_ID
;
351 Static
: Boolean := False) is
353 Check_Reserved_Interrupt
(Interrupt
);
354 Interrupt_Manager
.Detach_Handler
(Interrupt
, Static
);
357 ------------------------------
358 -- Detach_Interrupt_Entries --
359 ------------------------------
361 procedure Detach_Interrupt_Entries
(T
: Task_Id
) is
363 Interrupt_Manager
.Detach_Interrupt_Entries
(T
);
364 end Detach_Interrupt_Entries
;
366 ----------------------
367 -- Exchange_Handler --
368 ----------------------
370 -- Calling this procedure with New_Handler = null and Static = True
371 -- means we want to detach the current handler regardless of the
372 -- previous handler's binding status (ie. do not care if it is a
373 -- dynamic or static handler).
375 -- This option is needed so that during the finalization of a PO, we
376 -- can detach handlers attached through pragma Attach_Handler.
378 procedure Exchange_Handler
379 (Old_Handler
: out Parameterless_Handler
;
380 New_Handler
: Parameterless_Handler
;
381 Interrupt
: Interrupt_ID
;
382 Static
: Boolean := False)
385 Check_Reserved_Interrupt
(Interrupt
);
386 Interrupt_Manager
.Exchange_Handler
387 (Old_Handler
, New_Handler
, Interrupt
, Static
);
388 end Exchange_Handler
;
394 procedure Finalize
(Object
: in out Static_Interrupt_Protection
) is
396 -- ??? loop to be executed only when we're not doing library level
397 -- finalization, since in this case all interrupt / signal tasks are
400 if not Interrupt_Manager
'Terminated then
401 for N
in reverse Object
.Previous_Handlers
'Range loop
402 Interrupt_Manager
.Attach_Handler
403 (New_Handler
=> Object
.Previous_Handlers
(N
).Handler
,
404 Interrupt
=> Object
.Previous_Handlers
(N
).Interrupt
,
405 Static
=> Object
.Previous_Handlers
(N
).Static
,
406 Restoration
=> True);
410 Tasking
.Protected_Objects
.Entries
.Finalize
411 (Tasking
.Protected_Objects
.Entries
.Protection_Entries
(Object
));
414 --------------------------------
415 -- Finalize_Interrupt_Servers --
416 --------------------------------
418 -- Restore default handlers for interrupt servers
420 -- This is called by the Interrupt_Manager task when it receives the abort
421 -- signal during program finalization.
423 procedure Finalize_Interrupt_Servers
is
424 HW_Interrupts
: constant Boolean := HW_Interrupt
'Last >= 0;
427 if HW_Interrupts
then
428 for Int
in HW_Interrupt
loop
429 if Server_ID
(Interrupt_ID
(Int
)) /= null
431 not Ada
.Task_Identification
.Is_Terminated
432 (To_Ada
(Server_ID
(Interrupt_ID
(Int
))))
434 Interrupt_Manager
.Attach_Handler
435 (New_Handler
=> null,
436 Interrupt
=> Interrupt_ID
(Int
),
438 Restoration
=> True);
442 end Finalize_Interrupt_Servers
;
444 -------------------------------------
445 -- Has_Interrupt_Or_Attach_Handler --
446 -------------------------------------
448 function Has_Interrupt_Or_Attach_Handler
449 (Object
: access Dynamic_Interrupt_Protection
)
452 pragma Unreferenced
(Object
);
455 end Has_Interrupt_Or_Attach_Handler
;
457 function Has_Interrupt_Or_Attach_Handler
458 (Object
: access Static_Interrupt_Protection
)
461 pragma Unreferenced
(Object
);
464 end Has_Interrupt_Or_Attach_Handler
;
466 ----------------------
467 -- Ignore_Interrupt --
468 ----------------------
470 procedure Ignore_Interrupt
(Interrupt
: Interrupt_ID
) is
472 Unimplemented
("Ignore_Interrupt");
473 end Ignore_Interrupt
;
475 ----------------------------
476 -- Install_Default_Action --
477 ----------------------------
479 procedure Install_Default_Action
(Interrupt
: HW_Interrupt
) is
481 -- Restore original interrupt handler
483 Interfaces
.VxWorks
.intVecSet
484 (Interfaces
.VxWorks
.INUM_TO_IVEC
(Integer (Interrupt
)),
485 Default_Handler
(Interrupt
));
486 Default_Handler
(Interrupt
) := null;
487 end Install_Default_Action
;
489 ----------------------
490 -- Install_Handlers --
491 ----------------------
493 procedure Install_Handlers
494 (Object
: access Static_Interrupt_Protection
;
495 New_Handlers
: New_Handler_Array
)
498 for N
in New_Handlers
'Range loop
500 -- We need a lock around this ???
502 Object
.Previous_Handlers
(N
).Interrupt
:= New_Handlers
(N
).Interrupt
;
503 Object
.Previous_Handlers
(N
).Static
:= User_Handler
504 (New_Handlers
(N
).Interrupt
).Static
;
506 -- We call Exchange_Handler and not directly Interrupt_Manager.
507 -- Exchange_Handler so we get the Is_Reserved check.
510 (Old_Handler
=> Object
.Previous_Handlers
(N
).Handler
,
511 New_Handler
=> New_Handlers
(N
).Handler
,
512 Interrupt
=> New_Handlers
(N
).Interrupt
,
515 end Install_Handlers
;
517 ------------------------------
518 -- Install_Umbrella_Handler --
519 ------------------------------
521 procedure Install_Umbrella_Handler
522 (Interrupt
: HW_Interrupt
;
523 Handler
: Interfaces
.VxWorks
.VOIDFUNCPTR
)
525 use Interfaces
.VxWorks
;
527 Vec
: constant Interrupt_Vector
:=
528 INUM_TO_IVEC
(Interfaces
.VxWorks
.int
(Interrupt
));
530 Old_Handler
: constant VOIDFUNCPTR
:=
532 (INUM_TO_IVEC
(Interfaces
.VxWorks
.int
(Interrupt
)));
534 Stat
: Interfaces
.VxWorks
.STATUS
;
535 pragma Unreferenced
(Stat
);
536 -- ??? shouldn't we test Stat at least in a pragma Assert?
539 -- Only install umbrella handler when no Ada handler has already been
540 -- installed. Note that the interrupt number is passed as a parameter
541 -- when an interrupt occurs, so the umbrella handler has a different
542 -- wrapper generated by intConnect for each interrupt number.
544 if Default_Handler
(Interrupt
) = null then
546 intConnect
(Vec
, Handler
, System
.Address
(Interrupt
));
547 Default_Handler
(Interrupt
) := Old_Handler
;
549 end Install_Umbrella_Handler
;
555 function Is_Blocked
(Interrupt
: Interrupt_ID
) return Boolean is
557 Unimplemented
("Is_Blocked");
561 -----------------------
562 -- Is_Entry_Attached --
563 -----------------------
565 function Is_Entry_Attached
(Interrupt
: Interrupt_ID
) return Boolean is
567 Check_Reserved_Interrupt
(Interrupt
);
568 return User_Entry
(Interrupt
).T
/= Null_Task
;
569 end Is_Entry_Attached
;
571 -------------------------
572 -- Is_Handler_Attached --
573 -------------------------
575 function Is_Handler_Attached
(Interrupt
: Interrupt_ID
) return Boolean is
577 Check_Reserved_Interrupt
(Interrupt
);
578 return User_Handler
(Interrupt
).H
/= null;
579 end Is_Handler_Attached
;
585 function Is_Ignored
(Interrupt
: Interrupt_ID
) return Boolean is
587 Unimplemented
("Is_Ignored");
595 function Is_Registered
(Handler
: Parameterless_Handler
) return Boolean is
596 type Fat_Ptr
is record
597 Object_Addr
: System
.Address
;
598 Handler_Addr
: System
.Address
;
601 function To_Fat_Ptr
is new Unchecked_Conversion
602 (Parameterless_Handler
, Fat_Ptr
);
608 if Handler
= null then
612 Fat
:= To_Fat_Ptr
(Handler
);
614 Ptr
:= Registered_Handler_Head
;
616 while Ptr
/= null loop
617 if Ptr
.H
= Fat
.Handler_Addr
then
631 function Is_Reserved
(Interrupt
: Interrupt_ID
) return Boolean is
632 use System
.Interrupt_Management
;
634 return Reserve
(System
.Interrupt_Management
.Interrupt_ID
(Interrupt
));
637 ----------------------
638 -- Notify_Interrupt --
639 ----------------------
641 -- Umbrella handler for vectored hardware interrupts (as opposed to
642 -- signals and exceptions). As opposed to the signal implementation,
643 -- this handler is only installed in the vector table while there is
644 -- an active association of an Ada handler to the interrupt.
646 -- Otherwise, the handler that existed prior to program startup is
647 -- in the vector table. This ensures that handlers installed by
648 -- the BSP are active unless explicitly replaced in the program text.
650 -- Each Interrupt_Server_Task has an associated binary semaphore
651 -- on which it pends once it's been started. This routine determines
652 -- The appropriate semaphore and and issues a semGive call, waking
653 -- the server task. When a handler is unbound,
654 -- System.Interrupts.Unbind_Handler issues a semFlush, and the
655 -- server task deletes its semaphore and terminates.
657 procedure Notify_Interrupt
(Param
: System
.Address
) is
658 Interrupt
: constant Interrupt_ID
:= Interrupt_ID
(Param
);
660 Discard_Result
: STATUS
;
661 pragma Unreferenced
(Discard_Result
);
664 Discard_Result
:= semGive
(Semaphore_ID_Map
(Interrupt
));
665 end Notify_Interrupt
;
671 function Reference
(Interrupt
: Interrupt_ID
) return System
.Address
is
673 Check_Reserved_Interrupt
(Interrupt
);
674 return Storage_Elements
.To_Address
675 (Storage_Elements
.Integer_Address
(Interrupt
));
678 --------------------------------
679 -- Register_Interrupt_Handler --
680 --------------------------------
682 procedure Register_Interrupt_Handler
(Handler_Addr
: System
.Address
) is
683 New_Node_Ptr
: R_Link
;
686 -- This routine registers a handler as usable for dynamic
687 -- interrupt handler association. Routines attaching and detaching
688 -- handlers dynamically should determine whether the handler is
689 -- registered. Program_Error should be raised if it is not registered.
691 -- Pragma Interrupt_Handler can only appear in a library
692 -- level PO definition and instantiation. Therefore, we do not need
693 -- to implement an unregister operation. Nor do we need to
694 -- protect the queue structure with a lock.
696 pragma Assert
(Handler_Addr
/= System
.Null_Address
);
698 New_Node_Ptr
:= new Registered_Handler
;
699 New_Node_Ptr
.H
:= Handler_Addr
;
701 if Registered_Handler_Head
= null then
702 Registered_Handler_Head
:= New_Node_Ptr
;
703 Registered_Handler_Tail
:= New_Node_Ptr
;
706 Registered_Handler_Tail
.Next
:= New_Node_Ptr
;
707 Registered_Handler_Tail
:= New_Node_Ptr
;
709 end Register_Interrupt_Handler
;
711 -----------------------
712 -- Unblock_Interrupt --
713 -----------------------
715 procedure Unblock_Interrupt
(Interrupt
: Interrupt_ID
) is
717 Unimplemented
("Unblock_Interrupt");
718 end Unblock_Interrupt
;
724 function Unblocked_By
725 (Interrupt
: Interrupt_ID
) return System
.Tasking
.Task_Id
728 Unimplemented
("Unblocked_By");
732 ------------------------
733 -- Unignore_Interrupt --
734 ------------------------
736 procedure Unignore_Interrupt
(Interrupt
: Interrupt_ID
) is
738 Unimplemented
("Unignore_Interrupt");
739 end Unignore_Interrupt
;
745 procedure Unimplemented
(Feature
: String) is
748 (Program_Error
'Identity,
749 Feature
& " not implemented on VxWorks");
752 -----------------------
753 -- Interrupt_Manager --
754 -----------------------
756 task body Interrupt_Manager
is
762 procedure Bind_Handler
(Interrupt
: Interrupt_ID
);
763 -- This procedure does not do anything if a signal is blocked.
764 -- Otherwise, we have to interrupt Server_Task for status change through
767 procedure Unbind_Handler
(Interrupt
: Interrupt_ID
);
768 -- This procedure does not do anything if a signal is blocked.
769 -- Otherwise, we have to interrupt Server_Task for status change
770 -- through an abort signal.
772 procedure Unprotected_Exchange_Handler
773 (Old_Handler
: out Parameterless_Handler
;
774 New_Handler
: Parameterless_Handler
;
775 Interrupt
: Interrupt_ID
;
777 Restoration
: Boolean := False);
779 procedure Unprotected_Detach_Handler
780 (Interrupt
: Interrupt_ID
;
787 procedure Bind_Handler
(Interrupt
: Interrupt_ID
) is
789 Install_Umbrella_Handler
790 (HW_Interrupt
(Interrupt
), Notify_Interrupt
'Access);
797 procedure Unbind_Handler
(Interrupt
: Interrupt_ID
) is
802 -- Hardware interrupt
804 Install_Default_Action
(HW_Interrupt
(Interrupt
));
806 -- Flush server task off semaphore, allowing it to terminate
808 S
:= semFlush
(Semaphore_ID_Map
(Interrupt
));
809 pragma Assert
(S
= 0);
812 --------------------------------
813 -- Unprotected_Detach_Handler --
814 --------------------------------
816 procedure Unprotected_Detach_Handler
817 (Interrupt
: Interrupt_ID
;
820 Old_Handler
: Parameterless_Handler
;
822 if User_Entry
(Interrupt
).T
/= Null_Task
then
823 -- If an interrupt entry is installed raise
824 -- Program_Error. (propagate it to the caller).
826 Raise_Exception
(Program_Error
'Identity,
827 "An interrupt entry is already installed");
830 -- Note : Static = True will pass the following check. This is the
831 -- case when we want to detach a handler regardless of the static
832 -- status of the Current_Handler.
834 if not Static
and then User_Handler
(Interrupt
).Static
then
836 -- Trying to detach a static Interrupt Handler. raise
839 Raise_Exception
(Program_Error
'Identity,
840 "Trying to detach a static Interrupt Handler");
843 Old_Handler
:= User_Handler
(Interrupt
).H
;
847 User_Handler
(Interrupt
).H
:= null;
848 User_Handler
(Interrupt
).Static
:= False;
850 if Old_Handler
/= null then
851 Unbind_Handler
(Interrupt
);
853 end Unprotected_Detach_Handler
;
855 ----------------------------------
856 -- Unprotected_Exchange_Handler --
857 ----------------------------------
859 procedure Unprotected_Exchange_Handler
860 (Old_Handler
: out Parameterless_Handler
;
861 New_Handler
: Parameterless_Handler
;
862 Interrupt
: Interrupt_ID
;
864 Restoration
: Boolean := False)
867 if User_Entry
(Interrupt
).T
/= Null_Task
then
869 -- If an interrupt entry is already installed, raise
870 -- Program_Error. (propagate it to the caller).
873 (Program_Error
'Identity,
874 "An interrupt is already installed");
877 -- Note : A null handler with Static = True will
878 -- pass the following check. This is the case when we want to
879 -- detach a handler regardless of the Static status
880 -- of Current_Handler.
881 -- We don't check anything if Restoration is True, since we
882 -- may be detaching a static handler to restore a dynamic one.
884 if not Restoration
and then not Static
885 and then (User_Handler
(Interrupt
).Static
887 -- Trying to overwrite a static Interrupt Handler with a
890 -- The new handler is not specified as an
891 -- Interrupt Handler by a pragma.
893 or else not Is_Registered
(New_Handler
))
896 (Program_Error
'Identity,
897 "Trying to overwrite a static Interrupt Handler with a " &
901 -- Save the old handler
903 Old_Handler
:= User_Handler
(Interrupt
).H
;
907 User_Handler
(Interrupt
).H
:= New_Handler
;
909 if New_Handler
= null then
911 -- The null handler means we are detaching the handler
913 User_Handler
(Interrupt
).Static
:= False;
916 User_Handler
(Interrupt
).Static
:= Static
;
919 -- Invoke a corresponding Server_Task if not yet created.
920 -- Place Task_Id info in Server_ID array.
922 if New_Handler
/= null
924 (Server_ID
(Interrupt
) = Null_Task
926 Ada
.Task_Identification
.Is_Terminated
927 (To_Ada
(Server_ID
(Interrupt
))))
929 Interrupt_Access_Hold
:=
930 new Interrupt_Server_Task
931 (Interrupt
, semBCreate
(SEM_Q_FIFO
, SEM_EMPTY
));
932 Server_ID
(Interrupt
) :=
933 To_System
(Interrupt_Access_Hold
.all'Identity);
936 if (New_Handler
= null) and then Old_Handler
/= null then
938 -- Restore default handler
940 Unbind_Handler
(Interrupt
);
942 elsif Old_Handler
= null then
944 -- Save default handler
946 Bind_Handler
(Interrupt
);
948 end Unprotected_Exchange_Handler
;
950 -- Start of processing for Interrupt_Manager
953 -- By making this task independent of any master, when the process
954 -- goes away, the Interrupt_Manager will terminate gracefully.
956 System
.Tasking
.Utilities
.Make_Independent
;
959 -- A block is needed to absorb Program_Error exception
962 Old_Handler
: Parameterless_Handler
;
966 accept Attach_Handler
967 (New_Handler
: Parameterless_Handler
;
968 Interrupt
: Interrupt_ID
;
970 Restoration
: Boolean := False)
972 Unprotected_Exchange_Handler
973 (Old_Handler
, New_Handler
, Interrupt
, Static
, Restoration
);
977 accept Exchange_Handler
978 (Old_Handler
: out Parameterless_Handler
;
979 New_Handler
: Parameterless_Handler
;
980 Interrupt
: Interrupt_ID
;
983 Unprotected_Exchange_Handler
984 (Old_Handler
, New_Handler
, Interrupt
, Static
);
985 end Exchange_Handler
;
988 accept Detach_Handler
989 (Interrupt
: Interrupt_ID
;
992 Unprotected_Detach_Handler
(Interrupt
, Static
);
995 accept Bind_Interrupt_To_Entry
997 E
: Task_Entry_Index
;
998 Interrupt
: Interrupt_ID
)
1000 -- If there is a binding already (either a procedure or an
1001 -- entry), raise Program_Error (propagate it to the caller).
1003 if User_Handler
(Interrupt
).H
/= null
1004 or else User_Entry
(Interrupt
).T
/= Null_Task
1007 (Program_Error
'Identity,
1008 "A binding for this interrupt is already present");
1011 User_Entry
(Interrupt
) := Entry_Assoc
'(T => T, E => E);
1013 -- Indicate the attachment of interrupt entry in the ATCB.
1014 -- This is needed so when an interrupt entry task terminates
1015 -- the binding can be cleaned. The call to unbinding must be
1016 -- make by the task before it terminates.
1018 T.Interrupt_Entry := True;
1020 -- Invoke a corresponding Server_Task if not yet created.
1021 -- Place Task_Id info in Server_ID array.
1023 if Server_ID (Interrupt) = Null_Task
1025 Ada.Task_Identification.Is_Terminated
1026 (To_Ada (Server_ID (Interrupt)))
1028 Interrupt_Access_Hold := new Interrupt_Server_Task
1029 (Interrupt, semBCreate (SEM_Q_FIFO, SEM_EMPTY));
1030 Server_ID (Interrupt) :=
1031 To_System (Interrupt_Access_Hold.all'Identity);
1034 Bind_Handler (Interrupt);
1035 end Bind_Interrupt_To_Entry;
1038 accept Detach_Interrupt_Entries (T : Task_Id) do
1039 for Int in Interrupt_ID'Range loop
1040 if not Is_Reserved (Int) then
1041 if User_Entry (Int).T = T then
1044 (T
=> Null_Task
, E
=> Null_Task_Entry
);
1045 Unbind_Handler
(Int
);
1050 -- Indicate in ATCB that no interrupt entries are attached
1052 T
.Interrupt_Entry
:= False;
1053 end Detach_Interrupt_Entries
;
1057 -- If there is a Program_Error we just want to propagate it to
1058 -- the caller and do not want to stop this task.
1060 when Program_Error
=>
1064 pragma Assert
(False);
1070 when Standard
'Abort_Signal =>
1071 -- Flush interrupt server semaphores, so they can terminate
1072 Finalize_Interrupt_Servers
;
1074 end Interrupt_Manager
;
1076 ---------------------------
1077 -- Interrupt_Server_Task --
1078 ---------------------------
1080 -- Server task for vectored hardware interrupt handling
1082 task body Interrupt_Server_Task
is
1083 Self_Id
: constant Task_Id
:= Self
;
1084 Tmp_Handler
: Parameterless_Handler
;
1086 Tmp_Entry_Index
: Task_Entry_Index
;
1092 System
.Tasking
.Utilities
.Make_Independent
;
1093 Semaphore_ID_Map
(Interrupt
) := Int_Sema
;
1096 -- Pend on semaphore that will be triggered by the
1097 -- umbrella handler when the associated interrupt comes in
1099 S
:= semTake
(Int_Sema
, WAIT_FOREVER
);
1100 pragma Assert
(S
= 0);
1102 if User_Handler
(Interrupt
).H
/= null then
1104 -- Protected procedure handler
1106 Tmp_Handler
:= User_Handler
(Interrupt
).H
;
1109 elsif User_Entry
(Interrupt
).T
/= Null_Task
then
1111 -- Interrupt entry handler
1113 Tmp_ID
:= User_Entry
(Interrupt
).T
;
1114 Tmp_Entry_Index
:= User_Entry
(Interrupt
).E
;
1115 System
.Tasking
.Rendezvous
.Call_Simple
1116 (Tmp_ID
, Tmp_Entry_Index
, System
.Null_Address
);
1119 -- Semaphore has been flushed by an unbind operation in
1120 -- the Interrupt_Manager. Terminate the server task.
1122 -- Wait for the Interrupt_Manager to complete its work
1124 POP
.Write_Lock
(Self_Id
);
1126 -- Delete the associated semaphore
1128 S
:= semDelete
(Int_Sema
);
1130 pragma Assert
(S
= 0);
1132 -- Set status for the Interrupt_Manager
1134 Semaphore_ID_Map
(Interrupt
) := 0;
1135 Server_ID
(Interrupt
) := Null_Task
;
1136 POP
.Unlock
(Self_Id
);
1141 end Interrupt_Server_Task
;
1144 -- Get Interrupt_Manager's ID so that Abort_Interrupt can be sent
1146 Interrupt_Manager_ID
:= To_System
(Interrupt_Manager
'Identity);
1147 end System
.Interrupts
;