OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-interr.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS               --
4 --                                                                          --
5 --                     S Y S T E M . I N T E R R U P T S                    --
6 --                                                                          --
7 --                                  B o d y                                 --
8 --                                                                          --
9 --                                                                          --
10 --         Copyright (C) 1992-2002, Free Software Foundation, Inc.          --
11 --                                                                          --
12 -- GNARL is free software; you can  redistribute it  and/or modify it under --
13 -- terms of the  GNU General Public License as published  by the Free Soft- --
14 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
15 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
18 -- for  more details.  You should have  received  a copy of the GNU General --
19 -- Public License  distributed with GNARL; see file COPYING.  If not, write --
20 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
21 -- MA 02111-1307, USA.                                                      --
22 --                                                                          --
23 -- As a special exception,  if other files  instantiate  generics from this --
24 -- unit, or you link  this unit with other files  to produce an executable, --
25 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
26 -- covered  by the  GNU  General  Public  License.  This exception does not --
27 -- however invalidate  any other reasons why  the executable file  might be --
28 -- covered by the  GNU Public License.                                      --
29 --                                                                          --
30 -- GNARL was developed by the GNARL team at Florida State University.       --
31 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
32 --                                                                          --
33 ------------------------------------------------------------------------------
34
35 --  Invariants:
36
37 --  All user-handleable interrupts are masked at all times in all
38 --  tasks/threads except possibly for the Interrupt_Manager task.
39
40 --  When a user task wants to have the effect of masking/unmasking an
41 --  interrupt, it must call Block_Interrupt/Unblock_Interrupt, which
42 --  will have the effect of unmasking/masking the interrupt in the
43 --  Interrupt_Manager task.
44
45 --  Note : Direct calls to sigaction, sigprocmask, pthread_sigsetmask or any
46 --  other low-level interface that changes the interrupt action or
47 --  interrupt mask needs a careful thought.
48 --  One may acheive the effect of system calls first masking RTS blocked
49 --  (by calling Block_Interrupt) for the interrupt under consideration.
50 --  This will make all the tasks in RTS blocked for the Interrupt.
51
52 --  Once we associate a Server_Task with an interrupt, the task never
53 --  goes away, and we never remove the association.
54
55 --  There is no more than one interrupt per Server_Task and no more than
56 --  one Server_Task per interrupt.
57
58 with Ada.Task_Identification;
59 --  used for Task_ID type
60
61 with Ada.Exceptions;
62 --  used for Raise_Exception
63
64 with System.Task_Primitives;
65 --  used for RTS_Lock
66 --           Self
67
68 with System.Interrupt_Management;
69 --  used for Reserve
70 --           Interrupt_ID
71 --           Interrupt_Mask
72 --           Abort_Task_Interrupt
73
74 with System.Interrupt_Management.Operations;
75 --  used for Thread_Block_Interrupt
76 --           Thread_Unblock_Interrupt
77 --           Install_Default_Action
78 --           Install_Ignore_Action
79 --           Copy_Interrupt_Mask
80 --           Set_Interrupt_Mask
81 --           Empty_Interrupt_Mask
82 --           Fill_Interrupt_Mask
83 --           Add_To_Interrupt_Mask
84 --           Delete_From_Interrupt_Mask
85 --           Interrupt_Wait
86 --           Interrupt_Self_Process
87 --           Get_Interrupt_Mask
88 --           Set_Interrupt_Mask
89 --           IS_Member
90 --           Environment_Mask
91 --           All_Tasks_Mask
92 pragma Elaborate_All (System.Interrupt_Management.Operations);
93
94 with System.Task_Primitives.Operations;
95 --  used for Write_Lock
96 --           Unlock
97 --           Abort
98 --           Wakeup_Task
99 --           Sleep
100 --           Initialize_Lock
101
102 with System.Task_Primitives.Interrupt_Operations;
103 --  used for Set_Interrupt_ID
104
105 with System.Storage_Elements;
106 --  used for To_Address
107 --           To_Integer
108 --           Integer_Address
109
110 with System.Tasking;
111 --  used for Task_ID
112 --           Task_Entry_Index
113 --           Null_Task
114 --           Self
115 --           Interrupt_Manager_ID
116
117 with System.Tasking.Utilities;
118 --  used for Make_Independent
119
120 with System.Tasking.Rendezvous;
121 --  used for Call_Simple
122 pragma Elaborate_All (System.Tasking.Rendezvous);
123
124 with System.Tasking.Initialization;
125 --  used for Defer_Abort
126 --           Undefer_Abort
127
128 with System.Parameters;
129 --  used for Single_Lock
130
131 with Unchecked_Conversion;
132
133 package body System.Interrupts is
134
135    use Parameters;
136    use Tasking;
137    use Ada.Exceptions;
138
139    package PRI renames System.Task_Primitives;
140    package POP renames System.Task_Primitives.Operations;
141    package PIO renames System.Task_Primitives.Interrupt_Operations;
142    package IMNG renames System.Interrupt_Management;
143    package IMOP renames System.Interrupt_Management.Operations;
144
145    function To_System is new Unchecked_Conversion
146      (Ada.Task_Identification.Task_Id, Task_ID);
147
148    -----------------
149    -- Local Tasks --
150    -----------------
151
152    --  WARNING: System.Tasking.Stages performs calls to this task
153    --  with low-level constructs. Do not change this spec without synchro-
154    --  nizing it.
155
156    task Interrupt_Manager is
157       entry Detach_Interrupt_Entries (T : Task_ID);
158
159       entry Initialize (Mask : IMNG.Interrupt_Mask);
160
161       entry Attach_Handler
162         (New_Handler : in Parameterless_Handler;
163          Interrupt   : in Interrupt_ID;
164          Static      : in Boolean;
165          Restoration : in Boolean := False);
166
167       entry Exchange_Handler
168         (Old_Handler : out Parameterless_Handler;
169          New_Handler : in Parameterless_Handler;
170          Interrupt   : in Interrupt_ID;
171          Static      : in Boolean);
172
173       entry Detach_Handler
174         (Interrupt   : in Interrupt_ID;
175          Static      : in Boolean);
176
177       entry Bind_Interrupt_To_Entry
178         (T         : Task_ID;
179          E         : Task_Entry_Index;
180          Interrupt : Interrupt_ID);
181
182       entry Block_Interrupt (Interrupt : Interrupt_ID);
183
184       entry Unblock_Interrupt (Interrupt : Interrupt_ID);
185
186       entry Ignore_Interrupt (Interrupt : Interrupt_ID);
187
188       entry Unignore_Interrupt (Interrupt : Interrupt_ID);
189
190       pragma Interrupt_Priority (System.Interrupt_Priority'Last);
191    end Interrupt_Manager;
192
193    task type Server_Task (Interrupt : Interrupt_ID) is
194       pragma Priority (System.Interrupt_Priority'Last);
195    end Server_Task;
196
197    type Server_Task_Access is access Server_Task;
198
199    -------------------------------
200    -- Local Types and Variables --
201    -------------------------------
202
203    type Entry_Assoc is record
204       T : Task_ID;
205       E : Task_Entry_Index;
206    end record;
207
208    type Handler_Assoc is record
209       H      : Parameterless_Handler;
210       Static : Boolean;   --  Indicates static binding;
211    end record;
212
213    User_Handler : array (Interrupt_ID'Range) of Handler_Assoc :=
214                     (others => (null, Static => False));
215    pragma Volatile_Components (User_Handler);
216    --  Holds the protected procedure handler (if any) and its Static
217    --  information  for each interrupt. A handler is a Static one if
218    --  it is specified through the pragma Attach_Handler.
219    --  Attach_Handler. Otherwise, not static)
220
221    User_Entry : array (Interrupt_ID'Range) of Entry_Assoc :=
222                   (others => (T => Null_Task, E => Null_Task_Entry));
223    pragma Volatile_Components (User_Entry);
224    --  Holds the task and entry index (if any) for each interrupt
225
226    Blocked : array (Interrupt_ID'Range) of Boolean := (others => False);
227    pragma Volatile_Components (Blocked);
228    --  True iff the corresponding interrupt is blocked in the process level
229
230    Ignored : array (Interrupt_ID'Range) of Boolean := (others => False);
231    pragma Volatile_Components (Ignored);
232    --  True iff the corresponding interrupt is blocked in the process level
233
234    Last_Unblocker :
235      array (Interrupt_ID'Range) of Task_ID := (others => Null_Task);
236    pragma Volatile_Components (Last_Unblocker);
237    --  Holds the ID of the last Task which Unblocked this Interrupt.
238    --  It contains Null_Task if no tasks have ever requested the
239    --  Unblocking operation or the Interrupt is currently Blocked.
240
241    Server_ID : array (Interrupt_ID'Range) of Task_ID :=
242                  (others => Null_Task);
243    pragma Atomic_Components (Server_ID);
244    --  Holds the Task_ID of the Server_Task for each interrupt.
245    --  Task_ID is needed to accomplish locking per Interrupt base. Also
246    --  is needed to decide whether to create a new Server_Task.
247
248    --  Type and Head, Tail of the list containing Registered Interrupt
249    --  Handlers. These definitions are used to register the handlers
250    --  specified by the pragma Interrupt_Handler.
251
252    type Registered_Handler;
253    type R_Link is access all Registered_Handler;
254
255    type Registered_Handler is record
256       H :    System.Address := System.Null_Address;
257       Next : R_Link := null;
258    end record;
259
260    Registered_Handler_Head : R_Link := null;
261    Registered_Handler_Tail : R_Link := null;
262
263    Access_Hold : Server_Task_Access;
264    --  variable used to allocate Server_Task using "new".
265
266    -----------------------
267    -- Local Subprograms --
268    -----------------------
269
270    function Is_Registered (Handler : Parameterless_Handler) return Boolean;
271    --  See if the Handler has been "pragma"ed using Interrupt_Handler.
272    --  Always consider a null handler as registered.
273
274    --------------------
275    -- Attach_Handler --
276    --------------------
277
278    --  Calling this procedure with New_Handler = null and Static = True
279    --  means we want to detach the current handler regardless of the
280    --  previous handler's binding status (ie. do not care if it is a
281    --  dynamic or static handler).
282
283    --  This option is needed so that during the finalization of a PO, we
284    --  can detach handlers attached through pragma Attach_Handler.
285
286    procedure Attach_Handler
287      (New_Handler : in Parameterless_Handler;
288       Interrupt   : in Interrupt_ID;
289       Static      : in Boolean := False)
290    is
291    begin
292       if Is_Reserved (Interrupt) then
293          Raise_Exception (Program_Error'Identity, "Interrupt" &
294            Interrupt_ID'Image (Interrupt) & " is reserved");
295       end if;
296
297       Interrupt_Manager.Attach_Handler (New_Handler, Interrupt, Static);
298
299    end Attach_Handler;
300
301    -----------------------------
302    -- Bind_Interrupt_To_Entry --
303    -----------------------------
304
305    --  This procedure raises a Program_Error if it tries to
306    --  bind an interrupt to which an Entry or a Procedure is
307    --  already bound.
308
309    procedure Bind_Interrupt_To_Entry
310      (T       : Task_ID;
311       E       : Task_Entry_Index;
312       Int_Ref : System.Address)
313    is
314       Interrupt   : constant Interrupt_ID :=
315         Interrupt_ID (Storage_Elements.To_Integer (Int_Ref));
316
317    begin
318       if Is_Reserved (Interrupt) then
319          Raise_Exception (Program_Error'Identity, "Interrupt" &
320            Interrupt_ID'Image (Interrupt) & " is reserved");
321       end if;
322
323       Interrupt_Manager.Bind_Interrupt_To_Entry (T, E, Interrupt);
324
325    end Bind_Interrupt_To_Entry;
326
327    ---------------------
328    -- Block_Interrupt --
329    ---------------------
330
331    procedure Block_Interrupt (Interrupt : Interrupt_ID) is
332    begin
333       if Is_Reserved (Interrupt) then
334          Raise_Exception (Program_Error'Identity, "Interrupt" &
335            Interrupt_ID'Image (Interrupt) & " is reserved");
336       end if;
337
338       Interrupt_Manager.Block_Interrupt (Interrupt);
339    end Block_Interrupt;
340
341    ---------------------
342    -- Current_Handler --
343    ---------------------
344
345    function Current_Handler
346      (Interrupt : Interrupt_ID)
347       return      Parameterless_Handler
348    is
349    begin
350       if Is_Reserved (Interrupt) then
351          Raise_Exception (Program_Error'Identity, "Interrupt" &
352            Interrupt_ID'Image (Interrupt) & " is reserved");
353       end if;
354
355       --  ??? Since Parameterless_Handler is not Atomic, the
356       --  current implementation is wrong. We need a new service in
357       --  Interrupt_Manager to ensure atomicity.
358
359       return User_Handler (Interrupt).H;
360    end Current_Handler;
361
362    --------------------
363    -- Detach_Handler --
364    --------------------
365
366    --  Calling this procedure with Static = True means we want to Detach the
367    --  current handler regardless of the previous handler's binding status
368    --  (i.e. do not care if it is a dynamic or static handler).
369
370    --  This option is needed so that during the finalization of a PO, we can
371    --  detach handlers attached through pragma Attach_Handler.
372
373    procedure Detach_Handler
374      (Interrupt : in Interrupt_ID;
375       Static    : in Boolean := False)
376    is
377    begin
378       if Is_Reserved (Interrupt) then
379          Raise_Exception (Program_Error'Identity, "Interrupt" &
380            Interrupt_ID'Image (Interrupt) & " is reserved");
381       end if;
382
383       Interrupt_Manager.Detach_Handler (Interrupt, Static);
384
385    end Detach_Handler;
386
387    ------------------------------
388    -- Detach_Interrupt_Entries --
389    ------------------------------
390
391    procedure Detach_Interrupt_Entries (T : Task_ID) is
392    begin
393       Interrupt_Manager.Detach_Interrupt_Entries (T);
394    end Detach_Interrupt_Entries;
395
396    ----------------------
397    -- Exchange_Handler --
398    ----------------------
399
400    --  Calling this procedure with New_Handler = null and Static = True
401    --  means we want to detach the current handler regardless of the
402    --  previous handler's binding status (ie. do not care if it is a
403    --  dynamic or static handler).
404
405    --  This option is needed so that during the finalization of a PO, we
406    --  can detach handlers attached through pragma Attach_Handler.
407
408    procedure Exchange_Handler
409      (Old_Handler : out Parameterless_Handler;
410       New_Handler : in Parameterless_Handler;
411       Interrupt   : in Interrupt_ID;
412       Static      : in Boolean := False)
413    is
414    begin
415       if Is_Reserved (Interrupt) then
416          Raise_Exception (Program_Error'Identity, "Interrupt" &
417            Interrupt_ID'Image (Interrupt) & " is reserved");
418       end if;
419
420       Interrupt_Manager.Exchange_Handler
421         (Old_Handler, New_Handler, Interrupt, Static);
422
423    end Exchange_Handler;
424
425    ----------------
426    --  Finalize  --
427    ----------------
428
429    procedure Finalize (Object : in out Static_Interrupt_Protection) is
430    begin
431       --  ??? loop to be executed only when we're not doing library level
432       --  finalization, since in this case all interrupt tasks are gone.
433       if not Interrupt_Manager'Terminated then
434          for N in reverse Object.Previous_Handlers'Range loop
435             Interrupt_Manager.Attach_Handler
436               (New_Handler => Object.Previous_Handlers (N).Handler,
437                Interrupt   => Object.Previous_Handlers (N).Interrupt,
438                Static      => Object.Previous_Handlers (N).Static,
439                Restoration => True);
440          end loop;
441       end if;
442
443       Tasking.Protected_Objects.Entries.Finalize
444         (Tasking.Protected_Objects.Entries.Protection_Entries (Object));
445    end Finalize;
446
447    -------------------------------------
448    -- Has_Interrupt_Or_Attach_Handler --
449    -------------------------------------
450
451    function Has_Interrupt_Or_Attach_Handler
452      (Object : access Dynamic_Interrupt_Protection) return Boolean is
453    begin
454       return True;
455    end Has_Interrupt_Or_Attach_Handler;
456
457    function Has_Interrupt_Or_Attach_Handler
458      (Object : access Static_Interrupt_Protection)
459       return   Boolean
460    is
461    begin
462       return True;
463    end Has_Interrupt_Or_Attach_Handler;
464
465    ----------------------
466    -- Ignore_Interrupt --
467    ----------------------
468
469    procedure Ignore_Interrupt (Interrupt : Interrupt_ID) is
470    begin
471       if Is_Reserved (Interrupt) then
472          Raise_Exception (Program_Error'Identity, "Interrupt" &
473            Interrupt_ID'Image (Interrupt) & " is reserved");
474       end if;
475
476       Interrupt_Manager.Ignore_Interrupt (Interrupt);
477    end Ignore_Interrupt;
478
479    ----------------------
480    -- Install_Handlers --
481    ----------------------
482
483    procedure Install_Handlers
484      (Object       : access Static_Interrupt_Protection;
485       New_Handlers : in New_Handler_Array)
486    is
487    begin
488       for N in New_Handlers'Range loop
489
490          --  We need a lock around this ???
491
492          Object.Previous_Handlers (N).Interrupt := New_Handlers (N).Interrupt;
493          Object.Previous_Handlers (N).Static    := User_Handler
494            (New_Handlers (N).Interrupt).Static;
495
496          --  We call Exchange_Handler and not directly Interrupt_Manager.
497          --  Exchange_Handler so we get the Is_Reserved check.
498
499          Exchange_Handler
500            (Old_Handler => Object.Previous_Handlers (N).Handler,
501             New_Handler => New_Handlers (N).Handler,
502             Interrupt   => New_Handlers (N).Interrupt,
503             Static      => True);
504       end loop;
505    end Install_Handlers;
506
507    ----------------
508    -- Is_Blocked --
509    ----------------
510
511    function Is_Blocked (Interrupt : Interrupt_ID) return Boolean is
512    begin
513       if Is_Reserved (Interrupt) then
514          Raise_Exception (Program_Error'Identity, "Interrupt" &
515            Interrupt_ID'Image (Interrupt) & " is reserved");
516       end if;
517
518       return Blocked (Interrupt);
519    end Is_Blocked;
520
521    -----------------------
522    -- Is_Entry_Attached --
523    -----------------------
524
525    function Is_Entry_Attached (Interrupt : Interrupt_ID) return Boolean is
526    begin
527       if Is_Reserved (Interrupt) then
528          Raise_Exception (Program_Error'Identity, "Interrupt" &
529            Interrupt_ID'Image (Interrupt) & " is reserved");
530       end if;
531
532       return User_Entry (Interrupt).T /= Null_Task;
533    end Is_Entry_Attached;
534
535    -------------------------
536    -- Is_Handler_Attached --
537    -------------------------
538
539    function Is_Handler_Attached (Interrupt : Interrupt_ID) return Boolean is
540    begin
541       if Is_Reserved (Interrupt) then
542          Raise_Exception (Program_Error'Identity, "Interrupt" &
543            Interrupt_ID'Image (Interrupt) & " is reserved");
544       end if;
545
546       return User_Handler (Interrupt).H /= null;
547    end Is_Handler_Attached;
548
549    ----------------
550    -- Is_Ignored --
551    ----------------
552
553    function Is_Ignored (Interrupt : Interrupt_ID) return Boolean is
554    begin
555       if Is_Reserved (Interrupt) then
556          Raise_Exception (Program_Error'Identity, "Interrupt" &
557            Interrupt_ID'Image (Interrupt) & " is reserved");
558       end if;
559
560       return Ignored (Interrupt);
561    end Is_Ignored;
562
563    -------------------
564    -- Is_Registered --
565    -------------------
566
567    function Is_Registered (Handler : Parameterless_Handler) return Boolean is
568
569       type Fat_Ptr is record
570          Object_Addr  : System.Address;
571          Handler_Addr : System.Address;
572       end record;
573
574       function To_Fat_Ptr is new Unchecked_Conversion
575         (Parameterless_Handler, Fat_Ptr);
576
577       Ptr : R_Link;
578       Fat : Fat_Ptr;
579
580    begin
581       if Handler = null then
582          return True;
583       end if;
584
585       Fat := To_Fat_Ptr (Handler);
586
587       Ptr := Registered_Handler_Head;
588
589       while (Ptr /= null) loop
590          if Ptr.H = Fat.Handler_Addr then
591             return True;
592          end if;
593
594          Ptr := Ptr.Next;
595       end loop;
596
597       return False;
598
599    end Is_Registered;
600
601    -----------------
602    -- Is_Reserved --
603    -----------------
604
605    function Is_Reserved (Interrupt : Interrupt_ID) return Boolean is
606    begin
607       return IMNG.Reserve (IMNG.Interrupt_ID (Interrupt));
608    end Is_Reserved;
609
610    ---------------
611    -- Reference --
612    ---------------
613
614    function Reference (Interrupt : Interrupt_ID) return System.Address is
615    begin
616       if Is_Reserved (Interrupt) then
617          Raise_Exception (Program_Error'Identity, "Interrupt" &
618            Interrupt_ID'Image (Interrupt) & " is reserved");
619       end if;
620
621       return Storage_Elements.To_Address
622         (Storage_Elements.Integer_Address (Interrupt));
623    end Reference;
624
625    ---------------------------------
626    -- Register_Interrupt_Handler  --
627    ---------------------------------
628
629    procedure Register_Interrupt_Handler (Handler_Addr : System.Address) is
630       New_Node_Ptr : R_Link;
631
632    begin
633       --  This routine registers the Handler as usable for Dynamic
634       --  Interrupt Handler. Routines attaching and detaching Handler
635       --  dynamically should first consult if the Handler is rgistered.
636       --  A Program Error should be raised if it is not registered.
637
638       --  The pragma Interrupt_Handler can only appear in the library
639       --  level PO definition and instantiation. Therefore, we do not need
640       --  to implement Unregistering operation. Neither we need to
641       --  protect the queue structure using a Lock.
642
643       pragma Assert (Handler_Addr /= System.Null_Address);
644
645       New_Node_Ptr := new Registered_Handler;
646       New_Node_Ptr.H := Handler_Addr;
647
648       if Registered_Handler_Head = null then
649          Registered_Handler_Head := New_Node_Ptr;
650          Registered_Handler_Tail := New_Node_Ptr;
651
652       else
653          Registered_Handler_Tail.Next := New_Node_Ptr;
654          Registered_Handler_Tail := New_Node_Ptr;
655       end if;
656    end Register_Interrupt_Handler;
657
658    -----------------------
659    -- Unblock_Interrupt --
660    -----------------------
661
662    procedure Unblock_Interrupt (Interrupt : Interrupt_ID) is
663    begin
664       if Is_Reserved (Interrupt) then
665          Raise_Exception (Program_Error'Identity, "Interrupt" &
666            Interrupt_ID'Image (Interrupt) & " is reserved");
667       end if;
668
669       Interrupt_Manager.Unblock_Interrupt (Interrupt);
670    end Unblock_Interrupt;
671
672    ------------------
673    -- Unblocked_By --
674    ------------------
675
676    function Unblocked_By
677      (Interrupt : Interrupt_ID)
678       return      System.Tasking.Task_ID
679    is
680    begin
681       if Is_Reserved (Interrupt) then
682          Raise_Exception (Program_Error'Identity, "Interrupt" &
683            Interrupt_ID'Image (Interrupt) & " is reserved");
684       end if;
685
686       return Last_Unblocker (Interrupt);
687    end Unblocked_By;
688
689    ------------------------
690    -- Unignore_Interrupt --
691    ------------------------
692
693    procedure Unignore_Interrupt (Interrupt : Interrupt_ID) is
694    begin
695       if Is_Reserved (Interrupt) then
696          Raise_Exception (Program_Error'Identity, "Interrupt" &
697            Interrupt_ID'Image (Interrupt) & " is reserved");
698       end if;
699
700       Interrupt_Manager.Unignore_Interrupt (Interrupt);
701    end Unignore_Interrupt;
702
703    -----------------------
704    -- Interrupt_Manager --
705    -----------------------
706
707    task body Interrupt_Manager is
708
709       ----------------------
710       --  Local Variables --
711       ----------------------
712
713       Intwait_Mask  : aliased IMNG.Interrupt_Mask;
714       Ret_Interrupt : Interrupt_ID;
715       Old_Mask      : aliased IMNG.Interrupt_Mask;
716       Self_ID       : Task_ID := POP.Self;
717       Old_Handler   : Parameterless_Handler;
718
719       ---------------------
720       --  Local Routines --
721       ---------------------
722
723       procedure Bind_Handler (Interrupt : Interrupt_ID);
724       --  This procedure does not do anything if the Interrupt is blocked.
725       --  Otherwise, we have to interrupt Server_Task for status change through
726       --  Wakeup interrupt.
727
728       procedure Unbind_Handler (Interrupt : Interrupt_ID);
729       --  This procedure does not do anything if the Interrupt is blocked.
730       --  Otherwise, we have to interrupt Server_Task for status change
731       --  through abort interrupt.
732
733       procedure Unprotected_Exchange_Handler
734         (Old_Handler : out Parameterless_Handler;
735          New_Handler : in  Parameterless_Handler;
736          Interrupt   : in  Interrupt_ID;
737          Static      : in  Boolean;
738          Restoration : in  Boolean := False);
739
740       procedure Unprotected_Detach_Handler
741         (Interrupt   : in Interrupt_ID;
742          Static      : in Boolean);
743
744       ------------------
745       -- Bind_Handler --
746       ------------------
747
748       procedure Bind_Handler (Interrupt : Interrupt_ID) is
749       begin
750          if not Blocked (Interrupt) then
751
752             --  Mask this task for the given Interrupt so that all tasks
753             --  are masked for the Interrupt and the actuall delivery of the
754             --  Interrupt will be caught using "sigwait" by the
755             --  corresponding Server_Task.
756
757             IMOP.Thread_Block_Interrupt (IMNG.Interrupt_ID (Interrupt));
758
759             --  We have installed a Handler or an Entry before we called
760             --  this procedure. If the Handler Task is waiting to be awakened,
761             --  do it here. Otherwise, the interrupt will be discarded.
762
763             POP.Wakeup (Server_ID (Interrupt), Interrupt_Server_Idle_Sleep);
764          end if;
765       end Bind_Handler;
766
767       --------------------
768       -- Unbind_Handler --
769       --------------------
770
771       procedure Unbind_Handler (Interrupt : Interrupt_ID) is
772       begin
773          if not Blocked (Interrupt) then
774
775             --  Currently, there is a Handler or an Entry attached and
776             --  corresponding Server_Task is waiting on "sigwait."
777             --  We have to wake up the Server_Task and make it
778             --  wait on condition variable by sending an
779             --  Abort_Task_Interrupt
780
781             POP.Abort_Task (Server_ID (Interrupt));
782
783             --  Make sure corresponding Server_Task is out of its own
784             --  sigwait state.
785
786             Ret_Interrupt :=
787               Interrupt_ID (IMOP.Interrupt_Wait (Intwait_Mask'Access));
788
789             pragma Assert
790               (Ret_Interrupt = Interrupt_ID (IMNG.Abort_Task_Interrupt));
791
792             IMOP.Install_Default_Action (IMNG.Interrupt_ID (Interrupt));
793
794             --  Unmake the Interrupt for this task in order to allow default
795             --  action again.
796
797             IMOP.Thread_Unblock_Interrupt (IMNG.Interrupt_ID (Interrupt));
798
799          else
800             IMOP.Install_Default_Action (IMNG.Interrupt_ID (Interrupt));
801          end if;
802
803       end Unbind_Handler;
804
805       --------------------------------
806       -- Unprotected_Detach_Handler --
807       --------------------------------
808
809       procedure Unprotected_Detach_Handler
810         (Interrupt   : in Interrupt_ID;
811          Static      : in Boolean)
812       is
813          Old_Handler : Parameterless_Handler;
814
815       begin
816          if User_Entry (Interrupt).T /= Null_Task then
817
818             --  In case we have an Interrupt Entry installed.
819             --  raise a program error. (propagate it to the caller).
820
821             Raise_Exception (Program_Error'Identity,
822               "An interrupt entry is already installed");
823          end if;
824
825          --  Note : Static = True will pass the following check. That is the
826          --  case when we want to detach a handler regardless of the static
827          --  status of the current_Handler.
828
829          if not Static and then User_Handler (Interrupt).Static then
830             --  Tries to detach a static Interrupt Handler.
831             --  raise a program error.
832
833             Raise_Exception (Program_Error'Identity,
834               "Trying to detach a static Interrupt Handler");
835          end if;
836
837          --  The interrupt should no longer be ignored if
838          --  it was ever ignored.
839
840          Ignored (Interrupt) := False;
841
842          Old_Handler := User_Handler (Interrupt).H;
843
844          --  The new handler
845
846          User_Handler (Interrupt).H := null;
847          User_Handler (Interrupt).Static := False;
848
849          if Old_Handler /= null then
850             Unbind_Handler (Interrupt);
851          end if;
852
853       end Unprotected_Detach_Handler;
854
855       ----------------------------------
856       -- Unprotected_Exchange_Handler --
857       ----------------------------------
858
859       procedure Unprotected_Exchange_Handler
860         (Old_Handler : out Parameterless_Handler;
861          New_Handler : in  Parameterless_Handler;
862          Interrupt   : in  Interrupt_ID;
863          Static      : in  Boolean;
864          Restoration : in  Boolean := False) is
865       begin
866          if User_Entry (Interrupt).T /= Null_Task then
867             --  In case we have an Interrupt Entry already installed.
868             --  raise a program error. (propagate it to the caller).
869
870             Raise_Exception (Program_Error'Identity,
871               "An interrupt is already installed");
872          end if;
873
874          --  Note : A null handler with Static = True will
875          --  pass the following check. That is the case when we want to
876          --  Detach a handler regardless of the Static status
877          --  of the current_Handler.
878          --  We don't check anything if Restoration is True, since we
879          --  may be detaching a static handler to restore a dynamic one.
880
881          if not Restoration and then not Static
882
883             --  Tries to overwrite a static Interrupt Handler with a
884             --  dynamic Handler
885
886            and then (User_Handler (Interrupt).Static
887
888                         --  The new handler is not specified as an
889                         --  Interrupt Handler by a pragma.
890
891                         or else not Is_Registered (New_Handler))
892          then
893             Raise_Exception (Program_Error'Identity,
894               "Trying to overwrite a static Interrupt Handler with a " &
895               "dynamic Handler");
896          end if;
897
898          --  The interrupt should no longer be ingnored if
899          --  it was ever ignored.
900
901          Ignored (Interrupt) := False;
902
903          --  Save the old handler
904
905          Old_Handler := User_Handler (Interrupt).H;
906
907          --  The new handler
908
909          User_Handler (Interrupt).H := New_Handler;
910
911          if New_Handler = null then
912
913             --  The null handler means we are detaching the handler.
914
915             User_Handler (Interrupt).Static := False;
916
917          else
918             User_Handler (Interrupt).Static := Static;
919          end if;
920
921          --  Invoke a corresponding Server_Task if not yet created.
922          --  Place Task_ID info in Server_ID array.
923
924          if Server_ID (Interrupt) = Null_Task then
925
926             --  When a new Server_Task is created, it should have its
927             --  signal mask set to the All_Tasks_Mask.
928
929             IMOP.Set_Interrupt_Mask
930               (IMOP.All_Tasks_Mask'Access, Old_Mask'Access);
931             Access_Hold := new Server_Task (Interrupt);
932             IMOP.Set_Interrupt_Mask (Old_Mask'Access);
933
934             Server_ID (Interrupt) := To_System (Access_Hold.all'Identity);
935          end if;
936
937          if (New_Handler = null) then
938             if Old_Handler /= null then
939                Unbind_Handler (Interrupt);
940             end if;
941
942             return;
943          end if;
944
945          if Old_Handler = null then
946             Bind_Handler (Interrupt);
947          end if;
948
949       end Unprotected_Exchange_Handler;
950
951    --  Start of processing for Interrupt_Manager
952
953    begin
954       --  By making this task independent of master, when the process
955       --  goes away, the Interrupt_Manager will terminate gracefully.
956
957       System.Tasking.Utilities.Make_Independent;
958
959       --  Environment task gets its own interrupt mask, saves it,
960       --  and then masks all interrupts except the Keep_Unmasked set.
961
962       --  During rendezvous, the Interrupt_Manager receives the old
963       --  interrupt mask of the environment task, and sets its own
964       --  interrupt mask to that value.
965
966       --  The environment task will call the entry of Interrupt_Manager some
967       --  during elaboration of the body of this package.
968
969       accept Initialize (Mask : IMNG.Interrupt_Mask) do
970          declare
971             The_Mask : aliased IMNG.Interrupt_Mask;
972
973          begin
974             IMOP.Copy_Interrupt_Mask (The_Mask, Mask);
975             IMOP.Set_Interrupt_Mask (The_Mask'Access);
976          end;
977       end Initialize;
978
979       --  Note: All tasks in RTS will have all the Reserve Interrupts
980       --  being masked (except the Interrupt_Manager) and Keep_Unmasked
981       --  unmasked when created.
982
983       --  Abort_Task_Interrupt is one of the Interrupt unmasked
984       --  in all tasks. We mask the Interrupt in this particular task
985       --  so that "sigwait" is possible to catch an explicitly sent
986       --  Abort_Task_Interrupt from the Server_Tasks.
987
988       --  This sigwaiting is needed so that we make sure a Server_Task is
989       --  out of its own sigwait state. This extra synchronization is
990       --  necessary to prevent following senarios.
991
992       --   1) Interrupt_Manager sends an Abort_Task_Interrupt to the
993       --      Server_Task then changes its own interrupt mask (OS level).
994       --      If an interrupt (corresponding to the Server_Task) arrives
995       --      in the nean time we have the Interrupt_Manager umnasked and
996       --      the Server_Task waiting on sigwait.
997
998       --   2) For unbinding handler, we install a default action in the
999       --      Interrupt_Manager. POSIX.1c states that the result of using
1000       --      "sigwait" and "sigaction" simaltaneously on the same interrupt
1001       --      is undefined. Therefore, we need to be informed from the
1002       --      Server_Task of the fact that the Server_Task is out of its
1003       --      sigwait stage.
1004
1005       IMOP.Empty_Interrupt_Mask (Intwait_Mask'Access);
1006       IMOP.Add_To_Interrupt_Mask
1007         (Intwait_Mask'Access, IMNG.Abort_Task_Interrupt);
1008       IMOP.Thread_Block_Interrupt
1009         (IMNG.Abort_Task_Interrupt);
1010
1011       loop
1012          --  A block is needed to absorb Program_Error exception
1013
1014          begin
1015             select
1016                accept Attach_Handler
1017                   (New_Handler : in Parameterless_Handler;
1018                    Interrupt   : in Interrupt_ID;
1019                    Static      : in Boolean;
1020                    Restoration : in Boolean := False)
1021                do
1022                   Unprotected_Exchange_Handler
1023                     (Old_Handler, New_Handler, Interrupt, Static, Restoration);
1024                end Attach_Handler;
1025
1026             or
1027                accept Exchange_Handler
1028                   (Old_Handler : out Parameterless_Handler;
1029                    New_Handler : in Parameterless_Handler;
1030                    Interrupt   : in Interrupt_ID;
1031                    Static      : in Boolean)
1032                do
1033                   Unprotected_Exchange_Handler
1034                     (Old_Handler, New_Handler, Interrupt, Static);
1035                end Exchange_Handler;
1036
1037             or
1038                accept Detach_Handler
1039                  (Interrupt   : in Interrupt_ID;
1040                   Static      : in Boolean)
1041                do
1042                   Unprotected_Detach_Handler (Interrupt, Static);
1043                end Detach_Handler;
1044
1045             or
1046                accept Bind_Interrupt_To_Entry
1047                  (T       : Task_ID;
1048                   E       : Task_Entry_Index;
1049                   Interrupt : Interrupt_ID)
1050                do
1051                   --  if there is a binding already (either a procedure or an
1052                   --  entry), raise Program_Error (propagate it to the caller).
1053
1054                   if User_Handler (Interrupt).H /= null
1055                     or else User_Entry (Interrupt).T /= Null_Task
1056                   then
1057                      Raise_Exception (Program_Error'Identity,
1058                        "A binding for this interrupt is already present");
1059                   end if;
1060
1061                   --  The interrupt should no longer be ingnored if
1062                   --  it was ever ignored.
1063
1064                   Ignored (Interrupt) := False;
1065                   User_Entry (Interrupt) := Entry_Assoc' (T => T, E => E);
1066
1067                   --  Indicate the attachment of Interrupt Entry in ATCB.
1068                   --  This is need so that when an Interrupt Entry task
1069                   --  terminates the binding can be cleaned. The call to
1070                   --  unbinding must be made by the task before it terminates.
1071
1072                   T.Interrupt_Entry := True;
1073
1074                   --  Invoke a corresponding Server_Task if not yet created.
1075                   --  Place Task_ID info in Server_ID array.
1076
1077                   if Server_ID (Interrupt) = Null_Task then
1078                      --  When a new Server_Task is created, it should have its
1079                      --  signal mask set to the All_Tasks_Mask.
1080
1081                      IMOP.Set_Interrupt_Mask
1082                        (IMOP.All_Tasks_Mask'Access, Old_Mask'Access);
1083                      Access_Hold := new Server_Task (Interrupt);
1084                      IMOP.Set_Interrupt_Mask (Old_Mask'Access);
1085                      Server_ID (Interrupt) :=
1086                        To_System (Access_Hold.all'Identity);
1087                   end if;
1088
1089                   Bind_Handler (Interrupt);
1090                end Bind_Interrupt_To_Entry;
1091
1092             or
1093                accept Detach_Interrupt_Entries (T : Task_ID) do
1094                   for J in Interrupt_ID'Range loop
1095                      if not Is_Reserved (J) then
1096                         if User_Entry (J).T = T then
1097                            --  The interrupt should no longer be ingnored if
1098                            --  it was ever ignored.
1099
1100                            Ignored (J) := False;
1101                            User_Entry (J) := Entry_Assoc'
1102                              (T => Null_Task, E => Null_Task_Entry);
1103                            Unbind_Handler (J);
1104                         end if;
1105                      end if;
1106                   end loop;
1107
1108                   --  Indicate in ATCB that no Interrupt Entries are attached.
1109
1110                   T.Interrupt_Entry := False;
1111                end Detach_Interrupt_Entries;
1112
1113             or
1114                accept Block_Interrupt (Interrupt : Interrupt_ID) do
1115                   if Blocked (Interrupt) then
1116                      return;
1117                   end if;
1118
1119                   Blocked (Interrupt) := True;
1120                   Last_Unblocker (Interrupt) := Null_Task;
1121
1122                   --  Mask this task for the given Interrupt so that all tasks
1123                   --  are masked for the Interrupt.
1124
1125                   IMOP.Thread_Block_Interrupt (IMNG.Interrupt_ID (Interrupt));
1126
1127                   if User_Handler (Interrupt).H /= null
1128                     or else  User_Entry (Interrupt).T /= Null_Task
1129                   then
1130                      --  This is the case where the Server_Task is waiting on
1131                      --  "sigwait." Wake it up by sending an
1132                      --  Abort_Task_Interrupt so that the Server_Task waits on
1133                      --  Cond.
1134
1135                      POP.Abort_Task (Server_ID (Interrupt));
1136
1137                      --  Make sure corresponding Server_Task is out of its own
1138                      --  sigwait state.
1139
1140                      Ret_Interrupt := Interrupt_ID
1141                        (IMOP.Interrupt_Wait (Intwait_Mask'Access));
1142                      pragma Assert
1143                        (Ret_Interrupt =
1144                         Interrupt_ID (IMNG.Abort_Task_Interrupt));
1145                   end if;
1146                end Block_Interrupt;
1147
1148             or
1149                accept Unblock_Interrupt (Interrupt : Interrupt_ID) do
1150                   if not Blocked (Interrupt) then
1151                      return;
1152                   end if;
1153
1154                   Blocked (Interrupt) := False;
1155                   Last_Unblocker (Interrupt) :=
1156                     To_System (Unblock_Interrupt'Caller);
1157
1158                   if User_Handler (Interrupt).H = null
1159                     and then User_Entry (Interrupt).T = Null_Task
1160                   then
1161                      --  No handler is attached. Unmask the Interrupt so that
1162                      --  the default action can be carried out.
1163                      IMOP.Thread_Unblock_Interrupt
1164                        (IMNG.Interrupt_ID (Interrupt));
1165
1166                   else
1167                      --  The Server_Task must be waiting on the Cond variable
1168                      --  since it was being blocked and an Interrupt Hander or
1169                      --  an Entry was there. Wake it up and let it change
1170                      --  it place of waiting according to its new state.
1171                      POP.Wakeup (Server_ID (Interrupt),
1172                        Interrupt_Server_Blocked_Interrupt_Sleep);
1173                   end if;
1174                end Unblock_Interrupt;
1175
1176             or
1177                accept Ignore_Interrupt (Interrupt : Interrupt_ID) do
1178                   if Ignored (Interrupt) then
1179                      return;
1180                   end if;
1181
1182                   Ignored (Interrupt) := True;
1183
1184                   --  If there is a handler associated with the Interrupt,
1185                   --  detach it first. In this way we make sure that the
1186                   --  Server_Task is not on sigwait. This is legal since
1187                   --  Unignore_Interrupt is to install the default action.
1188
1189                   if User_Handler (Interrupt).H /= null then
1190                      Unprotected_Detach_Handler
1191                        (Interrupt => Interrupt, Static => True);
1192
1193                   elsif User_Entry (Interrupt).T /= Null_Task then
1194                      User_Entry (Interrupt) := Entry_Assoc'
1195                        (T => Null_Task, E => Null_Task_Entry);
1196                      Unbind_Handler (Interrupt);
1197                   end if;
1198
1199                   IMOP.Install_Ignore_Action (IMNG.Interrupt_ID (Interrupt));
1200                end Ignore_Interrupt;
1201
1202             or
1203                accept Unignore_Interrupt (Interrupt : Interrupt_ID) do
1204                   Ignored (Interrupt) := False;
1205
1206                   --  If there is a handler associated with the Interrupt,
1207                   --  detach it first. In this way we make sure that the
1208                   --  Server_Task is not on sigwait. This is legal since
1209                   --  Unignore_Interrupt is to install the default action.
1210
1211                   if User_Handler (Interrupt).H /= null then
1212                      Unprotected_Detach_Handler
1213                        (Interrupt => Interrupt, Static => True);
1214
1215                   elsif User_Entry (Interrupt).T /= Null_Task then
1216                      User_Entry (Interrupt) := Entry_Assoc'
1217                        (T => Null_Task, E => Null_Task_Entry);
1218                      Unbind_Handler (Interrupt);
1219                   end if;
1220
1221                   IMOP.Install_Default_Action (IMNG.Interrupt_ID (Interrupt));
1222                end Unignore_Interrupt;
1223             end select;
1224
1225          exception
1226             --  If there is a program error we just want to propagate it to
1227             --  the caller and do not want to stop this task.
1228
1229             when Program_Error =>
1230                null;
1231
1232             when others =>
1233                pragma Assert (False);
1234                null;
1235          end;
1236       end loop;
1237    end Interrupt_Manager;
1238
1239    -----------------
1240    -- Server_Task --
1241    -----------------
1242
1243    task body Server_Task is
1244       Intwait_Mask    : aliased IMNG.Interrupt_Mask;
1245       Ret_Interrupt   : Interrupt_ID;
1246       Self_ID         : Task_ID := Self;
1247       Tmp_Handler     : Parameterless_Handler;
1248       Tmp_ID          : Task_ID;
1249       Tmp_Entry_Index : Task_Entry_Index;
1250
1251    begin
1252       --  By making this task independent of master, when the process
1253       --  goes away, the Server_Task will terminate gracefully.
1254
1255       System.Tasking.Utilities.Make_Independent;
1256
1257       --  Install default action in system level.
1258
1259       IMOP.Install_Default_Action (IMNG.Interrupt_ID (Interrupt));
1260
1261       --  Note: All tasks in RTS will have all the Reserve Interrupts
1262       --  being masked (except the Interrupt_Manager) and Keep_Unmasked
1263       --  unmasked when created.
1264
1265       --  Abort_Task_Interrupt is one of the Interrupt unmasked
1266       --  in all tasks. We mask the Interrupt in this particular task
1267       --  so that "sigwait" is possible to catch an explicitly sent
1268       --  Abort_Task_Interrupt from the Interrupt_Manager.
1269
1270       --  There are two Interrupt interrupts that this task catch through
1271       --  "sigwait." One is the Interrupt this task is designated to catch
1272       --  in order to execure user handler or entry. The other one is the
1273       --  Abort_Task_Interrupt. This interrupt is being sent from the
1274       --  Interrupt_Manager to inform status changes (e.g: become Blocked,
1275       --  Handler or Entry is to be detached).
1276
1277       --  Prepare a mask to used for sigwait.
1278
1279       IMOP.Empty_Interrupt_Mask (Intwait_Mask'Access);
1280
1281       IMOP.Add_To_Interrupt_Mask
1282         (Intwait_Mask'Access, IMNG.Interrupt_ID (Interrupt));
1283
1284       IMOP.Add_To_Interrupt_Mask
1285         (Intwait_Mask'Access, IMNG.Abort_Task_Interrupt);
1286
1287       IMOP.Thread_Block_Interrupt
1288         (IMNG.Abort_Task_Interrupt);
1289
1290       PIO.Set_Interrupt_ID (IMNG.Interrupt_ID (Interrupt), Self_ID);
1291
1292       loop
1293          System.Tasking.Initialization.Defer_Abort (Self_ID);
1294
1295          if Single_Lock then
1296             POP.Lock_RTS;
1297          end if;
1298
1299          POP.Write_Lock (Self_ID);
1300
1301          if User_Handler (Interrupt).H = null
1302            and then User_Entry (Interrupt).T = Null_Task
1303          then
1304             --  No Interrupt binding. If there is an interrupt,
1305             --  Interrupt_Manager will take default action.
1306
1307             Self_ID.Common.State := Interrupt_Server_Blocked_Interrupt_Sleep;
1308             POP.Sleep (Self_ID, Interrupt_Server_Idle_Sleep);
1309             Self_ID.Common.State := Runnable;
1310
1311          elsif Blocked (Interrupt) then
1312
1313             --  Interrupt is blocked. Stay here, so we won't catch
1314             --  the Interrupt.
1315
1316             Self_ID.Common.State := Interrupt_Server_Blocked_Interrupt_Sleep;
1317             POP.Sleep (Self_ID, Interrupt_Server_Blocked_Interrupt_Sleep);
1318             Self_ID.Common.State := Runnable;
1319
1320          else
1321             --  A Handler or an Entry is installed. At this point all tasks
1322             --  mask for the Interrupt is masked. Catch the Interrupt using
1323             --  sigwait.
1324
1325             --  This task may wake up from sigwait by receiving an interrupt
1326             --  (Abort_Task_Interrupt) from the Interrupt_Manager for unbinding
1327             --  a Procedure Handler or an Entry. Or it could be a wake up
1328             --  from status change (Unblocked -> Blocked). If that is not
1329             --  the case, we should exceute the attached Procedure or Entry.
1330
1331             POP.Unlock (Self_ID);
1332
1333             if Single_Lock then
1334                POP.Unlock_RTS;
1335             end if;
1336
1337             Ret_Interrupt :=
1338               Interrupt_ID (IMOP.Interrupt_Wait (Intwait_Mask'Access));
1339
1340             if Ret_Interrupt = Interrupt_ID (IMNG.Abort_Task_Interrupt) then
1341
1342                --  Inform the Interrupt_Manager of wakeup from above sigwait.
1343
1344                POP.Abort_Task (Interrupt_Manager_ID);
1345
1346                if Single_Lock then
1347                   POP.Lock_RTS;
1348                end if;
1349
1350                POP.Write_Lock (Self_ID);
1351
1352             else
1353                pragma Assert (Ret_Interrupt = Interrupt);
1354
1355                if Single_Lock then
1356                   POP.Lock_RTS;
1357                end if;
1358
1359                POP.Write_Lock (Self_ID);
1360
1361                --  Even though we have received an Interrupt the status may
1362                --  have changed already before we got the Self_ID lock above.
1363                --  Therefore we make sure a Handler or an Entry is still
1364                --  there and make appropriate call.
1365                --  If there is no calls to make we need to regenerate the
1366                --  Interrupt in order not to lose it.
1367
1368                if User_Handler (Interrupt).H /= null then
1369                   Tmp_Handler := User_Handler (Interrupt).H;
1370
1371                   --  RTS calls should not be made with self being locked.
1372
1373                   POP.Unlock (Self_ID);
1374
1375                   if Single_Lock then
1376                      POP.Unlock_RTS;
1377                   end if;
1378
1379                   Tmp_Handler.all;
1380
1381                   if Single_Lock then
1382                      POP.Lock_RTS;
1383                   end if;
1384
1385                   POP.Write_Lock (Self_ID);
1386
1387                elsif User_Entry (Interrupt).T /= Null_Task then
1388                   Tmp_ID := User_Entry (Interrupt).T;
1389                   Tmp_Entry_Index := User_Entry (Interrupt).E;
1390
1391                   --  RTS calls should not be made with self being locked.
1392
1393                   if Single_Lock then
1394                      POP.Unlock_RTS;
1395                   end if;
1396
1397                   POP.Unlock (Self_ID);
1398
1399                   System.Tasking.Rendezvous.Call_Simple
1400                     (Tmp_ID, Tmp_Entry_Index, System.Null_Address);
1401
1402                   POP.Write_Lock (Self_ID);
1403
1404                   if Single_Lock then
1405                      POP.Lock_RTS;
1406                   end if;
1407
1408                else
1409                   --  This is a situation that this task wake up
1410                   --  receiving an Interrupt and before it get the lock
1411                   --  the Interrupt is blocked. We do not
1412                   --  want to lose the interrupt in this case so that
1413                   --  regenerate the Interrupt to process level;
1414
1415                   IMOP.Interrupt_Self_Process (IMNG.Interrupt_ID (Interrupt));
1416                end if;
1417             end if;
1418          end if;
1419
1420          POP.Unlock (Self_ID);
1421
1422          if Single_Lock then
1423             POP.Unlock_RTS;
1424          end if;
1425
1426          System.Tasking.Initialization.Undefer_Abort (Self_ID);
1427
1428          --  Undefer abort here to allow a window for this task
1429          --  to be aborted  at the time of system shutdown.
1430       end loop;
1431    end Server_Task;
1432
1433 --  Elaboration code for package System.Interrupts
1434
1435 begin
1436
1437    --  Get Interrupt_Manager's ID so that Abort_Interrupt can be sent.
1438
1439    Interrupt_Manager_ID := To_System (Interrupt_Manager'Identity);
1440
1441    --  During the elaboration of this package body we want RTS to
1442    --  inherit the interrupt mask from the Environment Task.
1443
1444    --  The Environment Task should have gotten its mask from
1445    --  the enclosing process during the RTS start up. (See
1446    --  in s-inmaop.adb). Pass the Interrupt_Mask of the Environment
1447    --  task to the Interrupt_Manager.
1448
1449    --  Note : At this point we know that all tasks (including
1450    --  RTS internal servers) are masked for non-reserved signals
1451    --  (see s-taprop.adb). Only the Interrupt_Manager will have
1452    --  masks set up differently inheriting the original Environment
1453    --  Task's mask.
1454
1455    Interrupt_Manager.Initialize (IMOP.Environment_Mask);
1456 end System.Interrupts;