Remove some compile time warnings about duplicate definitions.
[official-gcc.git] / gcc / ada / 5vinterr.adb
blobcb974377a9721725367ad71d3925aac182e71904
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- S Y S T E M . I N T E R R U P T S --
6 -- --
7 -- B o d y --
8 -- --
9 -- $Revision: 1.4 $
10 -- --
11 -- Copyright (C) 1991-2000 Free Software Foundation, Inc. --
12 -- --
13 -- GNARL is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNARL; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
23 -- --
24 -- As a special exception, if other files instantiate generics from this --
25 -- unit, or you link this unit with other files to produce an executable, --
26 -- this unit does not by itself cause the resulting executable to be --
27 -- covered by the GNU General Public License. This exception does not --
28 -- however invalidate any other reasons why the executable file might be --
29 -- covered by the GNU Public License. --
30 -- --
31 -- GNARL was developed by the GNARL team at Florida State University. It is --
32 -- now maintained by Ada Core Technologies Inc. in cooperation with Florida --
33 -- State University (http://www.gnat.com). --
34 -- --
35 ------------------------------------------------------------------------------
37 -- This is an OpenVMS/Alpha version of this package.
39 -- Invariants:
41 -- Once we associate a Server_Task with an interrupt, the task never
42 -- goes away, and we never remove the association.
44 -- There is no more than one interrupt per Server_Task and no more than
45 -- one Server_Task per interrupt.
47 -- Within this package, the lock L is used to protect the various status
48 -- tables. If there is a Server_Task associated with an interrupt, we use
49 -- the per-task lock of the Server_Task instead so that we protect the
50 -- status between Interrupt_Manager and Server_Task. Protection among
51 -- service requests are done using User Request to Interrupt_Manager
52 -- rendezvous.
54 with Ada.Task_Identification;
55 -- used for Task_ID type
57 with Ada.Exceptions;
58 -- used for Raise_Exception
60 with System.Task_Primitives;
61 -- used for RTS_Lock
62 -- Self
64 with System.Interrupt_Management;
65 -- used for Reserve
66 -- Interrupt_ID
67 -- Interrupt_Mask
68 -- Abort_Task_Interrupt
70 with System.Interrupt_Management.Operations;
71 -- used for Thread_Block_Interrupt
72 -- Thread_Unblock_Interrupt
73 -- Install_Default_Action
74 -- Install_Ignore_Action
75 -- Copy_Interrupt_Mask
76 -- Set_Interrupt_Mask
77 -- Empty_Interrupt_Mask
78 -- Fill_Interrupt_Mask
79 -- Add_To_Interrupt_Mask
80 -- Delete_From_Interrupt_Mask
81 -- Interrupt_Wait
82 -- Interrupt_Self_Process
83 -- Get_Interrupt_Mask
84 -- Set_Interrupt_Mask
85 -- IS_Member
86 -- Environment_Mask
87 -- All_Tasks_Mask
88 pragma Elaborate_All (System.Interrupt_Management.Operations);
90 with System.Error_Reporting;
91 pragma Warnings (Off, System.Error_Reporting);
92 -- used for Shutdown
94 with System.Task_Primitives.Operations;
95 -- used for Write_Lock
96 -- Unlock
97 -- Abort
98 -- Wakeup_Task
99 -- Sleep
100 -- Initialize_Lock
102 with System.Task_Primitives.Interrupt_Operations;
103 -- used for Set_Interrupt_ID
105 with System.Storage_Elements;
106 -- used for To_Address
107 -- To_Integer
108 -- Integer_Address
110 with System.Tasking;
111 -- used for Task_ID
112 -- Task_Entry_Index
113 -- Null_Task
114 -- Self
115 -- Interrupt_Manager_ID
117 with System.Tasking.Utilities;
118 -- used for Make_Independent
120 with System.Tasking.Rendezvous;
121 -- used for Call_Simple
122 pragma Elaborate_All (System.Tasking.Rendezvous);
124 with System.Tasking.Initialization;
125 -- used for Defer_Abort
126 -- Undefer_Abort
128 with Unchecked_Conversion;
130 package body System.Interrupts is
132 use Tasking;
133 use System.Error_Reporting;
134 use Ada.Exceptions;
136 package PRI renames System.Task_Primitives;
137 package POP renames System.Task_Primitives.Operations;
138 package PIO renames System.Task_Primitives.Interrupt_Operations;
139 package IMNG renames System.Interrupt_Management;
140 package IMOP renames System.Interrupt_Management.Operations;
142 function To_System is new Unchecked_Conversion
143 (Ada.Task_Identification.Task_Id, Task_ID);
145 -----------------
146 -- Local Tasks --
147 -----------------
149 -- WARNING: System.Tasking.Utilities performs calls to this task
150 -- with low-level constructs. Do not change this spec without synchro-
151 -- nizing it.
153 task Interrupt_Manager is
154 entry Initialize (Mask : IMNG.Interrupt_Mask);
156 entry Attach_Handler
157 (New_Handler : in Parameterless_Handler;
158 Interrupt : in Interrupt_ID;
159 Static : in Boolean;
160 Restoration : in Boolean := False);
162 entry Exchange_Handler
163 (Old_Handler : out Parameterless_Handler;
164 New_Handler : in Parameterless_Handler;
165 Interrupt : in Interrupt_ID;
166 Static : in Boolean);
168 entry Detach_Handler
169 (Interrupt : in Interrupt_ID;
170 Static : in Boolean);
172 entry Bind_Interrupt_To_Entry
173 (T : Task_ID;
174 E : Task_Entry_Index;
175 Interrupt : Interrupt_ID);
177 entry Detach_Interrupt_Entries (T : Task_ID);
179 entry Block_Interrupt (Interrupt : Interrupt_ID);
181 entry Unblock_Interrupt (Interrupt : Interrupt_ID);
183 entry Ignore_Interrupt (Interrupt : Interrupt_ID);
185 entry Unignore_Interrupt (Interrupt : Interrupt_ID);
187 pragma Interrupt_Priority (System.Interrupt_Priority'Last);
188 end Interrupt_Manager;
190 task type Server_Task (Interrupt : Interrupt_ID) is
191 pragma Priority (System.Interrupt_Priority'Last);
192 end Server_Task;
194 type Server_Task_Access is access Server_Task;
196 --------------------------------
197 -- Local Types and Variables --
198 --------------------------------
200 type Entry_Assoc is record
201 T : Task_ID;
202 E : Task_Entry_Index;
203 end record;
205 type Handler_Assoc is record
206 H : Parameterless_Handler;
207 Static : Boolean; -- Indicates static binding;
208 end record;
210 User_Handler : array (Interrupt_ID'Range) of Handler_Assoc :=
211 (others => (null, Static => False));
212 pragma Volatile_Components (User_Handler);
213 -- Holds the protected procedure handler (if any) and its Static
214 -- information for each interrupt. A handler is a Static one if
215 -- it is specified through the pragma Attach_Handler.
216 -- Attach_Handler. Otherwise, not static)
218 User_Entry : array (Interrupt_ID'Range) of Entry_Assoc :=
219 (others => (T => Null_Task, E => Null_Task_Entry));
220 pragma Volatile_Components (User_Entry);
221 -- Holds the task and entry index (if any) for each interrupt
223 Blocked : array (Interrupt_ID'Range) of Boolean := (others => False);
224 pragma Volatile_Components (Blocked);
225 -- True iff the corresponding interrupt is blocked in the process level
227 Ignored : array (Interrupt_ID'Range) of Boolean := (others => False);
228 pragma Volatile_Components (Ignored);
229 -- True iff the corresponding interrupt is blocked in the process level
231 Last_Unblocker :
232 array (Interrupt_ID'Range) of Task_ID := (others => Null_Task);
233 pragma Volatile_Components (Last_Unblocker);
234 -- Holds the ID of the last Task which Unblocked this Interrupt.
235 -- It contains Null_Task if no tasks have ever requested the
236 -- Unblocking operation or the Interrupt is currently Blocked.
238 Server_ID : array (Interrupt_ID'Range) of Task_ID :=
239 (others => Null_Task);
240 pragma Atomic_Components (Server_ID);
241 -- Holds the Task_ID of the Server_Task for each interrupt.
242 -- Task_ID is needed to accomplish locking per Interrupt base. Also
243 -- is needed to decide whether to create a new Server_Task.
245 -- Type and Head, Tail of the list containing Registered Interrupt
246 -- Handlers. These definitions are used to register the handlers
247 -- specified by the pragma Interrupt_Handler.
249 type Registered_Handler;
250 type R_Link is access all Registered_Handler;
252 type Registered_Handler is record
253 H : System.Address := System.Null_Address;
254 Next : R_Link := null;
255 end record;
257 Registered_Handler_Head : R_Link := null;
258 Registered_Handler_Tail : R_Link := null;
260 Access_Hold : Server_Task_Access;
261 -- variable used to allocate Server_Task using "new".
263 L : aliased PRI.RTS_Lock;
264 -- L protects contents in tables above corresponding to interrupts
265 -- for which Server_ID (T) = null.
267 -- If Server_ID (T) /= null then protection is via
268 -- per-task (TCB) lock of Server_ID (T).
270 -- For deadlock prevention, L should not be locked after
271 -- any other lock is held.
273 Task_Lock : array (Interrupt_ID'Range) of Boolean := (others => False);
274 -- Boolean flags to give matching Locking and Unlocking. See the comments
275 -- in Lock_Interrupt.
277 -----------------------
278 -- Local Subprograms --
279 -----------------------
281 procedure Lock_Interrupt
282 (Self_ID : Task_ID;
283 Interrupt : Interrupt_ID);
284 -- protect the tables using L or per-task lock. Set the Boolean
285 -- value Task_Lock if the lock is made using per-task lock.
286 -- This information is needed so that Unlock_Interrupt
287 -- performs unlocking on the same lock. The situation we are preventing
288 -- is, for example, when Attach_Handler is called for the first time
289 -- we lock L and create an Server_Task. For a matching unlocking, if we
290 -- rely on the fact that there is a Server_Task, we will unlock the
291 -- per-task lock.
293 procedure Unlock_Interrupt
294 (Self_ID : Task_ID;
295 Interrupt : Interrupt_ID);
297 function Is_Registered (Handler : Parameterless_Handler) return Boolean;
299 --------------------
300 -- Lock_Interrupt --
301 --------------------
303 -- ?????
304 -- This package has been modified several times.
305 -- Do we still need this fancy locking scheme, now that more operations
306 -- are entries of the interrupt manager task?
307 -- ?????
308 -- More likely, we will need to convert one or more entry calls to
309 -- protected operations, because presently we are violating locking order
310 -- rules by calling a task entry from within the runtime system.
312 procedure Lock_Interrupt
313 (Self_ID : Task_ID;
314 Interrupt : Interrupt_ID)
316 begin
317 Initialization.Defer_Abort (Self_ID);
319 POP.Write_Lock (L'Access);
321 if Task_Lock (Interrupt) then
323 -- We need to use per-task lock.
325 POP.Unlock (L'Access);
326 POP.Write_Lock (Server_ID (Interrupt));
328 -- Rely on the fact that once Server_ID is set to a non-null
329 -- value it will never be set back to null.
331 elsif Server_ID (Interrupt) /= Null_Task then
333 -- We need to use per-task lock.
335 Task_Lock (Interrupt) := True;
336 POP.Unlock (L'Access);
337 POP.Write_Lock (Server_ID (Interrupt));
338 end if;
339 end Lock_Interrupt;
341 ----------------------
342 -- Unlock_Interrupt --
343 ----------------------
345 procedure Unlock_Interrupt
346 (Self_ID : Task_ID;
347 Interrupt : Interrupt_ID)
349 begin
350 if Task_Lock (Interrupt) then
351 POP.Unlock (Server_ID (Interrupt));
352 else
353 POP.Unlock (L'Access);
354 end if;
356 Initialization.Undefer_Abort (Self_ID);
357 end Unlock_Interrupt;
359 ----------------------------------
360 -- Register_Interrupt_Handler --
361 ----------------------------------
363 procedure Register_Interrupt_Handler (Handler_Addr : System.Address) is
364 New_Node_Ptr : R_Link;
366 begin
367 -- This routine registers the Handler as usable for Dynamic
368 -- Interrupt Handler. Routines attaching and detaching Handler
369 -- dynamically should first consult if the Handler is rgistered.
370 -- A Program Error should be raised if it is not registered.
372 -- The pragma Interrupt_Handler can only appear in the library
373 -- level PO definition and instantiation. Therefore, we do not need
374 -- to implement Unregistering operation. Neither we need to
375 -- protect the queue structure using a Lock.
377 pragma Assert (Handler_Addr /= System.Null_Address);
379 New_Node_Ptr := new Registered_Handler;
380 New_Node_Ptr.H := Handler_Addr;
382 if Registered_Handler_Head = null then
383 Registered_Handler_Head := New_Node_Ptr;
384 Registered_Handler_Tail := New_Node_Ptr;
386 else
387 Registered_Handler_Tail.Next := New_Node_Ptr;
388 Registered_Handler_Tail := New_Node_Ptr;
389 end if;
390 end Register_Interrupt_Handler;
392 -------------------
393 -- Is_Registered --
394 -------------------
396 -- See if the Handler has been "pragma"ed using Interrupt_Handler.
397 -- Always consider a null handler as registered.
399 function Is_Registered (Handler : Parameterless_Handler) return Boolean is
401 type Fat_Ptr is record
402 Object_Addr : System.Address;
403 Handler_Addr : System.Address;
404 end record;
406 function To_Fat_Ptr is new Unchecked_Conversion
407 (Parameterless_Handler, Fat_Ptr);
409 Ptr : R_Link;
410 Fat : Fat_Ptr;
412 begin
413 if Handler = null then
414 return True;
415 end if;
417 Fat := To_Fat_Ptr (Handler);
419 Ptr := Registered_Handler_Head;
421 while (Ptr /= null) loop
422 if Ptr.H = Fat.Handler_Addr then
423 return True;
424 end if;
426 Ptr := Ptr.Next;
427 end loop;
429 return False;
431 end Is_Registered;
433 -----------------
434 -- Is_Reserved --
435 -----------------
437 function Is_Reserved (Interrupt : Interrupt_ID) return Boolean is
438 begin
439 return IMNG.Reserve (IMNG.Interrupt_ID (Interrupt));
440 end Is_Reserved;
442 -----------------------
443 -- Is_Entry_Attached --
444 -----------------------
446 function Is_Entry_Attached (Interrupt : Interrupt_ID) return Boolean is
447 begin
448 if Is_Reserved (Interrupt) then
449 Raise_Exception (Program_Error'Identity, "Interrupt" &
450 Interrupt_ID'Image (Interrupt) & " is reserved");
451 end if;
453 return User_Entry (Interrupt).T /= Null_Task;
454 end Is_Entry_Attached;
456 -------------------------
457 -- Is_Handler_Attached --
458 -------------------------
460 function Is_Handler_Attached (Interrupt : Interrupt_ID) return Boolean is
461 begin
462 if Is_Reserved (Interrupt) then
463 Raise_Exception (Program_Error'Identity, "Interrupt" &
464 Interrupt_ID'Image (Interrupt) & " is reserved");
465 end if;
467 return User_Handler (Interrupt).H /= null;
468 end Is_Handler_Attached;
470 ----------------
471 -- Is_Blocked --
472 ----------------
474 function Is_Blocked (Interrupt : Interrupt_ID) return Boolean is
475 begin
476 if Is_Reserved (Interrupt) then
477 Raise_Exception (Program_Error'Identity, "Interrupt" &
478 Interrupt_ID'Image (Interrupt) & " is reserved");
479 end if;
481 return Blocked (Interrupt);
482 end Is_Blocked;
484 ----------------
485 -- Is_Ignored --
486 ----------------
488 function Is_Ignored (Interrupt : Interrupt_ID) return Boolean is
489 begin
490 if Is_Reserved (Interrupt) then
491 Raise_Exception (Program_Error'Identity, "Interrupt" &
492 Interrupt_ID'Image (Interrupt) & " is reserved");
493 end if;
495 return Ignored (Interrupt);
496 end Is_Ignored;
498 ---------------------
499 -- Current_Handler --
500 ---------------------
502 function Current_Handler (Interrupt : Interrupt_ID)
503 return Parameterless_Handler is
504 begin
505 if Is_Reserved (Interrupt) then
506 Raise_Exception (Program_Error'Identity, "Interrupt" &
507 Interrupt_ID'Image (Interrupt) & " is reserved");
508 end if;
510 -- ??? Since Parameterless_Handler is not Atomic, the
511 -- current implementation is wrong. We need a new service in
512 -- Interrupt_Manager to ensure atomicity.
514 return User_Handler (Interrupt).H;
515 end Current_Handler;
517 --------------------
518 -- Attach_Handler --
519 --------------------
521 -- Calling this procedure with New_Handler = null and Static = True
522 -- means we want to detach the current handler regardless of the
523 -- previous handler's binding status (ie. do not care if it is a
524 -- dynamic or static handler).
526 -- This option is needed so that during the finalization of a PO, we
527 -- can detach handlers attached through pragma Attach_Handler.
529 procedure Attach_Handler
530 (New_Handler : in Parameterless_Handler;
531 Interrupt : in Interrupt_ID;
532 Static : in Boolean := False)
534 begin
535 if Is_Reserved (Interrupt) then
536 Raise_Exception (Program_Error'Identity, "Interrupt" &
537 Interrupt_ID'Image (Interrupt) & " is reserved");
538 end if;
540 Interrupt_Manager.Attach_Handler (New_Handler, Interrupt, Static);
542 end Attach_Handler;
544 ----------------------
545 -- Exchange_Handler --
546 ----------------------
548 -- Calling this procedure with New_Handler = null and Static = True
549 -- means we want to detach the current handler regardless of the
550 -- previous handler's binding status (ie. do not care if it is a
551 -- dynamic or static handler).
553 -- This option is needed so that during the finalization of a PO, we
554 -- can detach handlers attached through pragma Attach_Handler.
556 procedure Exchange_Handler
557 (Old_Handler : out Parameterless_Handler;
558 New_Handler : in Parameterless_Handler;
559 Interrupt : in Interrupt_ID;
560 Static : in Boolean := False)
562 begin
563 if Is_Reserved (Interrupt) then
564 Raise_Exception (Program_Error'Identity, "Interrupt" &
565 Interrupt_ID'Image (Interrupt) & " is reserved");
566 end if;
568 Interrupt_Manager.Exchange_Handler
569 (Old_Handler, New_Handler, Interrupt, Static);
571 end Exchange_Handler;
573 --------------------
574 -- Detach_Handler --
575 --------------------
577 -- Calling this procedure with Static = True means we want to Detach the
578 -- current handler regardless of the previous handler's binding status
579 -- (i.e. do not care if it is a dynamic or static handler).
581 -- This option is needed so that during the finalization of a PO, we can
582 -- detach handlers attached through pragma Attach_Handler.
584 procedure Detach_Handler
585 (Interrupt : in Interrupt_ID;
586 Static : in Boolean := False)
588 begin
589 if Is_Reserved (Interrupt) then
590 Raise_Exception (Program_Error'Identity, "Interrupt" &
591 Interrupt_ID'Image (Interrupt) & " is reserved");
592 end if;
594 Interrupt_Manager.Detach_Handler (Interrupt, Static);
596 end Detach_Handler;
598 ---------------
599 -- Reference --
600 ---------------
602 function Reference (Interrupt : Interrupt_ID) return System.Address is
603 begin
604 if Is_Reserved (Interrupt) then
605 Raise_Exception (Program_Error'Identity, "Interrupt" &
606 Interrupt_ID'Image (Interrupt) & " is reserved");
607 end if;
609 return Storage_Elements.To_Address
610 (Storage_Elements.Integer_Address (Interrupt));
611 end Reference;
613 -----------------------------
614 -- Bind_Interrupt_To_Entry --
615 -----------------------------
617 -- This procedure raises a Program_Error if it tries to
618 -- bind an interrupt to which an Entry or a Procedure is
619 -- already bound.
621 procedure Bind_Interrupt_To_Entry
622 (T : Task_ID;
623 E : Task_Entry_Index;
624 Int_Ref : System.Address)
626 Interrupt : constant Interrupt_ID :=
627 Interrupt_ID (Storage_Elements.To_Integer (Int_Ref));
629 begin
630 if Is_Reserved (Interrupt) then
631 Raise_Exception (Program_Error'Identity, "Interrupt" &
632 Interrupt_ID'Image (Interrupt) & " is reserved");
633 end if;
635 Interrupt_Manager.Bind_Interrupt_To_Entry (T, E, Interrupt);
637 end Bind_Interrupt_To_Entry;
639 ------------------------------
640 -- Detach_Interrupt_Entries --
641 ------------------------------
643 procedure Detach_Interrupt_Entries (T : Task_ID) is
644 begin
645 Interrupt_Manager.Detach_Interrupt_Entries (T);
646 end Detach_Interrupt_Entries;
648 ---------------------
649 -- Block_Interrupt --
650 ---------------------
652 procedure Block_Interrupt (Interrupt : Interrupt_ID) is
653 begin
654 if Is_Reserved (Interrupt) then
655 Raise_Exception (Program_Error'Identity, "Interrupt" &
656 Interrupt_ID'Image (Interrupt) & " is reserved");
657 end if;
659 Interrupt_Manager.Block_Interrupt (Interrupt);
660 end Block_Interrupt;
662 -----------------------
663 -- Unblock_Interrupt --
664 -----------------------
666 procedure Unblock_Interrupt (Interrupt : Interrupt_ID) is
667 begin
668 if Is_Reserved (Interrupt) then
669 Raise_Exception (Program_Error'Identity, "Interrupt" &
670 Interrupt_ID'Image (Interrupt) & " is reserved");
671 end if;
673 Interrupt_Manager.Unblock_Interrupt (Interrupt);
674 end Unblock_Interrupt;
676 ------------------
677 -- Unblocked_By --
678 ------------------
680 function Unblocked_By
681 (Interrupt : Interrupt_ID)
682 return System.Tasking.Task_ID
684 begin
685 if Is_Reserved (Interrupt) then
686 Raise_Exception (Program_Error'Identity, "Interrupt" &
687 Interrupt_ID'Image (Interrupt) & " is reserved");
688 end if;
690 return Last_Unblocker (Interrupt);
691 end Unblocked_By;
693 ----------------------
694 -- Ignore_Interrupt --
695 ----------------------
697 procedure Ignore_Interrupt (Interrupt : Interrupt_ID) is
698 begin
699 if Is_Reserved (Interrupt) then
700 Raise_Exception (Program_Error'Identity, "Interrupt" &
701 Interrupt_ID'Image (Interrupt) & " is reserved");
702 end if;
704 Interrupt_Manager.Ignore_Interrupt (Interrupt);
705 end Ignore_Interrupt;
707 ------------------------
708 -- Unignore_Interrupt --
709 ------------------------
711 procedure Unignore_Interrupt (Interrupt : Interrupt_ID) is
712 begin
713 if Is_Reserved (Interrupt) then
714 Raise_Exception (Program_Error'Identity, "Interrupt" &
715 Interrupt_ID'Image (Interrupt) & " is reserved");
716 end if;
718 Interrupt_Manager.Unignore_Interrupt (Interrupt);
719 end Unignore_Interrupt;
721 -----------------------
722 -- Interrupt_Manager --
723 -----------------------
725 task body Interrupt_Manager is
727 ----------------------
728 -- Local Variables --
729 ----------------------
731 Intwait_Mask : aliased IMNG.Interrupt_Mask;
732 Ret_Interrupt : Interrupt_ID;
733 Old_Mask : aliased IMNG.Interrupt_Mask;
734 Self_ID : Task_ID := POP.Self;
736 ---------------------
737 -- Local Routines --
738 ---------------------
740 procedure Unprotected_Exchange_Handler
741 (Old_Handler : out Parameterless_Handler;
742 New_Handler : in Parameterless_Handler;
743 Interrupt : in Interrupt_ID;
744 Static : in Boolean;
745 Restoration : in Boolean := False);
747 procedure Unprotected_Detach_Handler
748 (Interrupt : in Interrupt_ID;
749 Static : in Boolean);
751 ----------------------------------
752 -- Unprotected_Exchange_Handler --
753 ----------------------------------
755 procedure Unprotected_Exchange_Handler
756 (Old_Handler : out Parameterless_Handler;
757 New_Handler : in Parameterless_Handler;
758 Interrupt : in Interrupt_ID;
759 Static : in Boolean;
760 Restoration : in Boolean := False)
762 begin
763 if User_Entry (Interrupt).T /= Null_Task then
765 -- In case we have an Interrupt Entry already installed.
766 -- raise a program error. (propagate it to the caller).
768 Unlock_Interrupt (Self_ID, Interrupt);
769 Raise_Exception (Program_Error'Identity,
770 "An interrupt is already installed");
771 end if;
773 -- Note : A null handler with Static = True will
774 -- pass the following check. That is the case when we want to
775 -- Detach a handler regardless of the Static status
776 -- of the current_Handler.
777 -- We don't check anything if Restoration is True, since we
778 -- may be detaching a static handler to restore a dynamic one.
780 if not Restoration and then not Static
782 -- Tries to overwrite a static Interrupt Handler with a
783 -- dynamic Handler
785 and then (User_Handler (Interrupt).Static
787 -- The new handler is not specified as an
788 -- Interrupt Handler by a pragma.
790 or else not Is_Registered (New_Handler))
791 then
792 Unlock_Interrupt (Self_ID, Interrupt);
793 Raise_Exception (Program_Error'Identity,
794 "Trying to overwrite a static Interrupt Handler with a " &
795 "dynamic Handler");
796 end if;
798 -- The interrupt should no longer be ingnored if
799 -- it was ever ignored.
801 Ignored (Interrupt) := False;
803 -- Save the old handler
805 Old_Handler := User_Handler (Interrupt).H;
807 -- The new handler
809 User_Handler (Interrupt).H := New_Handler;
811 if New_Handler = null then
813 -- The null handler means we are detaching the handler.
815 User_Handler (Interrupt).Static := False;
817 else
818 User_Handler (Interrupt).Static := Static;
819 end if;
821 -- Invoke a corresponding Server_Task if not yet created.
822 -- Place Task_ID info in Server_ID array.
824 if Server_ID (Interrupt) = Null_Task then
825 Access_Hold := new Server_Task (Interrupt);
826 Server_ID (Interrupt) := To_System (Access_Hold.all'Identity);
827 else
828 POP.Wakeup (Server_ID (Interrupt), Interrupt_Server_Idle_Sleep);
829 end if;
831 end Unprotected_Exchange_Handler;
833 --------------------------------
834 -- Unprotected_Detach_Handler --
835 --------------------------------
837 procedure Unprotected_Detach_Handler
838 (Interrupt : in Interrupt_ID;
839 Static : in Boolean)
841 Old_Handler : Parameterless_Handler;
843 begin
844 if User_Entry (Interrupt).T /= Null_Task then
846 -- In case we have an Interrupt Entry installed.
847 -- raise a program error. (propagate it to the caller).
849 Unlock_Interrupt (Self_ID, Interrupt);
850 Raise_Exception (Program_Error'Identity,
851 "An interrupt entry is already installed");
852 end if;
854 -- Note : Static = True will pass the following check. That is the
855 -- case when we want to detach a handler regardless of the static
856 -- status of the current_Handler.
858 if not Static and then User_Handler (Interrupt).Static then
860 -- Tries to detach a static Interrupt Handler.
861 -- raise a program error.
863 Unlock_Interrupt (Self_ID, Interrupt);
864 Raise_Exception (Program_Error'Identity,
865 "Trying to detach a static Interrupt Handler");
866 end if;
868 -- The interrupt should no longer be ignored if
869 -- it was ever ignored.
871 Ignored (Interrupt) := False;
873 Old_Handler := User_Handler (Interrupt).H;
875 -- The new handler
877 User_Handler (Interrupt).H := null;
878 User_Handler (Interrupt).Static := False;
879 IMOP.Interrupt_Self_Process (IMNG.Interrupt_ID (Interrupt));
881 end Unprotected_Detach_Handler;
883 -- Start of processing for Interrupt_Manager
885 begin
886 -- By making this task independent of master, when the process
887 -- goes away, the Interrupt_Manager will terminate gracefully.
889 System.Tasking.Utilities.Make_Independent;
891 -- Environmen task gets its own interrupt mask, saves it,
892 -- and then masks all interrupts except the Keep_Unmasked set.
894 -- During rendezvous, the Interrupt_Manager receives the old
895 -- interrupt mask of the environment task, and sets its own
896 -- interrupt mask to that value.
898 -- The environment task will call the entry of Interrupt_Manager some
899 -- during elaboration of the body of this package.
901 accept Initialize (Mask : IMNG.Interrupt_Mask) do
902 null;
903 end Initialize;
905 -- Note: All tasks in RTS will have all the Reserve Interrupts
906 -- being masked (except the Interrupt_Manager) and Keep_Unmasked
907 -- unmasked when created.
909 -- Abort_Task_Interrupt is one of the Interrupt unmasked
910 -- in all tasks. We mask the Interrupt in this particular task
911 -- so that "sigwait" is possible to catch an explicitely sent
912 -- Abort_Task_Interrupt from the Server_Tasks.
914 -- This sigwaiting is needed so that we make sure a Server_Task is
915 -- out of its own sigwait state. This extra synchronization is
916 -- necessary to prevent following senarios.
918 -- 1) Interrupt_Manager sends an Abort_Task_Interrupt to the
919 -- Server_Task then changes its own interrupt mask (OS level).
920 -- If an interrupt (corresponding to the Server_Task) arrives
921 -- in the nean time we have the Interrupt_Manager umnasked and
922 -- the Server_Task waiting on sigwait.
924 -- 2) For unbinding handler, we install a default action in the
925 -- Interrupt_Manager. POSIX.1c states that the result of using
926 -- "sigwait" and "sigaction" simaltaneously on the same interrupt
927 -- is undefined. Therefore, we need to be informed from the
928 -- Server_Task of the fact that the Server_Task is out of its
929 -- sigwait stage.
931 loop
932 -- A block is needed to absorb Program_Error exception
934 declare
935 Old_Handler : Parameterless_Handler;
937 begin
938 select
940 accept Attach_Handler
941 (New_Handler : in Parameterless_Handler;
942 Interrupt : in Interrupt_ID;
943 Static : in Boolean;
944 Restoration : in Boolean := False)
946 Lock_Interrupt (Self_ID, Interrupt);
947 Unprotected_Exchange_Handler
948 (Old_Handler, New_Handler, Interrupt, Static, Restoration);
949 Unlock_Interrupt (Self_ID, Interrupt);
950 end Attach_Handler;
952 or accept Exchange_Handler
953 (Old_Handler : out Parameterless_Handler;
954 New_Handler : in Parameterless_Handler;
955 Interrupt : in Interrupt_ID;
956 Static : in Boolean)
958 Lock_Interrupt (Self_ID, Interrupt);
959 Unprotected_Exchange_Handler
960 (Old_Handler, New_Handler, Interrupt, Static);
961 Unlock_Interrupt (Self_ID, Interrupt);
962 end Exchange_Handler;
964 or accept Detach_Handler
965 (Interrupt : in Interrupt_ID;
966 Static : in Boolean)
968 Lock_Interrupt (Self_ID, Interrupt);
969 Unprotected_Detach_Handler (Interrupt, Static);
970 Unlock_Interrupt (Self_ID, Interrupt);
971 end Detach_Handler;
973 or accept Bind_Interrupt_To_Entry
974 (T : Task_ID;
975 E : Task_Entry_Index;
976 Interrupt : Interrupt_ID)
978 Lock_Interrupt (Self_ID, Interrupt);
980 -- if there is a binding already (either a procedure or an
981 -- entry), raise Program_Error (propagate it to the caller).
983 if User_Handler (Interrupt).H /= null
984 or else User_Entry (Interrupt).T /= Null_Task
985 then
986 Unlock_Interrupt (Self_ID, Interrupt);
987 Raise_Exception (Program_Error'Identity,
988 "A binding for this interrupt is already present");
989 end if;
991 -- The interrupt should no longer be ingnored if
992 -- it was ever ignored.
994 Ignored (Interrupt) := False;
995 User_Entry (Interrupt) := Entry_Assoc' (T => T, E => E);
997 -- Indicate the attachment of Interrupt Entry in ATCB.
998 -- This is need so that when an Interrupt Entry task
999 -- terminates the binding can be cleaned.
1000 -- The call to unbinding must be
1001 -- make by the task before it terminates.
1003 T.Interrupt_Entry := True;
1005 -- Invoke a corresponding Server_Task if not yet created.
1006 -- Place Task_ID info in Server_ID array.
1008 if Server_ID (Interrupt) = Null_Task then
1010 Access_Hold := new Server_Task (Interrupt);
1011 Server_ID (Interrupt) :=
1012 To_System (Access_Hold.all'Identity);
1013 else
1014 POP.Wakeup (Server_ID (Interrupt),
1015 Interrupt_Server_Idle_Sleep);
1016 end if;
1018 Unlock_Interrupt (Self_ID, Interrupt);
1019 end Bind_Interrupt_To_Entry;
1021 or accept Detach_Interrupt_Entries (T : Task_ID)
1023 for I in Interrupt_ID'Range loop
1024 if not Is_Reserved (I) then
1025 Lock_Interrupt (Self_ID, I);
1027 if User_Entry (I).T = T then
1029 -- The interrupt should no longer be ignored if
1030 -- it was ever ignored.
1032 Ignored (I) := False;
1033 User_Entry (I) := Entry_Assoc'
1034 (T => Null_Task, E => Null_Task_Entry);
1035 IMOP.Interrupt_Self_Process (IMNG.Interrupt_ID (I));
1036 end if;
1038 Unlock_Interrupt (Self_ID, I);
1039 end if;
1040 end loop;
1042 -- Indicate in ATCB that no Interrupt Entries are attached.
1044 T.Interrupt_Entry := False;
1045 end Detach_Interrupt_Entries;
1047 or accept Block_Interrupt (Interrupt : Interrupt_ID) do
1048 raise Program_Error;
1049 end Block_Interrupt;
1051 or accept Unblock_Interrupt (Interrupt : Interrupt_ID) do
1052 raise Program_Error;
1053 end Unblock_Interrupt;
1055 or accept Ignore_Interrupt (Interrupt : Interrupt_ID) do
1056 raise Program_Error;
1057 end Ignore_Interrupt;
1059 or accept Unignore_Interrupt (Interrupt : Interrupt_ID) do
1060 raise Program_Error;
1061 end Unignore_Interrupt;
1063 end select;
1065 exception
1067 -- If there is a program error we just want to propagate it
1068 -- to the caller and do not want to stop this task.
1070 when Program_Error =>
1071 null;
1073 when others =>
1074 pragma Assert
1075 (Shutdown ("Interrupt_Manager---exception not expected"));
1076 null;
1077 end;
1079 end loop;
1081 pragma Assert (Shutdown ("Interrupt_Manager---should not get here"));
1083 end Interrupt_Manager;
1085 -----------------
1086 -- Server_Task --
1087 -----------------
1089 task body Server_Task is
1090 Self_ID : Task_ID := Self;
1091 Tmp_Handler : Parameterless_Handler;
1092 Tmp_ID : Task_ID;
1093 Tmp_Entry_Index : Task_Entry_Index;
1094 Intwait_Mask : aliased IMNG.Interrupt_Mask;
1095 Ret_Interrupt : IMNG.Interrupt_ID;
1097 begin
1098 -- By making this task independent of master, when the process
1099 -- goes away, the Server_Task will terminate gracefully.
1101 System.Tasking.Utilities.Make_Independent;
1103 -- Install default action in system level.
1105 IMOP.Install_Default_Action (IMNG.Interrupt_ID (Interrupt));
1107 -- Set up the mask (also clears the event flag)
1109 IMOP.Empty_Interrupt_Mask (Intwait_Mask'Access);
1110 IMOP.Add_To_Interrupt_Mask
1111 (Intwait_Mask'Access, IMNG.Interrupt_ID (Interrupt));
1113 -- Remember the Interrupt_ID for Abort_Task.
1115 PIO.Set_Interrupt_ID (IMNG.Interrupt_ID (Interrupt), Self_ID);
1117 -- Note: All tasks in RTS will have all the Reserve Interrupts
1118 -- being masked (except the Interrupt_Manager) and Keep_Unmasked
1119 -- unmasked when created.
1121 loop
1122 System.Tasking.Initialization.Defer_Abort (Self_ID);
1124 -- A Handler or an Entry is installed. At this point all tasks
1125 -- mask for the Interrupt is masked. Catch the Interrupt using
1126 -- sigwait.
1128 -- This task may wake up from sigwait by receiving an interrupt
1129 -- (Abort_Task_Interrupt) from the Interrupt_Manager for unbinding
1130 -- a Procedure Handler or an Entry. Or it could be a wake up
1131 -- from status change (Unblocked -> Blocked). If that is not
1132 -- the case, we should exceute the attached Procedure or Entry.
1134 POP.Write_Lock (Self_ID);
1136 if User_Handler (Interrupt).H = null
1137 and then User_Entry (Interrupt).T = Null_Task
1138 then
1139 -- No Interrupt binding. If there is an interrupt,
1140 -- Interrupt_Manager will take default action.
1142 Self_ID.Common.State := Interrupt_Server_Idle_Sleep;
1143 POP.Sleep (Self_ID, Interrupt_Server_Idle_Sleep);
1144 Self_ID.Common.State := Runnable;
1146 else
1148 Self_ID.Common.State := Interrupt_Server_Blocked_On_Event_Flag;
1149 Ret_Interrupt := IMOP.Interrupt_Wait (Intwait_Mask'Access);
1150 Self_ID.Common.State := Runnable;
1152 if not (Self_ID.Deferral_Level = 0
1153 and then Self_ID.Pending_ATC_Level
1154 < Self_ID.ATC_Nesting_Level)
1155 then
1156 if User_Handler (Interrupt).H /= null then
1157 Tmp_Handler := User_Handler (Interrupt).H;
1159 -- RTS calls should not be made with self being locked.
1161 POP.Unlock (Self_ID);
1163 Tmp_Handler.all;
1164 POP.Write_Lock (Self_ID);
1166 elsif User_Entry (Interrupt).T /= Null_Task then
1167 Tmp_ID := User_Entry (Interrupt).T;
1168 Tmp_Entry_Index := User_Entry (Interrupt).E;
1170 -- RTS calls should not be made with self being locked.
1172 POP.Unlock (Self_ID);
1174 System.Tasking.Rendezvous.Call_Simple
1175 (Tmp_ID, Tmp_Entry_Index, System.Null_Address);
1177 POP.Write_Lock (Self_ID);
1178 end if;
1179 end if;
1180 end if;
1182 POP.Unlock (Self_ID);
1183 System.Tasking.Initialization.Undefer_Abort (Self_ID);
1185 -- Undefer abort here to allow a window for this task
1186 -- to be aborted at the time of system shutdown.
1187 end loop;
1189 pragma Assert (Shutdown ("Server_Task---should not get here"));
1190 end Server_Task;
1192 -------------------------------------
1193 -- Has_Interrupt_Or_Attach_Handler --
1194 -------------------------------------
1196 function Has_Interrupt_Or_Attach_Handler
1197 (Object : access Dynamic_Interrupt_Protection) return Boolean is
1198 begin
1199 return True;
1200 end Has_Interrupt_Or_Attach_Handler;
1202 ----------------
1203 -- Finalize --
1204 ----------------
1206 procedure Finalize (Object : in out Static_Interrupt_Protection) is
1207 begin
1208 -- ??? loop to be executed only when we're not doing library level
1209 -- finalization, since in this case all interrupt tasks are gone.
1210 if not Interrupt_Manager'Terminated then
1211 for N in reverse Object.Previous_Handlers'Range loop
1212 Interrupt_Manager.Attach_Handler
1213 (New_Handler => Object.Previous_Handlers (N).Handler,
1214 Interrupt => Object.Previous_Handlers (N).Interrupt,
1215 Static => Object.Previous_Handlers (N).Static,
1216 Restoration => True);
1217 end loop;
1218 end if;
1220 Tasking.Protected_Objects.Entries.Finalize
1221 (Tasking.Protected_Objects.Entries.Protection_Entries (Object));
1222 end Finalize;
1224 -------------------------------------
1225 -- Has_Interrupt_Or_Attach_Handler --
1226 -------------------------------------
1228 function Has_Interrupt_Or_Attach_Handler
1229 (Object : access Static_Interrupt_Protection)
1230 return Boolean
1232 begin
1233 return True;
1234 end Has_Interrupt_Or_Attach_Handler;
1236 ----------------------
1237 -- Install_Handlers --
1238 ----------------------
1240 procedure Install_Handlers
1241 (Object : access Static_Interrupt_Protection;
1242 New_Handlers : in New_Handler_Array)
1244 begin
1245 for N in New_Handlers'Range loop
1247 -- We need a lock around this ???
1249 Object.Previous_Handlers (N).Interrupt := New_Handlers (N).Interrupt;
1250 Object.Previous_Handlers (N).Static := User_Handler
1251 (New_Handlers (N).Interrupt).Static;
1253 -- We call Exchange_Handler and not directly Interrupt_Manager.
1254 -- Exchange_Handler so we get the Is_Reserved check.
1256 Exchange_Handler
1257 (Old_Handler => Object.Previous_Handlers (N).Handler,
1258 New_Handler => New_Handlers (N).Handler,
1259 Interrupt => New_Handlers (N).Interrupt,
1260 Static => True);
1261 end loop;
1262 end Install_Handlers;
1264 -- Elaboration code for package System.Interrupts
1265 begin
1267 -- Get Interrupt_Manager's ID so that Abort_Interrupt can be sent.
1269 Interrupt_Manager_ID := To_System (Interrupt_Manager'Identity);
1271 -- Initialize the lock L.
1273 Initialization.Defer_Abort (Self);
1274 POP.Initialize_Lock (L'Access, POP.ATCB_Level);
1275 Initialization.Undefer_Abort (Self);
1277 -- During the elaboration of this package body we want RTS to
1278 -- inherit the interrupt mask from the Environment Task.
1280 -- The Environment Task should have gotten its mask from
1281 -- the enclosing process during the RTS start up. (See
1282 -- in s-inmaop.adb). Pass the Interrupt_Mask of the Environment
1283 -- task to the Interrupt_Manager.
1285 -- Note : At this point we know that all tasks (including
1286 -- RTS internal servers) are masked for non-reserved signals
1287 -- (see s-taprop.adb). Only the Interrupt_Manager will have
1288 -- masks set up differently inheriting the original Environment
1289 -- Task's mask.
1291 Interrupt_Manager.Initialize (IMOP.Environment_Mask);
1292 end System.Interrupts;