OSDN Git Service

2004-10-04 Jose Ruiz <ruiz@act-europe.fr>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-tposen.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --               GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS                --
4 --                                                                          --
5 --              SYSTEM.TASKING.PROTECTED_OBJECTS.SINGLE_ENTRY               --
6 --                                                                          --
7 --                                  B o d y                                 --
8 --                                                                          --
9 --         Copyright (C) 1998-2004, Free Software Foundation, Inc.          --
10 --                                                                          --
11 -- GNARL is free software; you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNARL; see file COPYING.  If not, write --
19 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
20 -- MA 02111-1307, USA.                                                      --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- GNARL was developed by the GNARL team at Florida State University.       --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc.     --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 pragma Style_Checks (All_Checks);
35 --  Turn off subprogram ordering check, since restricted GNARLI
36 --  subprograms are gathered together at end.
37
38 --  This package provides an optimized version of Protected_Objects.Operations
39 --  and Protected_Objects.Entries making the following assumptions:
40 --
41 --  PO have only one entry
42 --  There is only one caller at a time (No_Entry_Queue)
43 --  There is no dynamic priority support (No_Dynamic_Priorities)
44 --  No Abort Statements
45 --    (No_Abort_Statements, Max_Asynchronous_Select_Nesting => 0)
46 --  PO are at library level
47 --  No Requeue
48 --  None of the tasks will terminate (no need for finalization)
49 --
50 --  This interface is intended to be used in the ravenscar and restricted
51 --  profiles, the compiler is responsible for ensuring that the conditions
52 --  mentioned above are respected, except for the No_Entry_Queue restriction
53 --  that is checked dynamically in this package, since the check cannot be
54 --  performed at compile time, and is relatively cheap (see PO_Do_Or_Queue,
55 --  Service_Entry).
56
57 pragma Polling (Off);
58 --  Turn off polling, we do not want polling to take place during tasking
59 --  operations. It can cause  infinite loops and other problems.
60
61 pragma Suppress (All_Checks);
62
63 with System.Task_Primitives.Operations;
64 --  used for Self
65 --           Finalize_Lock
66 --           Write_Lock
67 --           Unlock
68
69 with Ada.Exceptions;
70 --  used for Exception_Id
71 --           Raise_Exception
72
73 with System.Parameters;
74 --  used for Single_Lock
75
76 package body System.Tasking.Protected_Objects.Single_Entry is
77
78    package STPO renames System.Task_Primitives.Operations;
79
80    use Parameters;
81
82    -----------------------
83    -- Local Subprograms --
84    -----------------------
85
86    procedure Send_Program_Error
87      (Self_Id    : Task_Id;
88       Entry_Call : Entry_Call_Link);
89    pragma Inline (Send_Program_Error);
90    --  Raise Program_Error in the caller of the specified entry call
91
92    --------------------------
93    -- Entry Calls Handling --
94    --------------------------
95
96    procedure Wakeup_Entry_Caller
97      (Self_ID    : Task_Id;
98       Entry_Call : Entry_Call_Link;
99       New_State  : Entry_Call_State);
100    pragma Inline (Wakeup_Entry_Caller);
101    --  This is called at the end of service of an entry call,
102    --  to abort the caller if he is in an abortable part, and
103    --  to wake up the caller if he is on Entry_Caller_Sleep.
104    --  Call it holding the lock of Entry_Call.Self.
105    --
106    --  Timed_Call or Simple_Call:
107    --    The caller is waiting on Entry_Caller_Sleep, in
108    --    Wait_For_Completion, or Wait_For_Completion_With_Timeout.
109
110    procedure Wait_For_Completion (Entry_Call : Entry_Call_Link);
111    pragma Inline (Wait_For_Completion);
112    --  This procedure suspends the calling task until the specified entry call
113    --  has either been completed or cancelled. On exit, the call will not be
114    --  queued. This waits for calls on protected entries.
115    --  Call this only when holding Self_ID locked.
116
117    procedure Wait_For_Completion_With_Timeout
118      (Entry_Call  : Entry_Call_Link;
119       Wakeup_Time : Duration;
120       Mode        : Delay_Modes);
121    --  Same as Wait_For_Completion but it waits for a timeout with the value
122    --  specified in Wakeup_Time as well.
123
124    procedure Check_Exception
125      (Self_ID : Task_Id;
126       Entry_Call : Entry_Call_Link);
127    pragma Inline (Check_Exception);
128    --  Raise any pending exception from the Entry_Call.
129    --  This should be called at the end of every compiler interface procedure
130    --  that implements an entry call.
131    --  The caller should not be holding any locks, or there will be deadlock.
132
133    procedure PO_Do_Or_Queue
134      (Self_Id    : Task_Id;
135       Object     : Protection_Entry_Access;
136       Entry_Call : Entry_Call_Link);
137    --  This procedure executes or queues an entry call, depending
138    --  on the status of the corresponding barrier. It assumes that the
139    --  specified object is locked.
140
141    ---------------------
142    -- Check_Exception --
143    ---------------------
144
145    procedure Check_Exception
146      (Self_ID    : Task_Id;
147       Entry_Call : Entry_Call_Link)
148    is
149       pragma Warnings (Off, Self_ID);
150
151       procedure Internal_Raise (X : Ada.Exceptions.Exception_Id);
152       pragma Import (C, Internal_Raise, "__gnat_raise_with_msg");
153
154       use type Ada.Exceptions.Exception_Id;
155
156       E : constant Ada.Exceptions.Exception_Id :=
157         Entry_Call.Exception_To_Raise;
158
159    begin
160       if E /= Ada.Exceptions.Null_Id then
161          Internal_Raise (E);
162       end if;
163    end Check_Exception;
164
165    ------------------------
166    -- Send_Program_Error --
167    ------------------------
168
169    procedure Send_Program_Error
170      (Self_Id    : Task_Id;
171       Entry_Call : Entry_Call_Link)
172    is
173       Caller : constant Task_Id := Entry_Call.Self;
174    begin
175       Entry_Call.Exception_To_Raise := Program_Error'Identity;
176
177       if Single_Lock then
178          STPO.Lock_RTS;
179       end if;
180
181       STPO.Write_Lock (Caller);
182       Wakeup_Entry_Caller (Self_Id, Entry_Call, Done);
183       STPO.Unlock (Caller);
184
185       if Single_Lock then
186          STPO.Unlock_RTS;
187       end if;
188    end Send_Program_Error;
189
190    -------------------------
191    -- Wait_For_Completion --
192    -------------------------
193
194    procedure Wait_For_Completion (Entry_Call : Entry_Call_Link) is
195       Self_Id : constant Task_Id := Entry_Call.Self;
196    begin
197       Self_Id.Common.State := Entry_Caller_Sleep;
198       STPO.Sleep (Self_Id, Entry_Caller_Sleep);
199       Self_Id.Common.State := Runnable;
200    end Wait_For_Completion;
201
202    --------------------------------------
203    -- Wait_For_Completion_With_Timeout --
204    --------------------------------------
205
206    procedure Wait_For_Completion_With_Timeout
207      (Entry_Call  : Entry_Call_Link;
208       Wakeup_Time : Duration;
209       Mode        : Delay_Modes)
210    is
211       Self_Id  : constant Task_Id := Entry_Call.Self;
212       Timedout : Boolean;
213       Yielded  : Boolean;
214
215       use type Ada.Exceptions.Exception_Id;
216
217    begin
218       --  This procedure waits for the entry call to be served, with a timeout.
219       --  It tries to cancel the call if the timeout expires before the call is
220       --  served.
221
222       --  If we wake up from the timed sleep operation here, it may be for the
223       --  following possible reasons:
224
225       --  1) The entry call is done being served.
226       --  2) The timeout has expired (Timedout = True)
227
228       --  Once the timeout has expired we may need to continue to wait if the
229       --  call is already being serviced. In that case, we want to go back to
230       --  sleep, but without any timeout. The variable Timedout is used to
231       --  control this. If the Timedout flag is set, we do not need to Sleep
232       --  with a timeout. We just sleep until we get a wakeup for some status
233       --  change.
234
235       pragma Assert (Entry_Call.Mode = Timed_Call);
236       Self_Id.Common.State := Entry_Caller_Sleep;
237
238       STPO.Timed_Sleep
239         (Self_Id, Wakeup_Time, Mode, Entry_Caller_Sleep, Timedout, Yielded);
240
241       if Timedout then
242          Entry_Call.State := Cancelled;
243       else
244          Entry_Call.State := Done;
245       end if;
246
247       Self_Id.Common.State := Runnable;
248    end Wait_For_Completion_With_Timeout;
249
250    -------------------------
251    -- Wakeup_Entry_Caller --
252    -------------------------
253
254    --  This is called at the end of service of an entry call, to abort the
255    --  caller if he is in an abortable part, and to wake up the caller if it
256    --  is on Entry_Caller_Sleep. It assumes that the call is already off-queue.
257
258    --  (This enforces the rule that a task must be off-queue if its state is
259    --  Done or Cancelled.) Call it holding the lock of Entry_Call.Self.
260
261    --  Timed_Call or Simple_Call:
262    --    The caller is waiting on Entry_Caller_Sleep, in
263    --    Wait_For_Completion, or Wait_For_Completion_With_Timeout.
264
265    --  Conditional_Call:
266    --    The caller might be in Wait_For_Completion,
267    --    waiting for a rendezvous (possibly requeued without abort)
268    --    to complete.
269
270    procedure Wakeup_Entry_Caller
271      (Self_ID    : Task_Id;
272       Entry_Call : Entry_Call_Link;
273       New_State  : Entry_Call_State)
274    is
275       pragma Warnings (Off, Self_ID);
276
277       Caller : constant Task_Id := Entry_Call.Self;
278
279    begin
280       pragma Assert (New_State = Done or else New_State = Cancelled);
281       pragma Assert
282         (Caller.Common.State /= Terminated and then
283          Caller.Common.State /= Unactivated);
284
285       Entry_Call.State := New_State;
286       STPO.Wakeup (Caller, Entry_Caller_Sleep);
287    end Wakeup_Entry_Caller;
288
289    -----------------------
290    -- Restricted GNARLI --
291    -----------------------
292
293    --------------------------------
294    -- Complete_Single_Entry_Body --
295    --------------------------------
296
297    procedure Complete_Single_Entry_Body (Object : Protection_Entry_Access) is
298       pragma Warnings (Off, Object);
299
300    begin
301       --  Nothing needs to do (Object.Call_In_Progress.Exception_To_Raise
302       --  has already been set to Null_Id).
303
304       null;
305    end Complete_Single_Entry_Body;
306
307    --------------------------------------------
308    -- Exceptional_Complete_Single_Entry_Body --
309    --------------------------------------------
310
311    procedure Exceptional_Complete_Single_Entry_Body
312      (Object : Protection_Entry_Access;
313       Ex     : Ada.Exceptions.Exception_Id) is
314    begin
315       Object.Call_In_Progress.Exception_To_Raise := Ex;
316    end Exceptional_Complete_Single_Entry_Body;
317
318    ---------------------------------
319    -- Initialize_Protection_Entry --
320    ---------------------------------
321
322    procedure Initialize_Protection_Entry
323      (Object            : Protection_Entry_Access;
324       Ceiling_Priority  : Integer;
325       Compiler_Info     : System.Address;
326       Entry_Body        : Entry_Body_Access)
327    is
328       Init_Priority : Integer := Ceiling_Priority;
329    begin
330       if Init_Priority = Unspecified_Priority then
331          Init_Priority := System.Priority'Last;
332       end if;
333
334       STPO.Initialize_Lock (Init_Priority, Object.L'Access);
335       Object.Ceiling := System.Any_Priority (Init_Priority);
336       Object.Compiler_Info := Compiler_Info;
337       Object.Call_In_Progress := null;
338       Object.Entry_Body := Entry_Body;
339       Object.Entry_Queue := null;
340    end Initialize_Protection_Entry;
341
342    ----------------
343    -- Lock_Entry --
344    ----------------
345
346    --  Compiler interface only.
347    --  Do not call this procedure from within the run-time system.
348
349    procedure Lock_Entry (Object : Protection_Entry_Access) is
350       Ceiling_Violation : Boolean;
351
352    begin
353       --  If pragma Detect_Blocking is active then Program_Error must
354       --  be raised if this potentially blocking operation is called from
355       --  a protected action, and the protected object nesting level
356       --  must be increased.
357
358       if Detect_Blocking then
359          declare
360             Self_Id : constant Task_Id := STPO.Self;
361          begin
362             if Self_Id.Common.Protected_Action_Nesting > 0  then
363                Ada.Exceptions.Raise_Exception
364                  (Program_Error'Identity, "potentially blocking operation");
365             else
366                --  We are entering in a protected action, so that we
367                --  increase the protected object nesting level.
368
369                Self_Id.Common.Protected_Action_Nesting :=
370                  Self_Id.Common.Protected_Action_Nesting + 1;
371             end if;
372          end;
373       end if;
374
375       STPO.Write_Lock (Object.L'Access, Ceiling_Violation);
376
377       if Ceiling_Violation then
378          raise Program_Error;
379       end if;
380    end Lock_Entry;
381
382    --------------------------
383    -- Lock_Read_Only_Entry --
384    --------------------------
385
386    --  Compiler interface only.
387    --  Do not call this procedure from within the runtime system.
388
389    procedure Lock_Read_Only_Entry (Object : Protection_Entry_Access) is
390       Ceiling_Violation : Boolean;
391
392    begin
393       --  If pragma Detect_Blocking is active then Program_Error must be
394       --  raised if this potentially blocking operation is called from a
395       --  protected action, and the protected object nesting level must
396       --  be increased.
397
398       if Detect_Blocking then
399          declare
400             Self_Id : constant Task_Id := STPO.Self;
401          begin
402             if Self_Id.Common.Protected_Action_Nesting > 0  then
403                Ada.Exceptions.Raise_Exception
404                  (Program_Error'Identity, "potentially blocking operation");
405             else
406                --  We are entering in a protected action, so that we
407                --  increase the protected object nesting level.
408
409                Self_Id.Common.Protected_Action_Nesting :=
410                  Self_Id.Common.Protected_Action_Nesting + 1;
411             end if;
412          end;
413       end if;
414
415       STPO.Read_Lock (Object.L'Access, Ceiling_Violation);
416
417       if Ceiling_Violation then
418          raise Program_Error;
419       end if;
420    end Lock_Read_Only_Entry;
421
422    --------------------
423    -- PO_Do_Or_Queue --
424    --------------------
425
426    procedure PO_Do_Or_Queue
427      (Self_Id    : Task_Id;
428       Object     : Protection_Entry_Access;
429       Entry_Call : Entry_Call_Link)
430    is
431       Barrier_Value : Boolean;
432    begin
433       --  When the Action procedure for an entry body returns, it must be
434       --  completed (having called [Exceptional_]Complete_Entry_Body).
435
436       Barrier_Value := Object.Entry_Body.Barrier (Object.Compiler_Info, 1);
437
438       if Barrier_Value then
439          if Object.Call_In_Progress /= null then
440             --  This violates the No_Entry_Queue restriction, send
441             --  Program_Error to the caller.
442
443             Send_Program_Error (Self_Id, Entry_Call);
444             return;
445          end if;
446
447          Object.Call_In_Progress := Entry_Call;
448          Object.Entry_Body.Action
449            (Object.Compiler_Info, Entry_Call.Uninterpreted_Data, 1);
450          Object.Call_In_Progress := null;
451
452          if Single_Lock then
453             STPO.Lock_RTS;
454          end if;
455
456          STPO.Write_Lock (Entry_Call.Self);
457          Wakeup_Entry_Caller (Self_Id, Entry_Call, Done);
458          STPO.Unlock (Entry_Call.Self);
459
460          if Single_Lock then
461             STPO.Unlock_RTS;
462          end if;
463
464       elsif Entry_Call.Mode /= Conditional_Call then
465          Object.Entry_Queue := Entry_Call;
466       else
467          --  Conditional_Call
468
469          if Single_Lock then
470             STPO.Lock_RTS;
471          end if;
472
473          STPO.Write_Lock (Entry_Call.Self);
474          Wakeup_Entry_Caller (Self_Id, Entry_Call, Cancelled);
475          STPO.Unlock (Entry_Call.Self);
476
477          if Single_Lock then
478             STPO.Unlock_RTS;
479          end if;
480       end if;
481
482    exception
483       when others =>
484          Send_Program_Error
485            (Self_Id, Entry_Call);
486    end PO_Do_Or_Queue;
487
488    ----------------------------
489    -- Protected_Single_Count --
490    ----------------------------
491
492    function Protected_Count_Entry (Object : Protection_Entry) return Natural is
493    begin
494       if Object.Entry_Queue /= null then
495          return 1;
496       else
497          return 0;
498       end if;
499    end Protected_Count_Entry;
500
501    ---------------------------------
502    -- Protected_Single_Entry_Call --
503    ---------------------------------
504
505    procedure Protected_Single_Entry_Call
506      (Object             : Protection_Entry_Access;
507       Uninterpreted_Data : System.Address;
508       Mode               : Call_Modes)
509    is
510       Self_Id           : constant Task_Id := STPO.Self;
511       Entry_Call        : Entry_Call_Record renames Self_Id.Entry_Calls (1);
512       Ceiling_Violation : Boolean;
513
514    begin
515       --  If pragma Detect_Blocking is active then Program_Error must be
516       --  raised if this potentially blocking operation is called from a
517       --  protected action.
518
519       if Detect_Blocking
520         and then Self_Id.Common.Protected_Action_Nesting > 0
521       then
522          Ada.Exceptions.Raise_Exception
523            (Program_Error'Identity, "potentially blocking operation");
524       end if;
525
526       STPO.Write_Lock (Object.L'Access, Ceiling_Violation);
527
528       if Ceiling_Violation then
529          raise Program_Error;
530       end if;
531
532       Entry_Call.Mode := Mode;
533       Entry_Call.State := Now_Abortable;
534       Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
535       Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;
536
537       PO_Do_Or_Queue (Self_Id, Object, Entry_Call'Access);
538       Unlock_Entry (Object);
539
540       --  The call is either `Done' or not. It cannot be cancelled since there
541       --  is no ATC construct.
542
543       pragma Assert (Entry_Call.State /= Cancelled);
544
545       if Entry_Call.State /= Done then
546          if Single_Lock then
547             STPO.Lock_RTS;
548          end if;
549
550          STPO.Write_Lock (Self_Id);
551          Wait_For_Completion (Entry_Call'Access);
552          STPO.Unlock (Self_Id);
553
554          if Single_Lock then
555             STPO.Unlock_RTS;
556          end if;
557       end if;
558
559       Check_Exception (Self_Id, Entry_Call'Access);
560    end Protected_Single_Entry_Call;
561
562    -----------------------------------
563    -- Protected_Single_Entry_Caller --
564    -----------------------------------
565
566    function Protected_Single_Entry_Caller
567      (Object : Protection_Entry) return Task_Id is
568    begin
569       return Object.Call_In_Progress.Self;
570    end Protected_Single_Entry_Caller;
571
572    -------------------
573    -- Service_Entry --
574    -------------------
575
576    procedure Service_Entry (Object : Protection_Entry_Access) is
577       Self_Id    : constant Task_Id := STPO.Self;
578       Entry_Call : constant Entry_Call_Link := Object.Entry_Queue;
579       Caller     : Task_Id;
580
581    begin
582       if Entry_Call /= null
583         and then Object.Entry_Body.Barrier (Object.Compiler_Info, 1)
584       then
585          Object.Entry_Queue := null;
586
587          if Object.Call_In_Progress /= null then
588
589             --  Violation of No_Entry_Queue restriction, raise exception
590
591             Send_Program_Error (Self_Id, Entry_Call);
592             Unlock_Entry (Object);
593             return;
594          end if;
595
596          Object.Call_In_Progress := Entry_Call;
597          Object.Entry_Body.Action
598            (Object.Compiler_Info, Entry_Call.Uninterpreted_Data, 1);
599          Object.Call_In_Progress := null;
600          Caller := Entry_Call.Self;
601          Unlock_Entry (Object);
602
603          if Single_Lock then
604             STPO.Lock_RTS;
605          end if;
606
607          STPO.Write_Lock (Caller);
608          Wakeup_Entry_Caller (Self_Id, Entry_Call, Done);
609          STPO.Unlock (Caller);
610
611          if Single_Lock then
612             STPO.Unlock_RTS;
613          end if;
614
615       else
616          --  Just unlock the entry
617
618          Unlock_Entry (Object);
619       end if;
620
621    exception
622       when others =>
623          Send_Program_Error (Self_Id, Entry_Call);
624          Unlock_Entry (Object);
625    end Service_Entry;
626
627    ---------------------------------------
628    -- Timed_Protected_Single_Entry_Call --
629    ---------------------------------------
630
631    --  Compiler interface only. Do not call from within the RTS.
632
633    procedure Timed_Protected_Single_Entry_Call
634      (Object                : Protection_Entry_Access;
635       Uninterpreted_Data    : System.Address;
636       Timeout               : Duration;
637       Mode                  : Delay_Modes;
638       Entry_Call_Successful : out Boolean)
639    is
640       Self_Id           : constant Task_Id  := STPO.Self;
641       Entry_Call        : Entry_Call_Record renames Self_Id.Entry_Calls (1);
642       Ceiling_Violation : Boolean;
643
644    begin
645       --  If pragma Detect_Blocking is active then Program_Error must be
646       --  raised if this potentially blocking operation is called from a
647       --  protected action.
648
649       if Detect_Blocking
650         and then Self_Id.Common.Protected_Action_Nesting > 0
651       then
652          Ada.Exceptions.Raise_Exception
653            (Program_Error'Identity, "potentially blocking operation");
654       end if;
655
656       STPO.Write_Lock (Object.L'Access, Ceiling_Violation);
657
658       if Ceiling_Violation then
659          raise Program_Error;
660       end if;
661
662       Entry_Call.Mode := Timed_Call;
663       Entry_Call.State := Now_Abortable;
664       Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
665       Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;
666
667       PO_Do_Or_Queue (Self_Id, Object, Entry_Call'Access);
668       Unlock_Entry (Object);
669
670       --  Try to avoid waiting for completed calls.
671       --  The call is either `Done' or not. It cannot be cancelled since there
672       --  is no ATC construct and the timed wait has not started yet.
673
674       pragma Assert (Entry_Call.State /= Cancelled);
675
676       if Entry_Call.State = Done then
677          Check_Exception (Self_Id, Entry_Call'Access);
678          Entry_Call_Successful := True;
679          return;
680       end if;
681
682       if Single_Lock then
683          STPO.Lock_RTS;
684       else
685          STPO.Write_Lock (Self_Id);
686       end if;
687
688       Wait_For_Completion_With_Timeout (Entry_Call'Access, Timeout, Mode);
689
690       if Single_Lock then
691          STPO.Unlock_RTS;
692       else
693          STPO.Unlock (Self_Id);
694       end if;
695
696       pragma Assert (Entry_Call.State >= Done);
697
698       Check_Exception (Self_Id, Entry_Call'Access);
699       Entry_Call_Successful := Entry_Call.State = Done;
700    end Timed_Protected_Single_Entry_Call;
701
702    ------------------
703    -- Unlock_Entry --
704    ------------------
705
706    procedure Unlock_Entry (Object : Protection_Entry_Access) is
707    begin
708       --  We are exiting from a protected action, so that we decrease the
709       --  protected object nesting level (if pragma Detect_Blocking is active).
710
711       if Detect_Blocking then
712          declare
713             Self_Id : constant Task_Id := Self;
714
715          begin
716             --  Cannot call Unlock_Entry without being within protected action
717
718             pragma Assert (Self_Id.Common.Protected_Action_Nesting > 0);
719
720             Self_Id.Common.Protected_Action_Nesting :=
721               Self_Id.Common.Protected_Action_Nesting - 1;
722          end;
723       end if;
724
725       STPO.Unlock (Object.L'Access);
726    end Unlock_Entry;
727
728 end System.Tasking.Protected_Objects.Single_Entry;