PR target/60039
[official-gcc.git] / gcc / ada / s-interr-hwint.adb
blob5cb38ea941c4f7cc0be6c2a48be59dabc9e3fa61
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 S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2013, 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 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. --
17 -- --
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. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- GNARL was developed by the GNARL team at Florida State University. --
28 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 -- Invariants:
34 -- All user-handleable signals are masked at all times in all tasks/threads
35 -- except possibly for the Interrupt_Manager task.
37 -- When a user task wants to have the effect of masking/unmasking an signal,
38 -- it must call Block_Interrupt/Unblock_Interrupt, which will have the effect
39 -- of unmasking/masking the signal in the Interrupt_Manager task. These
40 -- comments do not apply to vectored hardware interrupts, which may be masked
41 -- or unmasked using routined interfaced to the relevant embedded RTOS system
42 -- calls.
44 -- Once we associate a Signal_Server_Task with an signal, the task never goes
45 -- away, and we never remove the association. On the other hand, it is more
46 -- convenient to terminate an associated Interrupt_Server_Task for a vectored
47 -- hardware interrupt (since we use a binary semaphore for synchronization
48 -- with the umbrella handler).
50 -- There is no more than one signal per Signal_Server_Task and no more than
51 -- one Signal_Server_Task per signal. The same relation holds for hardware
52 -- interrupts and Interrupt_Server_Task's at any given time. That is, only
53 -- one non-terminated Interrupt_Server_Task exists for a give interrupt at
54 -- any time.
56 -- Within this package, the lock L is used to protect the various status
57 -- tables. If there is a Server_Task associated with a signal or interrupt, we
58 -- use the per-task lock of the Server_Task instead so that we protect the
59 -- status between Interrupt_Manager and Server_Task. Protection among service
60 -- requests are ensured via user calls to the Interrupt_Manager entries.
62 -- This is reasonably generic version of this package, supporting vectored
63 -- hardware interrupts using non-RTOS specific adapter routines which
64 -- should easily implemented on any RTOS capable of supporting GNAT.
66 with Ada.Unchecked_Conversion;
67 with Ada.Task_Identification;
69 with Interfaces.C; use Interfaces.C;
70 with System.OS_Interface; use System.OS_Interface;
71 with System.Interrupt_Management;
72 with System.Task_Primitives.Operations;
73 with System.Storage_Elements;
74 with System.Tasking.Utilities;
76 with System.Tasking.Rendezvous;
77 pragma Elaborate_All (System.Tasking.Rendezvous);
79 package body System.Interrupts is
81 use Tasking;
83 package POP renames System.Task_Primitives.Operations;
85 function To_Ada is new Ada.Unchecked_Conversion
86 (System.Tasking.Task_Id, Ada.Task_Identification.Task_Id);
88 function To_System is new Ada.Unchecked_Conversion
89 (Ada.Task_Identification.Task_Id, Task_Id);
91 -----------------
92 -- Local Tasks --
93 -----------------
95 -- WARNING: System.Tasking.Stages performs calls to this task with
96 -- low-level constructs. Do not change this spec without synchronizing it.
98 task Interrupt_Manager is
99 entry Detach_Interrupt_Entries (T : Task_Id);
101 entry Attach_Handler
102 (New_Handler : Parameterless_Handler;
103 Interrupt : Interrupt_ID;
104 Static : Boolean;
105 Restoration : Boolean := False);
107 entry Exchange_Handler
108 (Old_Handler : out Parameterless_Handler;
109 New_Handler : Parameterless_Handler;
110 Interrupt : Interrupt_ID;
111 Static : Boolean);
113 entry Detach_Handler
114 (Interrupt : Interrupt_ID;
115 Static : Boolean);
117 entry Bind_Interrupt_To_Entry
118 (T : Task_Id;
119 E : Task_Entry_Index;
120 Interrupt : Interrupt_ID);
122 pragma Interrupt_Priority (System.Interrupt_Priority'First);
123 end Interrupt_Manager;
125 task type Interrupt_Server_Task
126 (Interrupt : Interrupt_ID; Int_Sema : Binary_Semaphore_Id) is
127 -- Server task for vectored hardware interrupt handling
128 pragma Interrupt_Priority (System.Interrupt_Priority'First + 2);
129 end Interrupt_Server_Task;
131 type Interrupt_Task_Access is access Interrupt_Server_Task;
133 -------------------------------
134 -- Local Types and Variables --
135 -------------------------------
137 type Entry_Assoc is record
138 T : Task_Id;
139 E : Task_Entry_Index;
140 end record;
142 type Handler_Assoc is record
143 H : Parameterless_Handler;
144 Static : Boolean; -- Indicates static binding;
145 end record;
147 User_Handler : array (Interrupt_ID) of Handler_Assoc :=
148 (others => (null, Static => False));
149 pragma Volatile_Components (User_Handler);
150 -- Holds the protected procedure handler (if any) and its Static
151 -- information for each interrupt or signal. A handler is static
152 -- iff it is specified through the pragma Attach_Handler.
154 User_Entry : array (Interrupt_ID) of Entry_Assoc :=
155 (others => (T => Null_Task, E => Null_Task_Entry));
156 pragma Volatile_Components (User_Entry);
157 -- Holds the task and entry index (if any) for each interrupt / signal
159 -- Type and Head, Tail of the list containing Registered Interrupt
160 -- Handlers. These definitions are used to register the handlers
161 -- specified by the pragma Interrupt_Handler.
163 type Registered_Handler;
164 type R_Link is access all Registered_Handler;
166 type Registered_Handler is record
167 H : System.Address := System.Null_Address;
168 Next : R_Link := null;
169 end record;
171 Registered_Handler_Head : R_Link := null;
172 Registered_Handler_Tail : R_Link := null;
174 Server_ID : array (Interrupt_ID) of System.Tasking.Task_Id :=
175 (others => System.Tasking.Null_Task);
176 pragma Atomic_Components (Server_ID);
177 -- Holds the Task_Id of the Server_Task for each interrupt / signal.
178 -- Task_Id is needed to accomplish locking per interrupt base. Also
179 -- is needed to determine whether to create a new Server_Task.
181 Semaphore_ID_Map : array
182 (Interrupt_ID range 0 .. System.OS_Interface.Max_HW_Interrupt)
183 of Binary_Semaphore_Id := (others => 0);
184 -- Array of binary semaphores associated with vectored interrupts
185 -- Note that the last bound should be Max_HW_Interrupt, but this will raise
186 -- Storage_Error if Num_HW_Interrupts is null, so use an extra 4 bytes
187 -- instead.
189 Interrupt_Access_Hold : Interrupt_Task_Access;
190 -- Variable for allocating an Interrupt_Server_Task
192 Handler_Installed : array (HW_Interrupt) of Boolean := (others => False);
193 -- True if Notify_Interrupt was connected to the interrupt. Handlers
194 -- can be connected but disconnection is not possible on VxWorks.
195 -- Therefore we ensure Notify_Installed is connected at most once.
197 -----------------------
198 -- Local Subprograms --
199 -----------------------
201 procedure Check_Reserved_Interrupt (Interrupt : Interrupt_ID);
202 -- Check if Id is a reserved interrupt, and if so raise Program_Error
203 -- with an appropriate message, otherwise return.
205 procedure Finalize_Interrupt_Servers;
206 -- Unbind the handlers for hardware interrupt server tasks at program
207 -- termination.
209 function Is_Registered (Handler : Parameterless_Handler) return Boolean;
210 -- See if Handler has been "pragma"ed using Interrupt_Handler.
211 -- Always consider a null handler as registered.
213 procedure Notify_Interrupt (Param : System.Address);
214 pragma Convention (C, Notify_Interrupt);
215 -- Umbrella handler for vectored interrupts (not signals)
217 procedure Install_Umbrella_Handler
218 (Interrupt : HW_Interrupt;
219 Handler : System.OS_Interface.Interrupt_Handler);
220 -- Install the runtime umbrella handler for a vectored hardware
221 -- interrupt
223 procedure Unimplemented (Feature : String);
224 pragma No_Return (Unimplemented);
225 -- Used to mark a call to an unimplemented function. Raises Program_Error
226 -- with an appropriate message noting that Feature is unimplemented.
228 --------------------
229 -- Attach_Handler --
230 --------------------
232 -- Calling this procedure with New_Handler = null and Static = True
233 -- means we want to detach the current handler regardless of the
234 -- previous handler's binding status (i.e. do not care if it is a
235 -- dynamic or static handler).
237 -- This option is needed so that during the finalization of a PO, we
238 -- can detach handlers attached through pragma Attach_Handler.
240 procedure Attach_Handler
241 (New_Handler : Parameterless_Handler;
242 Interrupt : Interrupt_ID;
243 Static : Boolean := False) is
244 begin
245 Check_Reserved_Interrupt (Interrupt);
246 Interrupt_Manager.Attach_Handler (New_Handler, Interrupt, Static);
247 end Attach_Handler;
249 -----------------------------
250 -- Bind_Interrupt_To_Entry --
251 -----------------------------
253 -- This procedure raises a Program_Error if it tries to
254 -- bind an interrupt to which an Entry or a Procedure is
255 -- already bound.
257 procedure Bind_Interrupt_To_Entry
258 (T : Task_Id;
259 E : Task_Entry_Index;
260 Int_Ref : System.Address)
262 Interrupt : constant Interrupt_ID :=
263 Interrupt_ID (Storage_Elements.To_Integer (Int_Ref));
265 begin
266 Check_Reserved_Interrupt (Interrupt);
267 Interrupt_Manager.Bind_Interrupt_To_Entry (T, E, Interrupt);
268 end Bind_Interrupt_To_Entry;
270 ---------------------
271 -- Block_Interrupt --
272 ---------------------
274 procedure Block_Interrupt (Interrupt : Interrupt_ID) is
275 begin
276 Unimplemented ("Block_Interrupt");
277 end Block_Interrupt;
279 ------------------------------
280 -- Check_Reserved_Interrupt --
281 ------------------------------
283 procedure Check_Reserved_Interrupt (Interrupt : Interrupt_ID) is
284 begin
285 if Is_Reserved (Interrupt) then
286 raise Program_Error with
287 "Interrupt" & Interrupt_ID'Image (Interrupt) & " is reserved";
288 else
289 return;
290 end if;
291 end Check_Reserved_Interrupt;
293 ---------------------
294 -- Current_Handler --
295 ---------------------
297 function Current_Handler
298 (Interrupt : Interrupt_ID) return Parameterless_Handler
300 begin
301 Check_Reserved_Interrupt (Interrupt);
303 -- ??? Since Parameterless_Handler is not Atomic, the
304 -- current implementation is wrong. We need a new service in
305 -- Interrupt_Manager to ensure atomicity.
307 return User_Handler (Interrupt).H;
308 end Current_Handler;
310 --------------------
311 -- Detach_Handler --
312 --------------------
314 -- Calling this procedure with Static = True means we want to Detach the
315 -- current handler regardless of the previous handler's binding status
316 -- (i.e. do not care if it is a dynamic or static handler).
318 -- This option is needed so that during the finalization of a PO, we can
319 -- detach handlers attached through pragma Attach_Handler.
321 procedure Detach_Handler
322 (Interrupt : Interrupt_ID;
323 Static : Boolean := False) is
324 begin
325 Check_Reserved_Interrupt (Interrupt);
326 Interrupt_Manager.Detach_Handler (Interrupt, Static);
327 end Detach_Handler;
329 ------------------------------
330 -- Detach_Interrupt_Entries --
331 ------------------------------
333 procedure Detach_Interrupt_Entries (T : Task_Id) is
334 begin
335 Interrupt_Manager.Detach_Interrupt_Entries (T);
336 end Detach_Interrupt_Entries;
338 ----------------------
339 -- Exchange_Handler --
340 ----------------------
342 -- Calling this procedure with New_Handler = null and Static = True
343 -- means we want to detach the current handler regardless of the
344 -- previous handler's binding status (i.e. do not care if it is a
345 -- dynamic or static handler).
347 -- This option is needed so that during the finalization of a PO, we
348 -- can detach handlers attached through pragma Attach_Handler.
350 procedure Exchange_Handler
351 (Old_Handler : out Parameterless_Handler;
352 New_Handler : Parameterless_Handler;
353 Interrupt : Interrupt_ID;
354 Static : Boolean := False)
356 begin
357 Check_Reserved_Interrupt (Interrupt);
358 Interrupt_Manager.Exchange_Handler
359 (Old_Handler, New_Handler, Interrupt, Static);
360 end Exchange_Handler;
362 --------------
363 -- Finalize --
364 --------------
366 procedure Finalize (Object : in out Static_Interrupt_Protection) is
367 begin
368 -- ??? loop to be executed only when we're not doing library level
369 -- finalization, since in this case all interrupt / signal tasks are
370 -- gone.
372 if not Interrupt_Manager'Terminated then
373 for N in reverse Object.Previous_Handlers'Range loop
374 Interrupt_Manager.Attach_Handler
375 (New_Handler => Object.Previous_Handlers (N).Handler,
376 Interrupt => Object.Previous_Handlers (N).Interrupt,
377 Static => Object.Previous_Handlers (N).Static,
378 Restoration => True);
379 end loop;
380 end if;
382 Tasking.Protected_Objects.Entries.Finalize
383 (Tasking.Protected_Objects.Entries.Protection_Entries (Object));
384 end Finalize;
386 --------------------------------
387 -- Finalize_Interrupt_Servers --
388 --------------------------------
390 -- Restore default handlers for interrupt servers
392 -- This is called by the Interrupt_Manager task when it receives the abort
393 -- signal during program finalization.
395 procedure Finalize_Interrupt_Servers is
396 HW_Interrupts : constant Boolean := HW_Interrupt'Last >= 0;
398 begin
399 if HW_Interrupts then
400 for Int in HW_Interrupt loop
401 if Server_ID (Interrupt_ID (Int)) /= null
402 and then
403 not Ada.Task_Identification.Is_Terminated
404 (To_Ada (Server_ID (Interrupt_ID (Int))))
405 then
406 Interrupt_Manager.Attach_Handler
407 (New_Handler => null,
408 Interrupt => Interrupt_ID (Int),
409 Static => True,
410 Restoration => True);
411 end if;
412 end loop;
413 end if;
414 end Finalize_Interrupt_Servers;
416 -------------------------------------
417 -- Has_Interrupt_Or_Attach_Handler --
418 -------------------------------------
420 function Has_Interrupt_Or_Attach_Handler
421 (Object : access Dynamic_Interrupt_Protection)
422 return Boolean
424 pragma Unreferenced (Object);
425 begin
426 return True;
427 end Has_Interrupt_Or_Attach_Handler;
429 function Has_Interrupt_Or_Attach_Handler
430 (Object : access Static_Interrupt_Protection)
431 return Boolean
433 pragma Unreferenced (Object);
434 begin
435 return True;
436 end Has_Interrupt_Or_Attach_Handler;
438 ----------------------
439 -- Ignore_Interrupt --
440 ----------------------
442 procedure Ignore_Interrupt (Interrupt : Interrupt_ID) is
443 begin
444 Unimplemented ("Ignore_Interrupt");
445 end Ignore_Interrupt;
447 ----------------------
448 -- Install_Handlers --
449 ----------------------
451 procedure Install_Handlers
452 (Object : access Static_Interrupt_Protection;
453 New_Handlers : New_Handler_Array)
455 begin
456 for N in New_Handlers'Range loop
458 -- We need a lock around this ???
460 Object.Previous_Handlers (N).Interrupt := New_Handlers (N).Interrupt;
461 Object.Previous_Handlers (N).Static := User_Handler
462 (New_Handlers (N).Interrupt).Static;
464 -- We call Exchange_Handler and not directly Interrupt_Manager.
465 -- Exchange_Handler so we get the Is_Reserved check.
467 Exchange_Handler
468 (Old_Handler => Object.Previous_Handlers (N).Handler,
469 New_Handler => New_Handlers (N).Handler,
470 Interrupt => New_Handlers (N).Interrupt,
471 Static => True);
472 end loop;
473 end Install_Handlers;
475 ---------------------------------
476 -- Install_Restricted_Handlers --
477 ---------------------------------
479 procedure Install_Restricted_Handlers
480 (Prio : Any_Priority;
481 Handlers : New_Handler_Array)
483 pragma Unreferenced (Prio);
484 begin
485 for N in Handlers'Range loop
486 Attach_Handler (Handlers (N).Handler, Handlers (N).Interrupt, True);
487 end loop;
488 end Install_Restricted_Handlers;
490 ------------------------------
491 -- Install_Umbrella_Handler --
492 ------------------------------
494 procedure Install_Umbrella_Handler
495 (Interrupt : HW_Interrupt;
496 Handler : System.OS_Interface.Interrupt_Handler)
498 Vec : constant Interrupt_Vector :=
499 Interrupt_Number_To_Vector (int (Interrupt));
501 Status : int;
503 begin
504 -- Only install umbrella handler when no Ada handler has already been
505 -- installed. Note that the interrupt number is passed as a parameter
506 -- when an interrupt occurs, so the umbrella handler has a different
507 -- wrapper generated by intConnect for each interrupt number.
509 if not Handler_Installed (Interrupt) then
510 Status :=
511 Interrupt_Connect (Vec, Handler, System.Address (Interrupt));
512 pragma Assert (Status = 0);
514 Handler_Installed (Interrupt) := True;
515 end if;
516 end Install_Umbrella_Handler;
518 ----------------
519 -- Is_Blocked --
520 ----------------
522 function Is_Blocked (Interrupt : Interrupt_ID) return Boolean is
523 begin
524 Unimplemented ("Is_Blocked");
525 return False;
526 end Is_Blocked;
528 -----------------------
529 -- Is_Entry_Attached --
530 -----------------------
532 function Is_Entry_Attached (Interrupt : Interrupt_ID) return Boolean is
533 begin
534 Check_Reserved_Interrupt (Interrupt);
535 return User_Entry (Interrupt).T /= Null_Task;
536 end Is_Entry_Attached;
538 -------------------------
539 -- Is_Handler_Attached --
540 -------------------------
542 function Is_Handler_Attached (Interrupt : Interrupt_ID) return Boolean is
543 begin
544 Check_Reserved_Interrupt (Interrupt);
545 return User_Handler (Interrupt).H /= null;
546 end Is_Handler_Attached;
548 ----------------
549 -- Is_Ignored --
550 ----------------
552 function Is_Ignored (Interrupt : Interrupt_ID) return Boolean is
553 begin
554 Unimplemented ("Is_Ignored");
555 return False;
556 end Is_Ignored;
558 -------------------
559 -- Is_Registered --
560 -------------------
562 function Is_Registered (Handler : Parameterless_Handler) return Boolean is
563 type Fat_Ptr is record
564 Object_Addr : System.Address;
565 Handler_Addr : System.Address;
566 end record;
568 function To_Fat_Ptr is new Ada.Unchecked_Conversion
569 (Parameterless_Handler, Fat_Ptr);
571 Ptr : R_Link;
572 Fat : Fat_Ptr;
574 begin
575 if Handler = null then
576 return True;
577 end if;
579 Fat := To_Fat_Ptr (Handler);
581 Ptr := Registered_Handler_Head;
583 while Ptr /= null loop
584 if Ptr.H = Fat.Handler_Addr then
585 return True;
586 end if;
588 Ptr := Ptr.Next;
589 end loop;
591 return False;
592 end Is_Registered;
594 -----------------
595 -- Is_Reserved --
596 -----------------
598 function Is_Reserved (Interrupt : Interrupt_ID) return Boolean is
599 use System.Interrupt_Management;
600 begin
601 return Reserve (System.Interrupt_Management.Interrupt_ID (Interrupt));
602 end Is_Reserved;
604 ----------------------
605 -- Notify_Interrupt --
606 ----------------------
608 -- Umbrella handler for vectored hardware interrupts (as opposed to
609 -- signals and exceptions). As opposed to the signal implementation,
610 -- this handler is installed in the vector table when the first Ada
611 -- handler is attached to the interrupt. However because VxWorks don't
612 -- support disconnecting handlers, this subprogram always test whether
613 -- or not an Ada handler is effectively attached.
615 -- Otherwise, the handler that existed prior to program startup is
616 -- in the vector table. This ensures that handlers installed by
617 -- the BSP are active unless explicitly replaced in the program text.
619 -- Each Interrupt_Server_Task has an associated binary semaphore
620 -- on which it pends once it's been started. This routine determines
621 -- The appropriate semaphore and issues a semGive call, waking
622 -- the server task. When a handler is unbound,
623 -- System.Interrupts.Unbind_Handler issues a Binary_Semaphore_Flush,
624 -- and the server task deletes its semaphore and terminates.
626 procedure Notify_Interrupt (Param : System.Address) is
627 Interrupt : constant Interrupt_ID := Interrupt_ID (Param);
629 Id : constant Binary_Semaphore_Id := Semaphore_ID_Map (Interrupt);
631 Status : int;
633 begin
634 if Id /= 0 then
635 Status := Binary_Semaphore_Release (Id);
636 pragma Assert (Status = 0);
637 end if;
638 end Notify_Interrupt;
640 ---------------
641 -- Reference --
642 ---------------
644 function Reference (Interrupt : Interrupt_ID) return System.Address is
645 begin
646 Check_Reserved_Interrupt (Interrupt);
647 return Storage_Elements.To_Address
648 (Storage_Elements.Integer_Address (Interrupt));
649 end Reference;
651 --------------------------------
652 -- Register_Interrupt_Handler --
653 --------------------------------
655 procedure Register_Interrupt_Handler (Handler_Addr : System.Address) is
656 New_Node_Ptr : R_Link;
658 begin
659 -- This routine registers a handler as usable for dynamic
660 -- interrupt handler association. Routines attaching and detaching
661 -- handlers dynamically should determine whether the handler is
662 -- registered. Program_Error should be raised if it is not registered.
664 -- Pragma Interrupt_Handler can only appear in a library
665 -- level PO definition and instantiation. Therefore, we do not need
666 -- to implement an unregister operation. Nor do we need to
667 -- protect the queue structure with a lock.
669 pragma Assert (Handler_Addr /= System.Null_Address);
671 New_Node_Ptr := new Registered_Handler;
672 New_Node_Ptr.H := Handler_Addr;
674 if Registered_Handler_Head = null then
675 Registered_Handler_Head := New_Node_Ptr;
676 Registered_Handler_Tail := New_Node_Ptr;
678 else
679 Registered_Handler_Tail.Next := New_Node_Ptr;
680 Registered_Handler_Tail := New_Node_Ptr;
681 end if;
682 end Register_Interrupt_Handler;
684 -----------------------
685 -- Unblock_Interrupt --
686 -----------------------
688 procedure Unblock_Interrupt (Interrupt : Interrupt_ID) is
689 begin
690 Unimplemented ("Unblock_Interrupt");
691 end Unblock_Interrupt;
693 ------------------
694 -- Unblocked_By --
695 ------------------
697 function Unblocked_By
698 (Interrupt : Interrupt_ID) return System.Tasking.Task_Id
700 begin
701 Unimplemented ("Unblocked_By");
702 return Null_Task;
703 end Unblocked_By;
705 ------------------------
706 -- Unignore_Interrupt --
707 ------------------------
709 procedure Unignore_Interrupt (Interrupt : Interrupt_ID) is
710 begin
711 Unimplemented ("Unignore_Interrupt");
712 end Unignore_Interrupt;
714 -------------------
715 -- Unimplemented --
716 -------------------
718 procedure Unimplemented (Feature : String) is
719 begin
720 raise Program_Error with Feature & " not implemented on VxWorks";
721 end Unimplemented;
723 -----------------------
724 -- Interrupt_Manager --
725 -----------------------
727 task body Interrupt_Manager is
729 --------------------
730 -- Local Routines --
731 --------------------
733 procedure Bind_Handler (Interrupt : Interrupt_ID);
734 -- This procedure does not do anything if a signal is blocked.
735 -- Otherwise, we have to interrupt Server_Task for status change through
736 -- a wakeup signal.
738 procedure Unbind_Handler (Interrupt : Interrupt_ID);
739 -- This procedure does not do anything if a signal is blocked.
740 -- Otherwise, we have to interrupt Server_Task for status change
741 -- through an abort signal.
743 procedure Unprotected_Exchange_Handler
744 (Old_Handler : out Parameterless_Handler;
745 New_Handler : Parameterless_Handler;
746 Interrupt : Interrupt_ID;
747 Static : Boolean;
748 Restoration : Boolean := False);
750 procedure Unprotected_Detach_Handler
751 (Interrupt : Interrupt_ID;
752 Static : Boolean);
754 ------------------
755 -- Bind_Handler --
756 ------------------
758 procedure Bind_Handler (Interrupt : Interrupt_ID) is
759 begin
760 Install_Umbrella_Handler
761 (HW_Interrupt (Interrupt), Notify_Interrupt'Access);
762 end Bind_Handler;
764 --------------------
765 -- Unbind_Handler --
766 --------------------
768 procedure Unbind_Handler (Interrupt : Interrupt_ID) is
769 Status : int;
770 begin
772 -- Flush server task off semaphore, allowing it to terminate
774 Status := Binary_Semaphore_Flush (Semaphore_ID_Map (Interrupt));
775 pragma Assert (Status = 0);
776 end Unbind_Handler;
778 --------------------------------
779 -- Unprotected_Detach_Handler --
780 --------------------------------
782 procedure Unprotected_Detach_Handler
783 (Interrupt : Interrupt_ID;
784 Static : Boolean)
786 Old_Handler : Parameterless_Handler;
787 begin
788 if User_Entry (Interrupt).T /= Null_Task then
789 -- If an interrupt entry is installed raise
790 -- Program_Error. (propagate it to the caller).
792 raise Program_Error with
793 "An interrupt entry is already installed";
794 end if;
796 -- Note : Static = True will pass the following check. This is the
797 -- case when we want to detach a handler regardless of the static
798 -- status of the Current_Handler.
800 if not Static and then User_Handler (Interrupt).Static then
802 -- Trying to detach a static Interrupt Handler. raise
803 -- Program_Error.
805 raise Program_Error with
806 "Trying to detach a static Interrupt Handler";
807 end if;
809 Old_Handler := User_Handler (Interrupt).H;
811 -- The new handler
813 User_Handler (Interrupt).H := null;
814 User_Handler (Interrupt).Static := False;
816 if Old_Handler /= null then
817 Unbind_Handler (Interrupt);
818 end if;
819 end Unprotected_Detach_Handler;
821 ----------------------------------
822 -- Unprotected_Exchange_Handler --
823 ----------------------------------
825 procedure Unprotected_Exchange_Handler
826 (Old_Handler : out Parameterless_Handler;
827 New_Handler : Parameterless_Handler;
828 Interrupt : Interrupt_ID;
829 Static : Boolean;
830 Restoration : Boolean := False)
832 begin
833 if User_Entry (Interrupt).T /= Null_Task then
835 -- If an interrupt entry is already installed, raise
836 -- Program_Error. (propagate it to the caller).
838 raise Program_Error with "An interrupt is already installed";
839 end if;
841 -- Note : A null handler with Static = True will
842 -- pass the following check. This is the case when we want to
843 -- detach a handler regardless of the Static status
844 -- of Current_Handler.
845 -- We don't check anything if Restoration is True, since we
846 -- may be detaching a static handler to restore a dynamic one.
848 if not Restoration and then not Static
849 and then (User_Handler (Interrupt).Static
851 -- Trying to overwrite a static Interrupt Handler with a
852 -- dynamic Handler
854 -- The new handler is not specified as an
855 -- Interrupt Handler by a pragma.
857 or else not Is_Registered (New_Handler))
858 then
859 raise Program_Error with
860 "Trying to overwrite a static Interrupt Handler with a " &
861 "dynamic Handler";
862 end if;
864 -- Save the old handler
866 Old_Handler := User_Handler (Interrupt).H;
868 -- The new handler
870 User_Handler (Interrupt).H := New_Handler;
872 if New_Handler = null then
874 -- The null handler means we are detaching the handler
876 User_Handler (Interrupt).Static := False;
878 else
879 User_Handler (Interrupt).Static := Static;
880 end if;
882 -- Invoke a corresponding Server_Task if not yet created.
883 -- Place Task_Id info in Server_ID array.
885 if New_Handler /= null
886 and then
887 (Server_ID (Interrupt) = Null_Task
888 or else
889 Ada.Task_Identification.Is_Terminated
890 (To_Ada (Server_ID (Interrupt))))
891 then
892 Interrupt_Access_Hold :=
893 new Interrupt_Server_Task (Interrupt, Binary_Semaphore_Create);
894 Server_ID (Interrupt) :=
895 To_System (Interrupt_Access_Hold.all'Identity);
896 end if;
898 if (New_Handler = null) and then Old_Handler /= null then
900 -- Restore default handler
902 Unbind_Handler (Interrupt);
904 elsif Old_Handler = null then
906 -- Save default handler
908 Bind_Handler (Interrupt);
909 end if;
910 end Unprotected_Exchange_Handler;
912 -- Start of processing for Interrupt_Manager
914 begin
915 -- By making this task independent of any master, when the process
916 -- goes away, the Interrupt_Manager will terminate gracefully.
918 System.Tasking.Utilities.Make_Independent;
920 loop
921 -- A block is needed to absorb Program_Error exception
923 declare
924 Old_Handler : Parameterless_Handler;
926 begin
927 select
928 accept Attach_Handler
929 (New_Handler : Parameterless_Handler;
930 Interrupt : Interrupt_ID;
931 Static : Boolean;
932 Restoration : Boolean := False)
934 Unprotected_Exchange_Handler
935 (Old_Handler, New_Handler, Interrupt, Static, Restoration);
936 end Attach_Handler;
939 accept Exchange_Handler
940 (Old_Handler : out Parameterless_Handler;
941 New_Handler : Parameterless_Handler;
942 Interrupt : Interrupt_ID;
943 Static : Boolean)
945 Unprotected_Exchange_Handler
946 (Old_Handler, New_Handler, Interrupt, Static);
947 end Exchange_Handler;
950 accept Detach_Handler
951 (Interrupt : Interrupt_ID;
952 Static : Boolean)
954 Unprotected_Detach_Handler (Interrupt, Static);
955 end Detach_Handler;
957 accept Bind_Interrupt_To_Entry
958 (T : Task_Id;
959 E : Task_Entry_Index;
960 Interrupt : Interrupt_ID)
962 -- If there is a binding already (either a procedure or an
963 -- entry), raise Program_Error (propagate it to the caller).
965 if User_Handler (Interrupt).H /= null
966 or else User_Entry (Interrupt).T /= Null_Task
967 then
968 raise Program_Error with
969 "A binding for this interrupt is already present";
970 end if;
972 User_Entry (Interrupt) := Entry_Assoc'(T => T, E => E);
974 -- Indicate the attachment of interrupt entry in the ATCB.
975 -- This is needed so when an interrupt entry task terminates
976 -- the binding can be cleaned. The call to unbinding must be
977 -- make by the task before it terminates.
979 T.Interrupt_Entry := True;
981 -- Invoke a corresponding Server_Task if not yet created.
982 -- Place Task_Id info in Server_ID array.
984 if Server_ID (Interrupt) = Null_Task
985 or else
986 Ada.Task_Identification.Is_Terminated
987 (To_Ada (Server_ID (Interrupt)))
988 then
989 Interrupt_Access_Hold := new Interrupt_Server_Task
990 (Interrupt, Binary_Semaphore_Create);
991 Server_ID (Interrupt) :=
992 To_System (Interrupt_Access_Hold.all'Identity);
993 end if;
995 Bind_Handler (Interrupt);
996 end Bind_Interrupt_To_Entry;
999 accept Detach_Interrupt_Entries (T : Task_Id) do
1000 for Int in Interrupt_ID'Range loop
1001 if not Is_Reserved (Int) then
1002 if User_Entry (Int).T = T then
1003 User_Entry (Int) :=
1004 Entry_Assoc'
1005 (T => Null_Task, E => Null_Task_Entry);
1006 Unbind_Handler (Int);
1007 end if;
1008 end if;
1009 end loop;
1011 -- Indicate in ATCB that no interrupt entries are attached
1013 T.Interrupt_Entry := False;
1014 end Detach_Interrupt_Entries;
1015 end select;
1017 exception
1018 -- If there is a Program_Error we just want to propagate it to
1019 -- the caller and do not want to stop this task.
1021 when Program_Error =>
1022 null;
1024 when others =>
1025 pragma Assert (False);
1026 null;
1027 end;
1028 end loop;
1030 exception
1031 when Standard'Abort_Signal =>
1033 -- Flush interrupt server semaphores, so they can terminate
1035 Finalize_Interrupt_Servers;
1036 raise;
1037 end Interrupt_Manager;
1039 ---------------------------
1040 -- Interrupt_Server_Task --
1041 ---------------------------
1043 -- Server task for vectored hardware interrupt handling
1045 task body Interrupt_Server_Task is
1046 Self_Id : constant Task_Id := Self;
1047 Tmp_Handler : Parameterless_Handler;
1048 Tmp_ID : Task_Id;
1049 Tmp_Entry_Index : Task_Entry_Index;
1050 Status : int;
1052 begin
1053 System.Tasking.Utilities.Make_Independent;
1054 Semaphore_ID_Map (Interrupt) := Int_Sema;
1056 loop
1057 -- Pend on semaphore that will be triggered by the
1058 -- umbrella handler when the associated interrupt comes in
1060 Status := Binary_Semaphore_Obtain (Int_Sema);
1061 pragma Assert (Status = 0);
1063 if User_Handler (Interrupt).H /= null then
1065 -- Protected procedure handler
1067 Tmp_Handler := User_Handler (Interrupt).H;
1068 Tmp_Handler.all;
1070 elsif User_Entry (Interrupt).T /= Null_Task then
1072 -- Interrupt entry handler
1074 Tmp_ID := User_Entry (Interrupt).T;
1075 Tmp_Entry_Index := User_Entry (Interrupt).E;
1076 System.Tasking.Rendezvous.Call_Simple
1077 (Tmp_ID, Tmp_Entry_Index, System.Null_Address);
1079 else
1080 -- Semaphore has been flushed by an unbind operation in
1081 -- the Interrupt_Manager. Terminate the server task.
1083 -- Wait for the Interrupt_Manager to complete its work
1085 POP.Write_Lock (Self_Id);
1087 -- Unassociate the interrupt handler
1089 Semaphore_ID_Map (Interrupt) := 0;
1091 -- Delete the associated semaphore
1093 Status := Binary_Semaphore_Delete (Int_Sema);
1095 pragma Assert (Status = 0);
1097 -- Set status for the Interrupt_Manager
1099 Server_ID (Interrupt) := Null_Task;
1100 POP.Unlock (Self_Id);
1102 exit;
1103 end if;
1104 end loop;
1105 end Interrupt_Server_Task;
1107 begin
1108 -- Get Interrupt_Manager's ID so that Abort_Interrupt can be sent
1110 Interrupt_Manager_ID := To_System (Interrupt_Manager'Identity);
1111 end System.Interrupts;