Professional Documents
Culture Documents
UNIT5
UNIT5
Embedded/Real-Time OS Concepts
Architecture of Kernel
Task and Task Scheduler
Context Switching
Scheduling Algorithms
EDF and Rate Monotonic
Interrupt Service Routine
Memory Management
Priority Inversion Problem
Priority inheritance
Embedded OS
Handheld OS
Process management
Device management
Memory management
Interrupt handling
I/O communication
File system...etc.
Types of Kernel :
1. Monolithic Kernel –
It is one of types of kernel where all operating system services operate
in kernel space. It has dependencies between systems components. It
has huge lines of code which is complex.
Example :
Unix, Linux, Open VMS, XTS-400 etc.
Advantage :
It has good performance.
Disadvantage :
It has dependencies between system component and lines of code in
millions.
2. Micro Kernel –
It is kernel types which has minimalist approach. It has virtual memory and
thread scheduling. It is more stable with less services in kernel space. It puts
rest in user space.
Example :
Mach, L4, AmigaOS, Minix, K42 etc.
Advantage :
It is more stable.
Disadvantage :
There are lots of system calls and context switches.
2. Hybrid Kernel –
It is the combination of both monolithic kernel and microkernel. It has speed
and design of monolithic kernel and modularity and stability of microkernel.
Example :
Windows NT, Netware, BeOS etc.
Advantage :
It combines both monolithic kernel and microkernel.
Disadvantage :
It is still similar to monolithic kernel.
4. Exo Kernel –
It is the type of kernel which follows end-to-end principle. It has fewest
hardware abstractions as possible. It allocates physical resources to
applications.
Example :
Nemesis, ExOS etc.
Advantage :
It has fewest hardware abstractions.
Disadvantage :
There is more work for application developers.
5. Nano Kernel –
It is the type of kernel that offers hardware abstraction but without system
services. Micro Kernel also does not have system services therefore the
Micro Kernel and Nano Kernel have become analogous.
Example :
EROS etc.
Advantage :
It offers hardware abstractions without system services.
Disadvantage :
It is quite same as Micro kernel hence it is less used.
2.Task and Task Scheduler
Rate-monotonic scheduling
Last Updated : 13 May, 2020
Read
Discuss
Rate monotonic scheduling is a priority algorithm that belongs to the static priority
scheduling category of Real Time Operating Systems. It is preemptive in nature. The
priority is decided according to the cycle time of the processes that are involved. If the
process has a small job duration, then it has the highest priority. Thus if a process with
highest priority starts execution, it will preempt the other running processes. The
priority of a process is inversely proportional to the period it will run for.
A set of processes can be scheduled only if they satisfy the following equation :
Where n is the number of processes in the process set, Ci is the computation time of
the process, Ti is the Time period for the process to run and U is the processor
utilization.
Example:
An example to understand the working of Rate monotonic scheduling algorithm.
Processe Execution Time Time period
s (C) (T)
P1 3 20
P2 2 5
P3 2 10
n( 2^1/n - 1 ) = 3 ( 2^1/3 - 1 ) = 0.7977
Process P2 will run first for 2 time units because it has the highest priority. After
completing its two units, P3 will get the chance and thus it will run for 2 time
units.
As we know that process P2 will run 2 times in the interval of 5 time units and
process P3 will run 2 times in the interval of 10 time units, they have fulfilled the
criteria and thus now process P1 which has the least priority will get the chance
and it will run for 1 time. And here the interval of five time units have completed.
Because of its priority P2 will preempt P1 and thus will run 2 times. As P3 have
completed its 2 time units for its interval of 10 time units, P1 will get chance and it
will run for the remaining 2 times, completing its execution which was thrice in 20
time units.
Now 9-10 interval remains idle as no process needs it. At 10 time units, process P2
will run for 2 times completing its criteria for the third interval ( 10-15 ). Process
P3 will now run for two times completing its execution. Interval 14-15 will again
remain idle for the same reason mentioned above. At 15 time unit, process P2 will
execute for two times completing its execution. This is how the rate monotonic
scheduling works.
Conditions :
The analysis of Rate monotonic scheduling assumes few properties that every process
should possess. They are :
1. Processes involved should not share the resources with other processes.
2. Deadlines must be similar to the time periods. Deadlines are deterministic.
3. Process running with highest priority that needs to run, will preempt all the other
processes.
4. Priorities must be assigned to all the processes according to the protocol of Rate
monotonic scheduling.
Advantages :
1. It is easy to implement.
2. If any static priority assignment algorithm can meet the deadlines then rate
monotonic scheduling can also do the same. It is optimal.
3. It consists of calculated copy of the time periods unlike other time-sharing
algorithms as Round robin which neglects the scheduling needs of the processes.
Disadvantages :
1. It is very difficult to support aperiodic and sporadic tasks under RMA.
2. RMA is not optimal when tasks period and deadline differ.
Earliest Deadline First (EDF) CPU
scheduling algorithm
Earliest Deadline First (EDF) is an optimal dynamic priority scheduling algorithm
used in real-time systems.
It can be used for both static and dynamic real-time scheduling.
EDF uses priorities to the jobs for scheduling. It assigns priorities to the task
according to the absolute deadline. The task whose deadline is closest gets the highest
priority. The priorities are assigned and changed in a dynamic fashion. EDF is very
efficient as compared to other scheduling algorithms in real-time systems. It can make
the CPU utilization to about 100% while still guaranteeing the deadlines of all the
tasks.
EDF includes the kernel overload. In EDF, if the CPU usage is less than 100%, then it
means that all the tasks have met the deadline. EDF finds an optimal feasible
schedule. The feasible schedule is one in which all the tasks in the system are
executed within the deadline. If EDF is not able to find a feasible schedule for all the
tasks in the real-time system, then it means that no other task scheduling algorithms in
real-time systems can give a feasible schedule. All the tasks which are ready for
execution should announce their deadline to EDF when the task becomes runnable.
EDF scheduling algorithm does not need the tasks or processes to be periodic and also
the tasks or processes require a fixed CPU burst time. In EDF, any executing task can
be preempted if any other periodic instance with an earlier deadline is ready for
execution and becomes active. Preemption is allowed in the Earliest Deadline First
scheduling algorithm.
Example:
Consider two processes P1 and P2.
Let the period of P1 be p1 = 50
Let the processing time of P1 be t1 = 25
Let the period of P2 be period2 = 75
Let the processing time of P2 be t2 = 30
Steps for solution:
1. Deadline pf P1 is earlier, so priority of P1>P2.
2. Initially P1 runs and completes its execution of 25 time.
3. After 25 times, P2 starts to execute until 50 times, when P1 is able to execute.
4. Now, comparing the deadline of (P1, P2) = (100, 75), P2 continues to execute.
5. P2 completes its processing at time 55.
6. P1 starts to execute until time 75, when P2 is able to execute.
7. Now, again comparing the deadline of (P1, P2) = (100, 150), P1 continues to
execute.
8. Repeat the above steps…
9. Finally at time 150, both P1 and P2 have the same deadline, so P2 will continue to
execute till its processing time after which P1 starts to execute.
Limitations of EDF scheduling algorithm:
Transient Overload Problem
Resource Sharing Problem
Efficient Implementation Problem
First-in-first-out
First-in-first-out (FIFO) scheduling describes an operating system which is not a
multitasking operating system.
Each task runs until it is finished, and only after that is the next task started on
a first come first served basis.
Shortest job first
Shortest job first scheduling uses algorithms that will select always select a task
that will require the least amount of processor time to complete.
Round robin.
Round robin scheduling uses algorithms that allow every task to execute for a
fixed amount to time.
A running task is interrupted an put to a waiting state if its execution time
expires.
3.1 Scheduling Points
The scheduling points are the set of operating system events that result in an
invocation of the scheduler.
There are three such events: task creation and task deletion. During each of
these events a method is called to select the next task to be run.
A third scheduling point called the clock tick is a periodic event that is
triggered by a timer interrupt. When a timer expires, all of the tasks that are
waiting for it to complete are changed from the waiting state to the ready state.
3.2 Ready List
The scheduler uses a data structure called the ready list to track the tasks that
are in the ready state.
The ready list is implemented as an ordinary linked list, ordered by priority.
So the head of this list is always the highest priority task that is ready to run.
3.3 Idle task
If there are no tasks in the ready state when the scheduler is called, the idle task
will be executed.
The idle task looks the same in every operating system.
The idle task is always considered to be in the ready state.
4 CONTEXT SWITCH
The actual process of changing from one task to another is called Context
Switch.
Since contexts are processor-specific, so is the code that implements the
context switches, hence, it must always be written in assembly language.
5 TASK SYNCHRONIZATION
All the tasks in the multitasking operating systems work together to solve a
larger problem and to synchronize their activities, they occasionally
communicate with one another.
For example, in the printer sharing device the printer task doesn’t have any
work to do until new data is supplied to it by one of the computer tasks.
So the printer and the computer tasks must communicate with one another to
coordinate their access to common data buffers.
One way to do this is to use a data structure called a mutex.
Mutexes are mechanisms provided by many operating systems to assist with
task synchronization.
A mutex is a multitasking-aware binary flag. It is because the processes of
setting and clearing the binary flag are atomic (i.e. these operations cannot be
interrupted).
When this binary flag is set, the shared data buffer is assumed to be in use by
one of the tasks. All other tasks must wait until that flag is cleared before
reading or writing any of the data within that buffer.
The atomicity of the mutex set and clear operations is enforced by the operating
system, which disables interrupts before reading or modifying the state of the
binary flag.
This makes the context swap more complex and time consuming, as the OS
needs to set up the memory management unit (MMU) appropriately. Of course,
this architecture is only possible with a processor that supports an MMU.
Processes are supported by “high end” RTOSes and most desktop operating
systems. To further complicate matters, there may be support for multiple
threads within each process. This latter capability is rarely exploited in
conventional embedded applications.
A useful compromise may be reached, if an MMU is available, thus:
Many thread-based RTOSes support the use of an MMU to simply protect
memory from unauthorized access. So, while a task is in context, only its
code/data and necessary parts of the RTOS are “visible”; all the other memory is
disabled and an attempted access would cause an exception. This makes the
context switch just a little more complex, but renders the application more
secure. This may be called “Thread Protected Mode” or “Lightweight Process
Model”.
Schedulers
As we know, the illusion that all the tasks are running concurrently is achieved
by allowing each to have a share of the processor time. This is the core
functionality of a kernel. The way that time is allocated between tasks is termed
“scheduling”. The scheduler is the software that determines which task should
be run next. The logic of the scheduler and the mechanism that determines
when it should be run is the scheduling algorithm. We will look at a number of
scheduling algorithms in this section. Task scheduling is actually a vast subject,
with many whole books devoted to it. The intention here is to just give sufficient
introduction that you can understand what a given RTOS has to offer in this
respect.
Run to Completion (RTC) Scheduler
RTC scheduling is very simplistic and uses minimal resources. It is, therefore, an
ideal choice, if the application’s needs are fulfilled. Here is the timeline for a
system using RTC scheduling:
The scheduler simply calls the top level function of each task in turn. That task
has control of the CPU (interrupts aside) until the top level function executes
a return statement. If the RTOS supports task suspension, then any tasks that
are currently suspended are not run. This is a topic discussed below; see Task
Suspend .
The big advantages of an RTC scheduler, aside from its simplicity, are the need
for just a single stack and the portability of the code (as no assembly language is
generally required). The downside is that a task can “hog” the CPU, so careful
program design is required. Although each task is started “from the top” each
time it is scheduled – unlike other kinds of schedulers which allow the code to
continue from where it left off – greater flexibility may be programmed by use of
static “state” variables, which determine the logic of each sequential call.
However, with the RR scheduler, the task does not need to execute a return in
the top level function. It can relinquish the CPU at any time by making a call to
the RTOS. This call results in the kernel saving the context (all the registers –
including stack pointer and program counter) and loading the context of the
next task to be run. With some RTOSes, the processor may be relinquished – and
the task suspended – pending the availability of a kernel resource. This is more
sophisticated, but the principle is the same.
The greater flexibility of the RR scheduler comes from the ability for the tasks to
continue from where they left off without any accommodation in the
application code. The price for this flexibility is more complex, less portable
code and the need for a separate stack for each task.
Time Slice (TS) Scheduler
A TS scheduler is the next step in complexity from RR. Time is divided into
“slots”, with each task being allowed to execute for the duration of its slot, thus:
Obviously the background task should not do any time-critical work, as the
amount of CPU time it is allocated is totally unpredictable – it may never be
scheduled at all.
This design means that each task can predict when it will be scheduled again.
For example, if you have 10ms slots and 10 tasks, a task knows that, if it
relinquishes, it will continue executing after 100ms. This can lead to elegant
timing loops in application tasks.
An RTOS may offer the possibility for different time slots for each task. This
offers greater flexibility, but is just as predictable as with fixed slot size. Another
possibility is to allocate more than one slot to the same task, if you want to
increase its proportion of allocated processor time.
Priority Scheduler
Most RTOSes support Priority scheduling. The idea is simple: each task is
allocated a priority and, at any particular time, whichever task has the highest
priority and is “ready” is allocated the CPU, thus:
The scheduler is run when any “event” occurs (e.g. interrupt or certain kernel
service calls) that may cause a higher priority task being made “ready”. There
are broadly three circumstances that might result in the scheduler being run:
The number of levels of priority varies (from 8 to many hundreds) and the
significance of higher and lower values differs; some RTOSes use priority 0 as
highest, others as lowest.
Some RTOSes only allow a single task at each priority level; others permit
multiple tasks at each level, which complicates the associated data structures
considerably. Many OSes allow task priorities to be changed at runtime, which
adds further complexity.
Composite Scheduler
We have looked at RTC, RR, TS and Priority schedulers, but many commercial
RTOS products offer more sophisticated schedulers, which have characteristics
of more than one of these algorithms. For example, an RTOS may support
multiple tasks at each priority level and then use time slicing to divide time
between multiple ready tasks at the highest level.
Task States
At any one moment in time, just one task is actually running. Aside from CPU
time spent running interrupt service routines (more on that in the next article)
or the scheduler, the “current” task is the one whose code is currently being
executed and whose data is characterized by the current register values. There
may be other tasks that are “ready” (to run) and these will be considered when
the scheduler is executed. In a simple RTOS, using a Run to Completion, Round
Robin or Time Slice scheduler, this may be the whole story. But, more
commonly, and always with a Priority scheduler, tasks may also be in a
“suspended” state, which means that they are not considered by the scheduler
until they are resumed and made “ready”.
Task Suspend
Task suspension may be quite simple – a task suspends itself (by making an API
call) or another task suspends it. Another API call needs to be made by another
task or ISR to resume the suspended task. This is an “unconditional” or “pure”
suspend. Some OSes refer to a task as being “asleep”.
An RTOS may offer the facility for a task to suspend itself (go to sleep) for a
specific period of time, at the end of which it is resumed (by the system clock
ISR, see below). This may be termed “sleep suspend”.
Another more complex suspend may be offered, if an RTOS supports “blocking”
API calls. Such a call permits the task to request a service or resource, which it
will receive immediately if it is available, otherwise it is suspended until it is
available. There may also be a timeout option whereby a task is resumed if the
resource is not available in a specific timeframe.
Other Task States
Many RTOSes support other task states, but the definition of these and the
terminology used varies. Possibilities include a “finished” state, which simply
means that the task’s outermost function has exited (either by executing
a return or just ending the outer function block). For a finished task to run
again, it would probably need to be reset in some way.
Another possibility is a “terminated” state. This is like a pure suspend, except
that the task must be reset to its initial state in order to run again.
If an RTOS supports dynamic creation and deletion of tasks (see the next
article), this implies another possible task state: “deleted”.
Hardware Interrupt
A hardware interrupt is an electronic alerting signal sent to the processor from an
external device, like a disk controller or an external peripheral. For example, when
we press a key on the keyboard or move the mouse, they trigger hardware interrupts
which cause the processor to read the keystroke or mouse position.
Software Interrupt
A software interrupt is caused either by an exceptional condition or a special
instruction in the instruction set which causes an interrupt when it is executed by the
processor. For example, if the processor's arithmetic logic unit runs a command to
divide a number by zero, to cause a divide-by-zero exception, thus causing the
computer to abandon the calculation or display an error message. Software interrupt
instructions work similar to subroutine calls.
What is Polling?
The state of continuous monitoring is known as polling. The microcontroller keeps
checking the status of other devices; and while doing so, it does no other operation
and consumes all its processing time for monitoring. This problem can be addressed
by using interrupts.
In the interrupt method, the controller responds only when an interruption occurs.
Thus, the controller is not required to regularly monitor the status (flags, signals etc.)
of interfaced and inbuilt devices.
Interrupts v/s Polling
Here is an analogy that differentiates an interrupt from polling −
Interrupt Polling
An interrupt is like a shopkeeper. If one The polling method is like a salesperson. The
needs a service or product, he goes to salesman goes from door to door while
him and apprises him of his needs. In requesting to buy a product or service.
case of interrupts, when the flags or Similarly, the controller keeps monitoring the
signals are received, they notify the flags or signals one by one for all devices and
controller that they need to be serviced. provides service to whichever component that
needs its service.
Interrupt Service Routine
For every interrupt, there must be an interrupt service routine (ISR), or interrupt
handler. When an interrupt occurs, the microcontroller runs the interrupt service
routine. For every interrupt, there is a fixed location in memory that holds the
address of its interrupt service routine, ISR. The table of memory locations set aside
to hold the addresses of ISRs is called as the Interrupt Vector Table.
Reset 0000 9
When the reset pin is activated, the 8051 jumps to the address location 0000.
This is power-up reset.
Two interrupts are set aside for the timers: one for timer 0 and one for timer 1.
Memory locations are 000BH and 001BH respectively in the interrupt vector
table.
Two interrupts are set aside for hardware external interrupts. Pin no. 12 and
Pin no. 13 in Port 3 are for the external hardware interrupts INT0 and INT1,
respectively. Memory locations are 0003H and 0013H respectively in the
interrupt vector table.
Serial communication has a single interrupt that belongs to both receive and
transmit. Memory location 0023H belongs to this interrupt.
If the interrupt source is still asserted Edge-triggered interrupt modules can be acted
when the firmware interrupt handler immediately, no matter how the interrupt source
handles the interrupt, the interrupt behaves.
module will regenerate the interrupt,
causing the interrupt handler to be
invoked again.
Priority Inversion
Priority inversion is a operating system scenario in which a higher priority process is
preempted by a lower priority process. This implies the inversion of the priorities of
the two processes.
A system malfunction may occur if a high priority process is not provided the required
resources.
Priority inversion may also lead to implementation of corrective measures. These may
include the resetting of the entire system.
The performance of the system can be reduces due to priority inversion. This may
happen because it is imperative for higher priority tasks to execute promptly.
System responsiveness decreases as high priority tasks may have strict time
constraints or real time response guarantees.
Sometimes there is no harm caused by priority inversion as the late execution of the
high priority process is not noticed by the system.
Priority Ceiling
All of the resources are assigned a priority that is equal to the highest priority
of any task that may attempt to claim them. This helps in avoiding priority
inversion.
Disabling Interrupts
There are only two priorities in this case i.e. interrupts disabled and
preemptible. So priority inversion is impossible as there is no third option.
Priority Inheritance
This solution temporarily elevates the priority of the low priority task that is
executing to the highest priority task that needs the resource. This means that
medium priority tasks cannot intervene and lead to priority inversion.
No blocking
Priority inversion can be avoided by avoiding blocking as the low priority task
blocks the high priority task.
Random boosting
The priority of the ready tasks can be randomly boosted until they exit the
critical section.
Priority Inheritance Protocol (PIP) in
Synchronization
Last Updated : 25 May, 2020
Read
Discuss
Prerequisite – Introduction of Process Synchronization
Priority Inheritance Protocol (PIP) is a technique which is used for sharing critical
resources among different tasks. This allows the sharing of critical resources among
different without the occurrence of unbounded priority inversions.
Basic Concept of PIP :
The basic concept of PIP is that when a task goes through priority inversion, the
priority of the lower priority task which has the critical resource is increased by the
priority inheritance mechanism. It allows this task to use the critical resource as early
as possible without going through the preemption. It avoids the unbounded priority
inversion.
Working of PIP :
When several tasks are waiting for the same critical resource, the task which is
currently holding this critical resource is given the highest priority among all the
tasks which are waiting for the same critical resource.
Now after the lower priority task having the critical resource is given the highest
priority then the intermediate priority tasks can not preempt this task. This helps in
avoiding the unbounded priority inversion.
When the task which is given the highest priority among all tasks, finishes the job
and releases the critical resource then it gets back to its original priority value
(which may be less or equal).
If a task is holding multiple critical resources then after releasing one critical
resource it can not go back to it original priority value. In this case it inherits the
highest priority among all tasks waiting for the same critical resource.
If the critical resource is free then
allocate the resource
If the critical resource is held by higher priority task then
wait for the resource
If the critical resource is held by lower priority task
{
lower priority task is provided the highest priority
other tasks wait for the resource
}
Advantages of PIP :
Priority Inheritance protocol has the following advantages:
It allows the different priority tasks to share the critical resources.
The most prominent advantage with Priority Inheritance Protocol is that it avoids
the unbounded priority inversion.
Disadvantages of PIP :
Priority Inheritance Protocol has two major problems which may occur:
Deadlock –
There is possibility of deadlock in the priority inheritance protocol.
For example, there are two tasks T1 and T2. Suppose T1 has the higher priority than
T2. T2 starts running first and holds the critical resource CR2.
After that, T1 arrives and preempts T2. T1 holds critical resource CR1 and also tries
to hold CR2 which is held by T2. Now T1 blocks and T2 inherits the priority of
T1 according to PIP. T2 starts execution and now T2 tries to hold CR1 which is held
by T1.
Thus, both T1 and T2 are deadlocked.
Chain Blocking –
When a task goes through priority inversion each time it needs a resource then this
process is called chain blocking.
For example, there are two tasks T1 and T2. Suppose T1 has the higher priority than
T2. T2 holds the critical resource CR1 and CR2. T1 arrives and requests for CR1.
T2 undergoes the priority inversion according to PIP.
Now, T1 request CR2, again T2 goes for priority inversion according to PIP.
Hence, multiple priority inversion to hold the critical resource leads to chain
blocking.
Priority inversion
Priority inversion occurs when a high-priority task is forced to wait for the release of a
shared resource owned by a lower-priority task. The two types of priority inversion,
bounded and unbounded, occur when two tasks attempt to access a single shared
resource. A shared resource can be anything that must be used by two or more tasks in
a mutually exclusive fashion. The period of time that a task has a lock on a shared
resource is called the task's critical section or critical region.
Figure 4: Deadlock
Deadlock
Deadlock , shown in Figure 4, is a special case of nested resource locks, in which a
circular chain of tasks waiting for resources prevents all the tasks in the chain from
executing.2 Deadlocked tasks can have potentially fatal consequences for the application.
Suppose Task A is waiting for a resource held by Task B, while Task B is waiting for a
resource held by Task C, which is waiting for a resource held by Task A. None of the
three tasks is able to acquire the resource it needs to resume execution, so the
application is deadlocked.
1. Task 3 is given control of the processor and begins executing. The task requests
Resource A.
2. Task 3 acquires ownership of Resource A and begins executing its critical region.
3. Task 3 is preempted by Task 2, a higher-priority task. Task 2 requests ownership of
Resource B.
4. Task 2 is granted ownership of Resource B and begins executing its critical region.
The task requests ownership of Resource A, which is owned by Task 3.
5. Task 3 is hoisted to a priority above Task 2 and resumes executing its critical region.
6. Task 3 is preempted by Task 1, a higher-priority task.
Task 1 requests Resource B, which is owned by Task 2.
7. Task 2 is hoisted to a priority above Task 1. However, Task 2 still can't execute
because it must wait for Resource A, which is owned by Task 3.
Task 3 is hoisted to a priority above Task 2 and continues executing its critical
region.
8. Task 3 releases Resource A and is lowered back to its original priority.
Task 2 acquires ownership of Resource A and resumes executing its critical region.
9. Task 2 releases Resource A and then releases Resource B. The task is lowered back to
its original priority.
Task 1 acquires ownership of Resource B and begins executing its critical region.
10. Task 1 releases Resource B and continues executing normally.
11. Task 1 finishes executing. Task 2 resumes and continues executing normally.
12. Task 2 finishes executing. Task 3 resumes and continues executing normally.
13. Task 3 finishes executing.
1. Task L is given control of the processor and begins executing. Task L requests
Resource A.
2. Task L acquires ownership of Resource A and begins executing its critical region.
Task L requests Resource B.
3. Task L acquires ownership of Resource B and continues executing its critical region.
4. Task L is preempted by Task H, a higher-priority task.
Task H requests ownership of Resource A, which is owned by Task L.
5. Task L is hoisted above Task H and continues executing its critical region.
6. Task L releases Resource A even though it was acquired before Resource B.
Task L is lowered to its original priority level.
Task H acquires Resource A and begins executing its critical region.
Note that low-priority Task L no longer prevents Task H from running, even though
Task L still owns Resource B.
7. Task H releases Resource A and continues executing normally.
8. Task H finishes executing and Task L continues executing its critical region.
9. Task L releases Resource B and continues executing normally.
10. Task L finishes executing.
In Figure 8, Task L releases its resources in the same order they were acquired, which
most priority inheritance implementations wouldn't allow. Upon releasing Resource A,
Task L drops to its original priority level. This allows Task H to acquire Resource A,
ending the priority inversion. After Task H has released the resource and stopped
executing, Task L can continue executing with Resource B, on which it has an
uncontested lock. If Task L had been required to release Resource B before releasing
Resource A, Task H would have been prevented from running until Task L had released
both resources. This would have unnecessarily lengthened the duration of the bounded
priority inversion.
1. Task 3 is given control of the processor and begins executing. Task 3 requests
Resource A.
2. Task 3 acquires ownership of Resource A and begins executing its critical region.
Task 3 requests Resource B.
3. Task 3 acquires ownership of Resource B and continues executing its critical region.
4. Task 3 is preempted by Task 2, a higher-priority task.
Task 2 requests ownership of Resource A, which is owned by Task 3.
5. Task 3 is hoisted above Task 2 and continues executing its critical region.
6. Task 3 is preempted by Task 1, a higher-priority task.
Task 1 requests Resource B, which is owned by Task 3.
7. Task 3 is hoisted above Task 1 and continues executing its critical region.
8. Task 3 releases Resource A and continues executing with Resource B.
Note that Task 3 is not dropped to either its previous priority or its original priority.
To do so would immediately produce a priority inversion that requires Task 3 to be
hoisted above Task 1 because Task 3 still owns Resource B.
9. Task 3 releases Resource B and is lowered to its original priority level.
Task 1 acquires Resource B and continues executing its critical region.
10. Task 1 releases Resource B and continues executing normally.
11. Task 1 finishes executing and Task 2 acquires Resource A. Task 2 begins executing its
critical region.
12. Task 2 releases Resource A and continues executing normally.
13. Task 2 finishes executing and Task 3 continues executing normally.
14. Task 3 finishes executing.
The difficulty of implementing locks that aren't properly nested becomes apparent when
three tasks compete for two resources, as seen in Figure 9. When Resource A is released
at Time 8, low-priority Task 3 remains hoisted to the highest priority. An improperly
designed priority inheritance protocol would lower Task 3 to its original priority level,
which was the task's priority before acquiring Resource A. Task 3 would then have to be
immediately hoisted above Task 1 to avoid a priority inversion, because of the
contention for access to Resource B. Unbounded priority inversion could occur while Task
3 is momentarily lowered. A medium-priority task could preempt Task 3, extending the
priority inversion indefinitely.
The example in Figure 8 shows why it's sometimes desirable to release nested resources
“out of order,” or not the reverse of the order in which they were acquired. Although
such a capability is clearly advantageous, many implementations of the priority
inheritance protocol only support sequentially nested resource locks.
The example in Figure 9 helps show why it's more difficult to implement priority
inheritance while allowing resources to be released in any order. If a task owns multiple
shared resources and has been hoisted several times, care must be taken when the task
releases those resources. The task's priority must be adjusted to the appropriate level.
Failure to do so may result in unbounded priority inversion.
Avoid inversion
The best strategy for solving priority inversion is to design the system so that inversion
can't occur. Although priority ceilings and priority inheritance both prevent unbounded
priority inversion, neither protocol prevents bounded priority inversion. Priority inversion,
whether bounded or not, is inherently a contradiction. You don't want to have a high-
priority task wait for a low-priority task that holds a shared resource.
Prior to implementing an application, examine its overall design. If possible, avoid
sharing resources between tasks at all. If no resources are shared, priority inversion is
precluded.
If several tasks do use the same resource, consider combining them into a single task.
The sub-tasks can access the resource through a state machine in the combined task
without fear of priority inversion. Unless the competing sub-tasks are fairly simple,
however, the state machine might be too complex to justify.
Another way to prevent priority inversion is to ensure that all tasks that access a
common resource have the same priority. Although one task might still wait while
another task uses the resource, no priority inversion will occur because both tasks have
the same priority. Of course, this only works if the RTOS provides a non-preemptive
mechanism for gracefully switching between tasks of equal priority.
If you can't use any of these techniques to manage shared resources, consider giving a
“server task” sole possession of the resource. The server task can then regulate access
to the resource. When a “client task” needs the resource, it must call upon the server
task to perform the required operations and then wait for the server to respond. The
server task must be at a priority greater than that of the highest-priority client task that
will access the resource. This method of controlling access to a resource is similar to the
priority ceiling protocol and requires static analysis to determine the priority of the
server task. The method relies on RTOS message passing and synchronization services
instead of resource locks and dynamic task-priority adjustments.
Prioritize
Priority inversion is a serious problem that, if allowed to occur, can cause a system to
fail. It's generally simpler to avoid priority inversion than to solve it in software. If
possible, eliminate the need for shared resources altogether, avoiding any chance of
priority inversion. If you can't avoid priority inversion, at least make sure it's bounded.
Unbounded priority inversions can leave high-priority tasks unable to execute, resulting
in application failure. Two common methods of bounding priority inversion are the
priority ceiling protocol and the priority inheritance protocol. Neither protocol is perfect
for all situations. Hence, good analysis and design are always necessary to understand
which solution, or combination of solutions, is needed for your particular application.
The hardware that runs an embedded operating system is usually quite resource-
constrained. Embedded hardware systems are typically quite specific, and it means
that these systems are designed to cover certain tasks due to limited resources.
In this article, you will learn about the embedded operating system with its types and
many other features.
Disadvantages
There are various disadvantages of an embedded operating system. Some of them
are as follows: