PR target/35485
[official-gcc.git] / gcc / ada / s-tposen.adb
blobdfa4c03beba23ed6cec24a981cf95071383439fe
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- SYSTEM.TASKING.PROTECTED_OBJECTS.SINGLE_ENTRY --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1998-2008, 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, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, 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 ------------------------------------------------------------------------------
34 pragma Style_Checks (All_Checks);
35 -- Turn off subprogram ordering check, since restricted GNARLI subprograms are
36 -- gathered together at end.
38 -- This package provides an optimized version of Protected_Objects.Operations
39 -- and Protected_Objects.Entries making the following assumptions:
41 -- PO has 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)
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).
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.
61 pragma Suppress (All_Checks);
62 -- Why is this required ???
64 with Ada.Exceptions;
66 with System.Task_Primitives.Operations;
67 with System.Parameters;
69 package body System.Tasking.Protected_Objects.Single_Entry is
71 package STPO renames System.Task_Primitives.Operations;
73 use Parameters;
75 -----------------------
76 -- Local Subprograms --
77 -----------------------
79 procedure Send_Program_Error
80 (Self_Id : Task_Id;
81 Entry_Call : Entry_Call_Link);
82 pragma Inline (Send_Program_Error);
83 -- Raise Program_Error in the caller of the specified entry call
85 --------------------------
86 -- Entry Calls Handling --
87 --------------------------
89 procedure Wakeup_Entry_Caller
90 (Self_ID : Task_Id;
91 Entry_Call : Entry_Call_Link;
92 New_State : Entry_Call_State);
93 pragma Inline (Wakeup_Entry_Caller);
94 -- This is called at the end of service of an entry call,
95 -- to abort the caller if he is in an abortable part, and
96 -- to wake up the caller if he is on Entry_Caller_Sleep.
97 -- Call it holding the lock of Entry_Call.Self.
99 -- Timed_Call or Simple_Call:
100 -- The caller is waiting on Entry_Caller_Sleep, in
101 -- Wait_For_Completion, or Wait_For_Completion_With_Timeout.
103 procedure Wait_For_Completion (Entry_Call : Entry_Call_Link);
104 pragma Inline (Wait_For_Completion);
105 -- This procedure suspends the calling task until the specified entry call
106 -- has either been completed or cancelled. On exit, the call will not be
107 -- queued. This waits for calls on protected entries.
108 -- Call this only when holding Self_ID locked.
110 procedure Wait_For_Completion_With_Timeout
111 (Entry_Call : Entry_Call_Link;
112 Wakeup_Time : Duration;
113 Mode : Delay_Modes);
114 -- Same as Wait_For_Completion but it waits for a timeout with the value
115 -- specified in Wakeup_Time as well.
117 procedure Check_Exception
118 (Self_ID : Task_Id;
119 Entry_Call : Entry_Call_Link);
120 pragma Inline (Check_Exception);
121 -- Raise any pending exception from the Entry_Call.
122 -- This should be called at the end of every compiler interface procedure
123 -- that implements an entry call.
124 -- The caller should not be holding any locks, or there will be deadlock.
126 procedure PO_Do_Or_Queue
127 (Self_Id : Task_Id;
128 Object : Protection_Entry_Access;
129 Entry_Call : Entry_Call_Link);
130 -- This procedure executes or queues an entry call, depending
131 -- on the status of the corresponding barrier. It assumes that the
132 -- specified object is locked.
134 ---------------------
135 -- Check_Exception --
136 ---------------------
138 procedure Check_Exception
139 (Self_ID : Task_Id;
140 Entry_Call : Entry_Call_Link)
142 pragma Warnings (Off, Self_ID);
144 procedure Internal_Raise (X : Ada.Exceptions.Exception_Id);
145 pragma Import (C, Internal_Raise, "__gnat_raise_with_msg");
147 use type Ada.Exceptions.Exception_Id;
149 E : constant Ada.Exceptions.Exception_Id :=
150 Entry_Call.Exception_To_Raise;
152 begin
153 if E /= Ada.Exceptions.Null_Id then
154 Internal_Raise (E);
155 end if;
156 end Check_Exception;
158 ------------------------
159 -- Send_Program_Error --
160 ------------------------
162 procedure Send_Program_Error
163 (Self_Id : Task_Id;
164 Entry_Call : Entry_Call_Link)
166 Caller : constant Task_Id := Entry_Call.Self;
167 begin
168 Entry_Call.Exception_To_Raise := Program_Error'Identity;
170 if Single_Lock then
171 STPO.Lock_RTS;
172 end if;
174 STPO.Write_Lock (Caller);
175 Wakeup_Entry_Caller (Self_Id, Entry_Call, Done);
176 STPO.Unlock (Caller);
178 if Single_Lock then
179 STPO.Unlock_RTS;
180 end if;
181 end Send_Program_Error;
183 -------------------------
184 -- Wait_For_Completion --
185 -------------------------
187 procedure Wait_For_Completion (Entry_Call : Entry_Call_Link) is
188 Self_Id : constant Task_Id := Entry_Call.Self;
189 begin
190 Self_Id.Common.State := Entry_Caller_Sleep;
191 STPO.Sleep (Self_Id, Entry_Caller_Sleep);
192 Self_Id.Common.State := Runnable;
193 end Wait_For_Completion;
195 --------------------------------------
196 -- Wait_For_Completion_With_Timeout --
197 --------------------------------------
199 procedure Wait_For_Completion_With_Timeout
200 (Entry_Call : Entry_Call_Link;
201 Wakeup_Time : Duration;
202 Mode : Delay_Modes)
204 Self_Id : constant Task_Id := Entry_Call.Self;
205 Timedout : Boolean;
207 Yielded : Boolean;
208 pragma Unreferenced (Yielded);
210 use type Ada.Exceptions.Exception_Id;
212 begin
213 -- This procedure waits for the entry call to be served, with a timeout.
214 -- It tries to cancel the call if the timeout expires before the call is
215 -- served.
217 -- If we wake up from the timed sleep operation here, it may be for the
218 -- following possible reasons:
220 -- 1) The entry call is done being served.
221 -- 2) The timeout has expired (Timedout = True)
223 -- Once the timeout has expired we may need to continue to wait if the
224 -- call is already being serviced. In that case, we want to go back to
225 -- sleep, but without any timeout. The variable Timedout is used to
226 -- control this. If the Timedout flag is set, we do not need to Sleep
227 -- with a timeout. We just sleep until we get a wakeup for some status
228 -- change.
230 pragma Assert (Entry_Call.Mode = Timed_Call);
231 Self_Id.Common.State := Entry_Caller_Sleep;
233 STPO.Timed_Sleep
234 (Self_Id, Wakeup_Time, Mode, Entry_Caller_Sleep, Timedout, Yielded);
236 if Timedout then
237 Entry_Call.State := Cancelled;
238 else
239 Entry_Call.State := Done;
240 end if;
242 Self_Id.Common.State := Runnable;
243 end Wait_For_Completion_With_Timeout;
245 -------------------------
246 -- Wakeup_Entry_Caller --
247 -------------------------
249 -- This is called at the end of service of an entry call, to abort the
250 -- caller if he is in an abortable part, and to wake up the caller if it
251 -- is on Entry_Caller_Sleep. It assumes that the call is already off-queue.
253 -- (This enforces the rule that a task must be off-queue if its state is
254 -- Done or Cancelled.) Call it holding the lock of Entry_Call.Self.
256 -- Timed_Call or Simple_Call:
257 -- The caller is waiting on Entry_Caller_Sleep, in
258 -- Wait_For_Completion, or Wait_For_Completion_With_Timeout.
260 -- Conditional_Call:
261 -- The caller might be in Wait_For_Completion,
262 -- waiting for a rendezvous (possibly requeued without abort)
263 -- to complete.
265 procedure Wakeup_Entry_Caller
266 (Self_ID : Task_Id;
267 Entry_Call : Entry_Call_Link;
268 New_State : Entry_Call_State)
270 pragma Warnings (Off, Self_ID);
272 Caller : constant Task_Id := Entry_Call.Self;
274 begin
275 pragma Assert (New_State = Done or else New_State = Cancelled);
276 pragma Assert
277 (Caller.Common.State /= Terminated and then
278 Caller.Common.State /= Unactivated);
280 Entry_Call.State := New_State;
281 STPO.Wakeup (Caller, Entry_Caller_Sleep);
282 end Wakeup_Entry_Caller;
284 -----------------------
285 -- Restricted GNARLI --
286 -----------------------
288 --------------------------------
289 -- Complete_Single_Entry_Body --
290 --------------------------------
292 procedure Complete_Single_Entry_Body (Object : Protection_Entry_Access) is
293 pragma Warnings (Off, Object);
295 begin
296 -- Nothing needs to do (Object.Call_In_Progress.Exception_To_Raise
297 -- has already been set to Null_Id).
299 null;
300 end Complete_Single_Entry_Body;
302 --------------------------------------------
303 -- Exceptional_Complete_Single_Entry_Body --
304 --------------------------------------------
306 procedure Exceptional_Complete_Single_Entry_Body
307 (Object : Protection_Entry_Access;
308 Ex : Ada.Exceptions.Exception_Id) is
309 begin
310 Object.Call_In_Progress.Exception_To_Raise := Ex;
311 end Exceptional_Complete_Single_Entry_Body;
313 ---------------------------------
314 -- Initialize_Protection_Entry --
315 ---------------------------------
317 procedure Initialize_Protection_Entry
318 (Object : Protection_Entry_Access;
319 Ceiling_Priority : Integer;
320 Compiler_Info : System.Address;
321 Entry_Body : Entry_Body_Access)
323 Init_Priority : Integer := Ceiling_Priority;
324 begin
325 if Init_Priority = Unspecified_Priority then
326 Init_Priority := System.Priority'Last;
327 end if;
329 STPO.Initialize_Lock (Init_Priority, Object.L'Access);
330 Object.Ceiling := System.Any_Priority (Init_Priority);
331 Object.Owner := Null_Task;
332 Object.Compiler_Info := Compiler_Info;
333 Object.Call_In_Progress := null;
334 Object.Entry_Body := Entry_Body;
335 Object.Entry_Queue := null;
336 end Initialize_Protection_Entry;
338 ----------------
339 -- Lock_Entry --
340 ----------------
342 -- Compiler interface only.
343 -- Do not call this procedure from within the run-time system.
345 procedure Lock_Entry (Object : Protection_Entry_Access) is
346 Ceiling_Violation : Boolean;
348 begin
349 -- If pragma Detect_Blocking is active then, as described in the ARM
350 -- 9.5.1, par. 15, we must check whether this is an external call on a
351 -- protected subprogram with the same target object as that of the
352 -- protected action that is currently in progress (i.e., if the caller
353 -- is already the protected object's owner). If this is the case hence
354 -- Program_Error must be raised.
356 if Detect_Blocking and then Object.Owner = Self then
357 raise Program_Error;
358 end if;
360 STPO.Write_Lock (Object.L'Access, Ceiling_Violation);
362 if Ceiling_Violation then
363 raise Program_Error;
364 end if;
366 -- We are entering in a protected action, so that we increase the
367 -- protected object nesting level (if pragma Detect_Blocking is
368 -- active), and update the protected object's owner.
370 if Detect_Blocking then
371 declare
372 Self_Id : constant Task_Id := Self;
374 begin
375 -- Update the protected object's owner
377 Object.Owner := Self_Id;
379 -- Increase protected object nesting level
381 Self_Id.Common.Protected_Action_Nesting :=
382 Self_Id.Common.Protected_Action_Nesting + 1;
383 end;
384 end if;
385 end Lock_Entry;
387 --------------------------
388 -- Lock_Read_Only_Entry --
389 --------------------------
391 -- Compiler interface only
393 -- Do not call this procedure from within the runtime system
395 procedure Lock_Read_Only_Entry (Object : Protection_Entry_Access) is
396 Ceiling_Violation : Boolean;
398 begin
399 -- If pragma Detect_Blocking is active then, as described in the ARM
400 -- 9.5.1, par. 15, we must check whether this is an external call on a
401 -- protected subprogram with the same target object as that of the
402 -- protected action that is currently in progress (i.e., if the caller
403 -- is already the protected object's owner). If this is the case hence
404 -- Program_Error must be raised.
406 -- Note that in this case (getting read access), several tasks may
407 -- have read ownership of the protected object, so that this method of
408 -- storing the (single) protected object's owner does not work
409 -- reliably for read locks. However, this is the approach taken for two
410 -- major reasons: first, this function is not currently being used (it
411 -- is provided for possible future use), and second, it largely
412 -- simplifies the implementation.
414 if Detect_Blocking and then Object.Owner = Self then
415 raise Program_Error;
416 end if;
418 STPO.Read_Lock (Object.L'Access, Ceiling_Violation);
420 if Ceiling_Violation then
421 raise Program_Error;
422 end if;
424 -- We are entering in a protected action, so that we increase the
425 -- protected object nesting level (if pragma Detect_Blocking is
426 -- active), and update the protected object's owner.
428 if Detect_Blocking then
429 declare
430 Self_Id : constant Task_Id := Self;
432 begin
433 -- Update the protected object's owner
435 Object.Owner := Self_Id;
437 -- Increase protected object nesting level
439 Self_Id.Common.Protected_Action_Nesting :=
440 Self_Id.Common.Protected_Action_Nesting + 1;
441 end;
442 end if;
443 end Lock_Read_Only_Entry;
445 --------------------
446 -- PO_Do_Or_Queue --
447 --------------------
449 procedure PO_Do_Or_Queue
450 (Self_Id : Task_Id;
451 Object : Protection_Entry_Access;
452 Entry_Call : Entry_Call_Link)
454 Barrier_Value : Boolean;
456 begin
457 -- When the Action procedure for an entry body returns, it must be
458 -- completed (having called [Exceptional_]Complete_Entry_Body).
460 Barrier_Value := Object.Entry_Body.Barrier (Object.Compiler_Info, 1);
462 if Barrier_Value then
463 if Object.Call_In_Progress /= null then
465 -- This violates the No_Entry_Queue restriction, send
466 -- Program_Error to the caller.
468 Send_Program_Error (Self_Id, Entry_Call);
469 return;
470 end if;
472 Object.Call_In_Progress := Entry_Call;
473 Object.Entry_Body.Action
474 (Object.Compiler_Info, Entry_Call.Uninterpreted_Data, 1);
475 Object.Call_In_Progress := null;
477 if Single_Lock then
478 STPO.Lock_RTS;
479 end if;
481 STPO.Write_Lock (Entry_Call.Self);
482 Wakeup_Entry_Caller (Self_Id, Entry_Call, Done);
483 STPO.Unlock (Entry_Call.Self);
485 if Single_Lock then
486 STPO.Unlock_RTS;
487 end if;
489 elsif Entry_Call.Mode /= Conditional_Call then
490 if Object.Entry_Queue /= null then
492 -- This violates the No_Entry_Queue restriction, send
493 -- Program_Error to the caller.
495 Send_Program_Error (Self_Id, Entry_Call);
496 return;
497 else
498 Object.Entry_Queue := Entry_Call;
499 end if;
501 else
502 -- Conditional_Call
504 if Single_Lock then
505 STPO.Lock_RTS;
506 end if;
508 STPO.Write_Lock (Entry_Call.Self);
509 Wakeup_Entry_Caller (Self_Id, Entry_Call, Cancelled);
510 STPO.Unlock (Entry_Call.Self);
512 if Single_Lock then
513 STPO.Unlock_RTS;
514 end if;
515 end if;
517 exception
518 when others =>
519 Send_Program_Error
520 (Self_Id, Entry_Call);
521 end PO_Do_Or_Queue;
523 ----------------------------
524 -- Protected_Single_Count --
525 ----------------------------
527 function Protected_Count_Entry (Object : Protection_Entry) return Natural is
528 begin
529 if Object.Entry_Queue /= null then
530 return 1;
531 else
532 return 0;
533 end if;
534 end Protected_Count_Entry;
536 ---------------------------------
537 -- Protected_Single_Entry_Call --
538 ---------------------------------
540 procedure Protected_Single_Entry_Call
541 (Object : Protection_Entry_Access;
542 Uninterpreted_Data : System.Address;
543 Mode : Call_Modes)
545 Self_Id : constant Task_Id := STPO.Self;
546 Entry_Call : Entry_Call_Record renames Self_Id.Entry_Calls (1);
547 begin
548 -- If pragma Detect_Blocking is active then Program_Error must be
549 -- raised if this potentially blocking operation is called from a
550 -- protected action.
552 if Detect_Blocking
553 and then Self_Id.Common.Protected_Action_Nesting > 0
554 then
555 raise Program_Error with "potentially blocking operation";
556 end if;
558 Lock_Entry (Object);
560 Entry_Call.Mode := Mode;
561 Entry_Call.State := Now_Abortable;
562 Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
563 Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;
565 PO_Do_Or_Queue (Self_Id, Object, Entry_Call'Access);
566 Unlock_Entry (Object);
568 -- The call is either `Done' or not. It cannot be cancelled since there
569 -- is no ATC construct.
571 pragma Assert (Entry_Call.State /= Cancelled);
573 if Entry_Call.State /= Done then
574 if Single_Lock then
575 STPO.Lock_RTS;
576 end if;
578 STPO.Write_Lock (Self_Id);
579 Wait_For_Completion (Entry_Call'Access);
580 STPO.Unlock (Self_Id);
582 if Single_Lock then
583 STPO.Unlock_RTS;
584 end if;
585 end if;
587 Check_Exception (Self_Id, Entry_Call'Access);
588 end Protected_Single_Entry_Call;
590 -----------------------------------
591 -- Protected_Single_Entry_Caller --
592 -----------------------------------
594 function Protected_Single_Entry_Caller
595 (Object : Protection_Entry) return Task_Id is
596 begin
597 return Object.Call_In_Progress.Self;
598 end Protected_Single_Entry_Caller;
600 -------------------
601 -- Service_Entry --
602 -------------------
604 procedure Service_Entry (Object : Protection_Entry_Access) is
605 Self_Id : constant Task_Id := STPO.Self;
606 Entry_Call : constant Entry_Call_Link := Object.Entry_Queue;
607 Caller : Task_Id;
609 begin
610 if Entry_Call /= null
611 and then Object.Entry_Body.Barrier (Object.Compiler_Info, 1)
612 then
613 Object.Entry_Queue := null;
615 if Object.Call_In_Progress /= null then
617 -- Violation of No_Entry_Queue restriction, raise exception
619 Send_Program_Error (Self_Id, Entry_Call);
620 Unlock_Entry (Object);
621 return;
622 end if;
624 Object.Call_In_Progress := Entry_Call;
625 Object.Entry_Body.Action
626 (Object.Compiler_Info, Entry_Call.Uninterpreted_Data, 1);
627 Object.Call_In_Progress := null;
628 Caller := Entry_Call.Self;
629 Unlock_Entry (Object);
631 if Single_Lock then
632 STPO.Lock_RTS;
633 end if;
635 STPO.Write_Lock (Caller);
636 Wakeup_Entry_Caller (Self_Id, Entry_Call, Done);
637 STPO.Unlock (Caller);
639 if Single_Lock then
640 STPO.Unlock_RTS;
641 end if;
643 else
644 -- Just unlock the entry
646 Unlock_Entry (Object);
647 end if;
649 exception
650 when others =>
651 Send_Program_Error (Self_Id, Entry_Call);
652 Unlock_Entry (Object);
653 end Service_Entry;
655 ---------------------------------------
656 -- Timed_Protected_Single_Entry_Call --
657 ---------------------------------------
659 -- Compiler interface only (do not call from within the RTS)
661 procedure Timed_Protected_Single_Entry_Call
662 (Object : Protection_Entry_Access;
663 Uninterpreted_Data : System.Address;
664 Timeout : Duration;
665 Mode : Delay_Modes;
666 Entry_Call_Successful : out Boolean)
668 Self_Id : constant Task_Id := STPO.Self;
669 Entry_Call : Entry_Call_Record renames Self_Id.Entry_Calls (1);
670 Ceiling_Violation : Boolean;
672 begin
673 -- If pragma Detect_Blocking is active then Program_Error must be
674 -- raised if this potentially blocking operation is called from a
675 -- protected action.
677 if Detect_Blocking
678 and then Self_Id.Common.Protected_Action_Nesting > 0
679 then
680 raise Program_Error with "potentially blocking operation";
681 end if;
683 STPO.Write_Lock (Object.L'Access, Ceiling_Violation);
685 if Ceiling_Violation then
686 raise Program_Error;
687 end if;
689 Entry_Call.Mode := Timed_Call;
690 Entry_Call.State := Now_Abortable;
691 Entry_Call.Uninterpreted_Data := Uninterpreted_Data;
692 Entry_Call.Exception_To_Raise := Ada.Exceptions.Null_Id;
694 PO_Do_Or_Queue (Self_Id, Object, Entry_Call'Access);
695 Unlock_Entry (Object);
697 -- Try to avoid waiting for completed calls.
698 -- The call is either `Done' or not. It cannot be cancelled since there
699 -- is no ATC construct and the timed wait has not started yet.
701 pragma Assert (Entry_Call.State /= Cancelled);
703 if Entry_Call.State = Done then
704 Check_Exception (Self_Id, Entry_Call'Access);
705 Entry_Call_Successful := True;
706 return;
707 end if;
709 if Single_Lock then
710 STPO.Lock_RTS;
711 else
712 STPO.Write_Lock (Self_Id);
713 end if;
715 Wait_For_Completion_With_Timeout (Entry_Call'Access, Timeout, Mode);
717 if Single_Lock then
718 STPO.Unlock_RTS;
719 else
720 STPO.Unlock (Self_Id);
721 end if;
723 pragma Assert (Entry_Call.State >= Done);
725 Check_Exception (Self_Id, Entry_Call'Access);
726 Entry_Call_Successful := Entry_Call.State = Done;
727 end Timed_Protected_Single_Entry_Call;
729 ------------------
730 -- Unlock_Entry --
731 ------------------
733 procedure Unlock_Entry (Object : Protection_Entry_Access) is
734 begin
735 -- We are exiting from a protected action, so that we decrease the
736 -- protected object nesting level (if pragma Detect_Blocking is
737 -- active), and remove ownership of the protected object.
739 if Detect_Blocking then
740 declare
741 Self_Id : constant Task_Id := Self;
743 begin
744 -- Calls to this procedure can only take place when being within
745 -- a protected action and when the caller is the protected
746 -- object's owner.
748 pragma Assert (Self_Id.Common.Protected_Action_Nesting > 0
749 and then Object.Owner = Self_Id);
751 -- Remove ownership of the protected object
753 Object.Owner := Null_Task;
755 Self_Id.Common.Protected_Action_Nesting :=
756 Self_Id.Common.Protected_Action_Nesting - 1;
757 end;
758 end if;
760 STPO.Unlock (Object.L'Access);
761 end Unlock_Entry;
763 end System.Tasking.Protected_Objects.Single_Entry;