D.3 Priority Ceiling Locking
This subclause specifies the interactions between 
priority task scheduling and protected object ceilings. This interaction 
is based on the concept of the ceiling priority of a protected 
object. 
Syntax
The form of a 
pragma 
Locking_Policy is as follows: 
 
Legality Rules
Post-Compilation Rules
A Locking_Policy 
pragma is a configuration pragma.
 
Dynamic Semantics
A locking policy specifies the 
details of protected object locking. All protected objects have a priority. 
The locking policy specifies the meaning of the priority of a protected 
object, and the relationships between these priorities and task priorities. 
In addition, the policy specifies the state of a task when it executes 
a protected action, and how its active priority is affected by the locking. 
The 
locking policy is specified by a Locking_Policy pragma. For 
implementation-defined locking policies, the meaning of the priority 
of a protected object is implementation defined. If no Locking_Policy 
pragma applies to any of the program units comprising a partition, the 
locking policy for that partition, as well as the meaning of the priority 
of a protected object, are implementation defined. 
 
  The 
expression 
specified for the Priority or Interrupt_Priority aspect (see 
D.1) 
is evaluated as part of the creation of the corresponding protected object 
and converted to the subtype System.Any_Priority or System.Interrupt_Priority, 
respectively. The value of the expression is the initial priority of 
the corresponding protected object. If no Priority or Interrupt_Priority 
aspect is specified for a protected object, the initial priority is specified 
by the locking policy. 
 
There is one predefined 
locking policy, Ceiling_Locking; this policy is defined as follows:
 
 
Every protected object has 
a 
ceiling priority, which is determined by either a Priority or 
Interrupt_Priority aspect as defined in 
D.1, 
or by assignment to the Priority attribute as described in 
D.5.2. 
The ceiling priority of a protected object (or ceiling, for short) is 
an upper bound on the active priority a task can have when it calls protected 
operations of that protected object.
 
The initial ceiling priority of a protected object 
is equal to the initial priority for that object.
If an Interrupt_Handler or Attach_Handler aspect 
(see 
C.3.1) is specified for a protected 
subprogram of a protected type that does not have either the Priority 
or Interrupt_Priority aspect specified, the initial priority of protected 
objects of that type is implementation defined, but in the range of the 
subtype System.Interrupt_Priority. 
 
If neither aspect Priority nor Interrupt_Priority 
is specified for a protected type, and no protected subprogram of the 
type has aspect Interrupt_Handler or Attach_Handler specified, then the 
initial priority of the corresponding protected object is System.Priority'Last.
While a task executes a protected action, it inherits 
the ceiling priority of the corresponding protected object.
When 
a task calls a protected operation, a check is made that its active priority 
is not higher than the ceiling of the corresponding protected object; 
Program_Error is raised if this check fails.
 
Bounded (Run-Time) Errors
   Following any change 
of priority, it is a bounded error for the active priority of any task 
with a call queued on an entry of a protected object to be higher than 
the ceiling priority of the protected object. 
In 
this case one of the following applies:
 
at any time prior to executing the entry body Program_Error 
is raised in the calling task; 
 
when the entry is open the entry body is executed 
at the ceiling priority of the protected object;
when the entry is open the entry body is executed 
at the ceiling priority of the protected object and then Program_Error 
is raised in the calling task; or 
 
when the entry is open the entry body is executed 
at the ceiling priority of the protected object that was in effect when 
the entry call was queued. 
Implementation Permissions
The implementation is allowed to round all ceilings 
in a certain subrange of System.Priority or System.Interrupt_Priority 
up to the top of that subrange, uniformly. 
 Implementations are allowed to define other locking 
policies, but need not support more than one locking policy per partition.
Since implementations are allowed to place restrictions 
on code that runs at an interrupt-level active priority (see 
C.3.1 
and 
D.2.1), the implementation may implement 
a language feature in terms of a protected object with an implementation-defined 
ceiling, but the ceiling shall be no less than Priority'Last. 
 
Implementation Advice
The implementation should use names that end with 
“_Locking” for implementation-defined locking policies.
20  While a task executes in a protected 
action, it can be preempted only by tasks whose active priorities are 
higher than the ceiling priority of the protected object.
21  If a protected object has a ceiling 
priority in the range of Interrupt_Priority, certain interrupts are blocked 
while protected actions of that object execute. In the extreme, if the 
ceiling is Interrupt_Priority'Last, all blockable interrupts are blocked 
during that time.
22  The ceiling priority of a protected 
object has to be in the Interrupt_Priority range if one of its procedures 
is to be used as an interrupt handler (see 
C.3).
 
23  When specifying the ceiling of a protected 
object, one should choose a value that is at least as high as the highest 
active priority at which tasks can be executing when they call protected 
operations of that object. In determining this value the following factors, 
which can affect active priority, should be considered: the effect of 
Set_Priority, nested protected operations, entry calls, task activation, 
and other implementation-defined factors.
24  Attaching a protected procedure whose 
ceiling is below the interrupt hardware priority to an interrupt causes 
the execution of the program to be erroneous (see 
C.3.1).
 
25  On a single processor implementation, 
the ceiling priority rules guarantee that there is no possibility of 
deadlock involving only protected subprograms (excluding the case where 
a protected operation calls another protected operation on the same protected 
object).
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe