D.2.4 Non-Preemptive Dispatching
The following language-defined library package exists:
Preelaborate, Nonblocking, Global => in out synchronized is(Non_Preemptive);
A call of Yield_To_Higher is a task dispatching point for this policy.
If the task at the head of the highest priority ready queue has a higher
active priority than the calling task, then the calling task is preempted.
Ramification: For language-defined policies
other than Non_Preemptive_FIFO_Within_Priorities, a higher priority task
should never be on a ready queue while a lower priority task is executed.
Thus, for such policies, Yield_To_Higher does nothing.
Yield_To_Higher is not a potentially
blocking operation; it can be used during a protected operation. That
is allowed, as under the predefined Ceiling_Locking policy any task with
a higher priority than the protected operation cannot call the operation
(that would violate the locking policy). An implementation-defined locking
policy may need to define the semantics of Yield_To_Higher differently.
Reason: The non-preemptive nature of
this policy could cause the policies of higher priority tasks to malfunction,
missing deadlines and having unlimited priority inversion. That would
render the use of such policies impotent and misleading. As such, this
policy only makes sense for a complete system.
When Non_Preemptive_FIFO_Within_Priorities is in effect, modifications
to the ready queues occur only as follows:
When a blocked task becomes ready, it is added at the tail of the ready
queue for its active priority.
When the active priority of a ready task that is
not running changes, or the setting of its base priority takes effect,
the task is removed from the ready queue for its old active priority
and is added at the tail of the ready queue for its new active priority.
When the setting of the base priority of a running
task takes effect, the task is added to the tail of the ready queue for
its active priority.
When a task executes a delay_statement
that does not result in blocking, it is added to the tail of the ready
queue for its active priority.
Ramification: If the delay does result
in blocking, the task moves to the “delay queue”, not to
the ready queue.
For this policy, blocking or termination of a task, a delay_statement
a call to Yield_To_Higher, and a call to Yield_To_Same_Or_Higher or Yield
are the only task dispatching points (see D.2.1
is always a task dispatching point even if it is not blocking. Similarly,
a call to Yield_To_Higher is never blocking, but it is a task dispatching
point In each of these cases, they can cause the current task to stop
running (it is still ready). Otherwise, the running task continues to
run until it is blocked.
This rule supersedes the Implementation Permission
of D.2.1; an implementation that adds additional
task dispatching points to this policy is incorrect.
An implementation shall allow, for a single partition, both the task
dispatching policy to be specified as Non_Preemptive_FIFO_Within_Priorities
and also the locking policy (see D.3
) to be
specified as Ceiling_Locking.
Reason: This is the preferred combination
of the Non_Preemptive_FIFO_Within_Priorities policy with a locking policy,
and we want that combination to be portable.
Since implementations are allowed to round all ceiling priorities in
subrange System.Priority to System.Priority'Last (see D.3
an implementation may allow a task of a partition using the Non_Premptive_FIFO_Within_Priorities
policy to execute within a protected object without raising its active
priority provided the associated protected unit does not contain any
subprograms with aspects Interrupt_Handler or Attach_Handler specified,
nor does the unit have aspect Interrupt_Priority specified. When the
locking policy (see D.3
) is Ceiling_Locking,
an implementation taking advantage of this permission shall ensure that
a call to Yield_to_Higher that occurs within a protected action uses
the ceiling priority of the protected object (rather than the active
priority of the task) when determining whether to preempt the task.
We explicitly require that the ceiling priority be used in calls to Yield_to_Higher
in order to prevent a risk of priority inversion and consequent loss
of mutual exclusion when Yield_to_Higher is used in a protected object.
This requirement might lessen the value of the permission (as the current
Ceiling_Priority will have to be maintained in the TCB), but loss of
mutual exclusion cannot be tolerated. The primary benefit of the permission
(eliminating the need for preemption at the end of a protected action)
is still available. As noted above, an implementation-defined locking
policy will need to specify the semantics of Yield_to_Higher, including
Extensions to Ada 95
Extensions to Ada 2005
Package Dispatching.Non_Preemptive is new.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe