Rtos Lec Notes
Rtos Lec Notes
tjwc - 17-Mar-09
2.1
1.1 Introduction
Tasks
PART 1 Real-Time
Applications
PART 2 - Implementation
Hardware
Background/foreground systems
Interrupts vs tasks
Task states
FreeRTOS API
1.6 Synchronisation
tjwc - 17-Mar-09
2.2
Anatomy of an RTOS
RTOS Design Goals
Portability
Minimise code specific to a given
architecture/compiler
Scalability
Make feature-set configurable, so the
same system can be configured for
very small, or large, systems
Hardware interface
Interrupt handling
Task switching
Clock tick implementation
Scheduling
Communication & Synchronisation
Memory Allocation
Timers & Delay Implementation
tjwc - 17-Mar-09
Performance
Low interrupt-level & task-level latency
Rich Feature-set?
Ways to deal with priority-inversion
Deadline scheduling
Rich set of comms & synch primitives
2.3
Interrupts
Simple foreground/background systems
How the RTOS responds to events
Polling vs timer ISR vs ISR
Interrupt latency
Task or interrupt?
RTOS Implementation
Task lists & scheduler
Linked lists vs bit-mapped array
Semaphores
Queues
tjwc - 17-Mar-09
vTaskIncrementTick()
vPortYieldFromTick()
vPreemptiveTick()
prvCheckDelayedTasks()
vTaskDelay()
vTaskSwitchContext()
portSAVE_CONTEXT()
taskYIELD()
xTaskCreate()
vTaskStartScheduler()
xPortStartScheduler
vPortISRStartFirstTask()
xQueueSend()
prvUnlockQueue()
prvLockQueue()
prvCopyQueueData()
xQueueReceive()
2.4
Interrupt processing
tjwc - 17-Mar-09
Timer timeout
I/O request
2.5
Interrupt Priority
Three prioritised ISRs
3
2
1
Background code
Time
Hardware support can implement branch to the correct ISR for each
interrupt
Vectored priority interrupt controller
2.6
Interrupt priority n
Hardware event initiates
computation
ISR n
Cn
Tn
Interrupt
Task
tjwc - 17-Mar-09
Interrupt
n occurs
ISR n
runs
ISR n
returns
Task n
becomes
ready
Task n
runs
Task n
blocks
2.7
Advantages
Simple
More efficient than RTOS
Disadvantages
More computation must be implemented in ISR coding more
complex & difficult to debug
Can't use tasks to simplify & modularise design
tjwc - 17-Mar-09
2.8
BackgroundLoop()
{
for (;;) {
if (device A is ready) [ Service Device A ];
if (device B is ready) [ Service Device B ];
}
}
Timer1_ISR() // device C or D
{
if (device C is ready) [ Service Device C ];
if (device D is ready) [ Service Device D ];
[ update system clock ]
}
DeviceE_ISR()
{
[ Service Device E ]; /*NB polling not needed*/
}
tjwc - 17-Mar-09
2.9
tjwc - 17-Mar-09
2.10
interrupt
occurs
Latency
E Dev ISR
Lower
level
code
Interrupt entry:
Hardware entry
Save lower level context
tjwc - 17-Mar-09
User
Code
Interrupt return:
Restore lower level context
Hardware return
2.11
In real-time systems the deadline for ISR execution is often stricter than
that used in RMA.
Deadlines are specified as a maximum allowed interrupt latency: delay
from the interrupt being raised to the ISR starting
Worst-case interrupt latency Ln for ISR priority n must be explicitly
calculated by considering:
Delay from non-interrupt code to the first ISR
All ISRs of higher priority than n
Interrupt entry & return time
Best-case latency = E
Ln C E
D4
critical
section
length C
ISR 4 R
i m
( D E R)
i n 1
D3
E
ISR 3 R
D2
ISR 2
ISR 2 latency
C
tjwc - 17-Mar-09
2.12
Worst case
latency
tjwc - 17-Mar-09
i n 1
Best case
latency
Real-Time Operating Systems
2.13
tjwc - 17-Mar-09
ISR 2
ISR 2
ISRs
ISR 1
increasing
priority
Tasks
Task 3
Task 2
Task 1
2.14
tjwc - 17-Mar-09
DeviceX_Task
task
latency
DeviceX_ISR
interrupt
latency
total latency of
DeviceX_task
DeviceX_ISR()
{
[ time-critical handler code ]
SemaGiveFromISR(SemaX);
}
DeviceX_Task()
{
for (;;) {
SemaTake(SemaX); /*wait for device*/
[ rest of handler code ]
}
}
2.15
tjwc - 17-Mar-09
2.16
tjwc - 17-Mar-09
2.17
Task
Control
Block
Task
SUSPEND
List
Task
READY
List
Task
DELAYED
List
Task
Stack
tjwc - 17-Mar-09
Task
Control
Block
Task
Control
Block
RTOS Objects
PC
Semaphore
Waiter
List
Semaphore
Control
Block
Real-Time Operating Systems
Registers
PSR
Processor context
Task
Stack
2.18
Possible states:
READY
BLOCKED on timeout (DELAYED)
BLOCKED on EVENT
SUSPENDED
tjwc - 17-Mar-09
2.19
Task Lists
READY List
Need to extract the highest
priority task
SUSPENDED list
At most one EVENT list
EVENT lists
Lists for waiters on semaphores
& other objects
A separate list for each object
Need to extract the highest
priority task
Real-Time Operating Systems
2.20
FreeRTOS Lists
Implement operations
2.21
Item:
ListEnd:
itemvalue
itemvalue
itemvalue
next
next
next
previous
previous
previous
owner
owner
container
container
Event
ListItem
Generic
ListItem
TCB
tjwc - 17-Mar-09
Dummy list
item marks
end & start
of circular
list
2.22
pxp
pxn
itemvalue
itemvalue
next
next
next
previous
previous
previous
owner
owner
owner
Remove(px)
container
container
{
pxn = px->next;
pxp = px->previous;
pxn->previous=pxp;
pxp->next=pxn;
px->container->numberofitems--;
px->container = NULL;/* if px matters */
}
tjwc - 17-Mar-09
container
numberofitems
index
itemvalue
next
previous
2.23
pz
pxn
itemvalue
itemvalue
next
next
next
previous
previous
previous
owner
owner
container
container
InsertAfter(px, pz)
owner
{
pxn = px->next;
container
px->next = pz;
pxn->previous=pz;
pz->next=pxn;
pz->previous=px;
pz->container=px->container;
px->container->numberofitems++;
}
numberofitems
index
itemvalue
next
previous
tjwc - 17-Mar-09
2.24
O(list length)
linear time
pxl->listend
3
10
22
15
22
99
22
MAX
101
2.25
Advantages
Disadvantages
Sorted Insertion operation takes
typical time O(length of list)
Extra pointers are an overhead
2.26
InsertSorted
Depends on length of list and insert position
Worst case scales as number of tasks in system
tjwc - 17-Mar-09
2.27
2.28
tjwc - 17-Mar-09
31
30
29
...
1
0
configMAX_PRIORITIES
Doubly
linked
list
2.29
Optimisation (2)
Task Addition is now much faster, but finding the highest priority
ready task means scanning the array to find highest non-empty
location.
Use extra global variable to store top priority currently in ready list
Highest priority task normally from topReadyPriority list
If this is empty search downwards in array until non-empty list is found
Update uxTopReadyPriority
2.30
MicroC/OS-II uses a
completely different and
clever implementation for all
its priority ordered task lists.
Suppose each task has a
unique priority so tasks
can be identified by their
priority, and the priorities lie in
a small range. We will assume
priority P satisfies: 0 P < 64
Any power of 2 can equally
well be used
One byte stores 8 array
locations
tjwc - 17-Mar-09
2.31
OSRdyTbl
OSRdyTbl
[0]
tjwc - 17-Mar-09
[1]
15 14 13 12 11 10 9
[2]
23 22 21 20 19 18 17 16
[3]
31 30 29 28 27 26 25 24
[4]
39 38 37 35 35 34 33 32
[5]
47 46 45 44 43 42 41 40
[6]
55 54 53 52 51 50 49 48
[7]
63 62 61 60 59 58 57 56
2.32
tjwc - 17-Mar-09
2.33
OSRdyGrp
OSRdyGrp is a
summary byte.
Each bit is the OR of
all the bits in one byte
(row) of OSRdyTbl
This doubles the time
of insert & remove
operations, but they
are still fast.
OSRdyGrp is used to
implement very fast
searching.
tjwc - 17-Mar-09
OSRdyTbl
0
1
2
3
4
5
6
7
2.34
tjwc - 17-Mar-09
255: 11111111
.....
8:
7:
6:
5:
4:
3:
2:
1:
0:
7
...
00001000
3
00000111
2
00000110
2
00000101
2
00000100
2
00000011
1
00000010
1
00000001
0
00000000 not used
76543210
OSUnMapTbl
index
2.35
y = OSUnMapTbl[OSRdyGrp]; //
x = OSUnMapTbl[OSRdyTbl[y]];//
prio = ( y << 3) + x;
//
//
2.36
Advantages
All operations are O(1), and can be very fast if number of
priorities is small
Operation time is independent of number of tasks in lists
Disadvantages
All priorities must be unique
Does not allow round-robin scheduling
2.37
Task lists are basic data structure used to control task scheduling
in an RTOS
All RTOS uses task lists for:
READY list
Delayed task list
Event waiting task lists (semaphores etc)
Suspended Task List
tjwc - 17-Mar-09
2.38
2.39
RTOS Scheduler
After calling the scheduler the context switch code (see later) can
complete the task switch
Scheduler is called from task level as taskYield() (see later)
FreeRTOS uses priority scheduling with round-robin time-slicing for
tasks of equal priority
All this is implemented using generic doubly-linked list package for
compact code
FreeRTOS uses same doubly-linked list package for other purposes
tjwc - 17-Mar-09
2.40
tjwc - 17-Mar-09
Stack top
during
execution
of f2()
f2
Task2
context
f3
f1
Task1
Stack
base
Task1
stack
Task2
Task2
stack
2.42
tjwc - 17-Mar-09
2.43
/* Allocate the memory required by the TCB and stack for the new task.
checking that the allocation was successful. */
pxNewTCB = prvAllocateTCBAndStack( usStackDepth );
if( pxNewTCB != NULL )
{
portSTACK_TYPE *pxTopOfStack;
/* Setup the newly allocated TCB with the initial state of the task. */
FreeRTOS Task
Creation
/* Initialize the TCB stack to look as if the task was already running, but had been interrupted
by the scheduler. The return address is set to the start of the task function. Once the stack
has been initialised the top of stack variable is updated. */
uxCurrentNumberOfTasks++;
if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
{
/* As this is the first task it must also be the current task. pxCurrentTCB = pxNewTCB*/
/* This is the first task to be created so do the preliminary initialisation required.
We will not recover if this call fails, but we will report the failure. */
}
else
{
prvInitialiseTaskLists();
/* If the scheduler is not already running, make this task the current task
if it is the highest priority task to be created so far. */
if( xSchedulerRunning == pdFALSE )
{
if( pxCurrentTCB->uxPriority <= uxPriority )
{
pxCurrentTCB = pxNewTCB;
}
}
FreeRTOS Task
Creation (2)
}
portEXIT_CRITICAL();
} else {
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
if( xReturn == pdPASS ) {
if( ( void * ) pxCreatedTask != NULL ) {
/* If the created task is higher priority than the current task then it should run now. */
}
return xReturn;
FreeRTOS Task
Creation (3)
FreeRTOS Startup
/* Interrupts are turned off here, to ensure a tick does not occur before or
during the call to xPortStartScheduler(). The stacks of the created tasks
contain a status word with interrupts switched on so interrupts will automatically
get re-enabled when the first task starts to run.*/
xSchedulerRunning = pdTRUE;
xTickCount = ( portTickType ) 0;
/*Setting up the timer tick is hardware specific and in the portable interface. */
if( xPortStartScheduler() )
{
/* Should not reach here as if scheduler is running function will not return. */
}
else
{
FreeRTOS Startup
Portable Code
portBASE_TYPE xPortStartScheduler( void )
{
return 0;
portRESTORE_CONTEXT();
Stack top
during
execution
of f2()
Task1
stack
f2
Task2
stack
Task2
context
f3
Task2 stack
top when
suspended
Stack top
on restart
of f3()
Task1
Stack top
when
suspended
Task2
stack
Task2
context
f3
f1
Task2
Task1
context
f2
f1
Stack Task1
base
Task1
stack
1
PC
R0
.
R15
PSW
Stack Task1
base
Task2
CPU context
2.49
tjwc - 17-Mar-09
2.50
Tick interrupt
2.51
pxCurrentTCB
TaskA
TCB
32
registers
R0 (A)
R1 (A)
R30 (A)
R31 (A)
TaskA
Code
LDI R0,0
LDI, R1,1
ADD R0, R1
SREG (A)
RTOS state
PCH (A)
PCL (A)
SPH (A)
SPL (A)
TaskA
data
16 bits
NB AVR has downward-growing stack!
tjwc - 17-Mar-09
TaskA
Stack
8 bits
2.52
32
registers
R0 (A)
R1 (A)
R30 (A)
R31 (A)
Timer ISR
JSR vPortYieldfromTick
PUSH R0
MOV R0, SR
PUSH R0
SREG (A)
PCH (A)
PCL (A)
SPH (A)
SPL (A)
16 bits
tjwc - 17-Mar-09
start of
SAVECONTEXT
macro
TaskA
Stack
TaskA
data
PCL
PCH
8 bits
Real-Time Operating Systems
2.53
32
registers
PCH (A)
SPH (A)
R1 (A)
Timer
ISR
SAVE
R30 (A)
R31 (A)
PCL (A)
SPL (A)
16 bits
TaskA
Stack
TaskA
data
PCL (A)
PCH (A)
PCL (ISR)
PCH (ISR)
R0 (A)
SREG (A)
R1 (A)
.
R31 (A)
PUSHed by
interrupt
PUSHed by
function call
Pushed by
SAVE_CONTEXT()
Copy of SP (A)
tjwc - 17-Mar-09
TaskA TCB
pxCurrentTCB
Real-Time Operating Systems
2.54
At this point the entire context of taskA has been pushed onto
TaskA stack
It can be retrieved later via the stored SP in taskA TCB
The ISR is still executing, using TaskA stack extra items can be
pushed temporarily without harming the stored context any
change in SP now will not affect TaskA stored SP
vTaskIncrementTick() will alter system time and, we assume,
wake up TaskB
TaskB moved to READY list
tjwc - 17-Mar-09
2.55
4: Start of portRESTORE_CONTEXT()
8 bits
32
registers
R1 (A)
MOV SPL,R0
MOV SPH, R1 TaskB
R30 (A)
R31 (A)
PCH
SPH (B)
Timer
ISR
PCL
SPL (B)
16 bits
Copy of SP (B)
tjwc - 17-Mar-09
TaskB TCB
Stack
TaskB
data
PCL (B)
PCH (B)
PCL (ISR)
PCH (ISR)
R0 (B)
SREG (B)
R1 (B)
.
R31 (B)
PUSHed by
interrupt
PUSHed by
function call
Pushed by
SAVE_CONTEXT()
pxCurrentTCB
Real-Time Operating Systems
2.56
5: End of portRESTORE_CONTEXT()
8 bits
32
registers
R0 (B)
R1 (B)
R30 (B)
R31 (B)
SREG (B)
PCH
PCL
SPH (B)
SPL (B)
Timer
ISR
RET
RETI
TaskB
Stack
TaskB
data
PCL (B)
PCH (B)
PCL (ISR)
PCH (ISR)
PUSHed by
interrupt
PUSHed by
function call
16 bits
8 bits
tjwc - 17-Mar-09
2.57
6: Restart of taskB
8 bits
32
registers
R0 (B)
R1 (B)
R30 (B)
R31 (B)
SREG (B)
PCH (B)
PCL (B)
SPH (B)
SPL (B)
Timer
ISR
Final instruction
Of ISR
RET
SUB R0,R1
TaskB
data
TaskB
Stack
16 bits
8 bits
tjwc - 17-Mar-09
2.58
AVR portSAVE_CONTEXT
; interrupts are disabled on entry
; PCH,PCL are pushed onto stack by interrupt
push
r0
;push r0 first to allow SREG to be loaded
in
r0, __SREG_
; r0 := SREG
push
r0
; push SREG
push
r1
clr
r1
; needed since compiler expects 0 in r1
push
r2
Push all
; push r3-r29
other
push
r30
registers
push
r31
lds
r26, pxCurrentTCB ;x := pxCurrentTCB
lds
r27, pxCurrentTCB + 1
in
r0, 0x3d
;r0 := SPL
st
x+, r0
;[x]:=r0, x := x+1
in
r0, 0x3e
;r0 := SPH
st
x+, r0
;[x]:=r0, x := x+1
2.59
tjwc - 17-Mar-09
2.60
The code which saves & restores context is written in assembler &
depends on CPU, and (to a lesser extent) compiler.
The ARM7 port has very convoluted save & restore code because
ARM processor switches to a different IRQ-mode stack while
processing an interrupt. The saved PC must be extracted from this
stack and saved on the Task stack.
ARM code will be shown here with detailed description of how
the ARM stacks are managed during portSAVE_CONTEXT()
Restore operation (not shown here) is very similar but in reverse
tjwc - 17-Mar-09
2.61
TASK A SP
R0
R1
.
R12
SP R13^
LR R14^
PC R15
TaskA
registers
(System
mode)
CPSR
tjwc - 17-Mar-09
IRQ stack
TaskA
Return address
SPSR
2.62
ARM7 portSAVE_CONTEXT()
STMDB
STMDB
NOP
SUB
LDMIA
SP!, {R0}
SP,{SP}^
STMDB
MOV
LDMIA
R0!, {LR}
LR, R0
SP!, {R0}
STMDB
NOP
SUB
MRS
STMDB
LR,{R0-LR}^
/* Push all the system mode registers onto the task stack*/
LDR
LDR
STMDB
R0, =ulCriticalNesting
R0, [R0]
LR!, {R0}
LDR
LDR
STR
R0, =pxCurrentTCB
R1, [R0]
LR, [R1]
SP, SP, #4
SP!,{R0}
tjwc - 17-Mar-09
2.63
SP!, {R0}
STMDB SP,{SP}^
NOP
SUB
SP, SP, #4
LDMIA SP!,{R0}
tjwc - 17-Mar-09
- needed because of
2.64
tjwc - 17-Mar-09
2.65
tjwc - 17-Mar-09
2.66
tjwc - 17-Mar-09
2.67
FreeRTOS
tasks.c
list.c
Core list package
queue.c
Queue package
Portable
Arm-Keil port
port.c task-level
portable code
portisr.c ISR level
portable code
portmacro.h portable
macro function definitions
tjwc - 17-Mar-09
Include
tasks.h interface to tasks.c
list.h interface to lists.c
queue.h interface to queue.c
FreeRTOS.h includes:
projdefs.h basic definitions
FreeRTOSconfig.h
App-specific definitions
2.68
Eventlist
Genericlist
READY
no
ReadyList
Waiting on Queue
DelayedTaskList
Waiting on Queue
SuspendedTaskList
Delayed
no
DelayedTaskList
Suspended
no
SuspendedTaskList
xTicksToWait = portMAX_DELAY
=> no timeout
tjwc - 17-Mar-09
2.69
3. Call Scheduler
4. Restore selected task context
5. Return from interrupt to selected task
tjwc - 17-Mar-09
2.70
Clock-tick operation
tjwc - 17-Mar-09
2.71
T0IR = portTIMER_MATCH_ISR_BIT;
VICVectAddr = portCLEAR_VIC_INTERRUPT;
/* Restore the context of the highest priority task that is ready to run. */
}
portRESTORE_CONTEXT();
tjwc - 17-Mar-09
2.72
vTaskSuspendAll()
xTaskResumeAll()
tjwc - 17-Mar-09
2.73
pxReadyTasksLists[0]
pxReadyTasksLists[1]
pxReadyTasksLists[2]
.
tjwc - 17-Mar-09
Ready Queue:
Array of task lists
indexed by task priority
See prvAddTaskToReadyQueue()
2.74
Normal
Case
}
#endif
#define prvCheckDelayedTasks()
{
register tskTCB *pxTCB;
\
\
\
\
while ( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY(
\
pxDelayedTaskList ) ) != NULL )
\
{
\
if(xTickCount < listGET_LIST_ITEM_VALUE(&(pxTCB->xGenericListItem) ) ) \
{
\
break; /*this item and all after will wake up in the future, so exit */ \
}
\
vListRemove( &( pxTCB->xGenericListItem ) );/*remove from delayed task list*/\
/* Is the task waiting on an event also? */
\
if( pxTCB->xEventListItem.pvContainer )
\
{
\
/* if so remove it from the event waiters list as well
\
vListRemove( &( pxTCB->xEventListItem ) );
\
}
\
/* add task to ready queue for possible scheduling */
\
prvAddTaskToReadyQueue( pxTCB );
\
}
\
}
If ( xTickCount == ( portTickType ) 0 )
{
xList *pxTemp;
pxTemp = pxDelayedTaskList;
pxDelayedTaskList = pxOverflowDelayedTaskList;
pxOverflowDelayedTaskList = pxTemp;
tjwc - 17-Mar-09
2.77
#if ( INCLUDE_vTaskDelay == 1 )
if( !xAlreadyYielded )
{
taskYIELD();
}
#endif
A task that is removed from the event list while the scheduler is
suspended will not get placed in the ready list or removed from the
blocked list until the schedule is resumed. This task cannot be in an
event list as it is the currently executing task.
/* Wake time has overflowed. Place this item in the overflow list. */
else
{
NB TaskSuspendAll() increments
uxSchedulerSuspended and does nothing else!
portENTER_CRITICAL();
--uxSchedulerSuspended;
the scheduler has been resumed it is safe to move all the pending
ready tasks from this list into their appropriate ready list.
}
portEXIT_CRITICAL();
return xAlreadyYielded;
2.82
2.83
tjwc - 17-Mar-09
2.84
tjwc - 17-Mar-09
2.85
tjwc - 17-Mar-09
2.86
Objects considered:
Semaphores
Message Queues
tjwc - 17-Mar-09
2.87
Semaphore Implementation
Semaphore timeouts
A Taking task can specify optional timeout to be used if it blocks
Waking from timeout returns from Take operation with timeout return value
tjwc - 17-Mar-09
2.88
Each arrow
corresponds to
some semaphore
code inside
SemaGive() or
SemaTake() which
must execute.
2a is made up of
SemaGive() from
signalling task +
SemaTake() from
unblocked task
2b is made up of
clock interrupt code
+ SemaTake() from
unblocked task
tjwc - 17-Mar-09
Task not
waiting
(1) Task
waits on
semaphore
(3) Task is
scheduled
to run
Task
waiting
(2b)
Timeout
ISR
(2a)
Signal
Task is
ready to
run &
re-starting
2.89
tjwc - 17-Mar-09
2.90
2.91
if necessary*/
tjwc - 17-Mar-09
2.92
The size of the return code could be shorter than an int to reduce TCB size
on 8-bit systems. For simplicity this is ignored here
The semaphore count could be one or two bytes only to save space
in the SCB.
If there is any possibility of semaphore count overflow this should be
detected by the SemaGive() API function and result in an error code returned
Not implemented, for simplicity, here.
tjwc - 17-Mar-09
2.93
FreeRTOS Semaphores
tjwc - 17-Mar-09
2.94
tjwc - 17-Mar-09
2.95
Each arrow
corresponds to some
code inside
QueueSend() and/or
QueueReceive() which
must execute.
2Sa is made up of
QueueReceive() from
signalling task
2Sb is made up of
clock interrupt code
QueueSend() from
unblocked task
2S is followed by 3S,
in which QueueSend()
returns
tjwc - 17-Mar-09
Task
waiting
(2Sb,2Rb)
Timeout
(3S, 3R) Task
is scheduled
to run
(2Sa) Receive
(2Ra) Send
Task is
ready to
run &
re-starting
2.96
Simple Pseudocode
xQueueSend(message)
This code works, but has a
{
[ enter critical section ]
very long critical section which
if ( [ queue is full ] ) {
disables interrupts. Alternative:
if (xTicksToWait > 0) {
use separate queue-locks to
[ delete task from ready list ]
protect queue buffer from
1S
[ add task to queue event waiter list ]
interrupts
[ add task to delayed tasks list ]
taskYIELD()
}
}
taskYield() will result in task
if [ queue is full ] {
switch since current task is no
[ exit critical section ]
longer READY
[
return
error
]
3S
} else { /*there is room on queue*/
[ copy message to queue ]
[ update queue pointers ]
2Ra [ wake up the highest priority receiving task ]
}
[ exit critical section ]
[ return OK ]
}
tjwc - 17-Mar-09
2.97
Analysis
2.98
Message FIFO
signed portCHAR *pcWriteTo; /*< Points to the free next place in the storage area. */
signed portCHAR *pcReadFrom; /*< Points to the last place that a queued item was read from.*/
blocked
priority
blocked
priority
Queue Sizes
Locks
Queue Locks
tjwc - 17-Mar-09
2.100
xQUEUE
Task list
Task list
pcHead
pcReadFrom
pcWriteTo
pcTail
uxMessagesWaiting
uxLength
uxItemSize
xTxLock
xTasksWaitingToReceive
xRxLock
xTasksWaitingToSend
3
items
in
queue
>queueUNLOCKED+1
queueUNLOCKED+1
queueUNLOCKED
Real-Time Operating Systems
2.101
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
prvUnlockQueue() - 1
While the queue is locked ISR queue operations
may change data buffers and the queue pointers,
but not the event lists.
This function unlocks the queue, and alters event
queues waking up (one) task if necessary.
static signed portBASE_TYPE prvUnlockQueue(xQueueHandle pxQueue)
{
signed portBASE_TYPE xYieldRequired = pdFALSE;
/* THIS FUNCTION MUST BE CALLED
WITH THE SCHEDULER SUSPENDED. */
[ unlock Tx Queue, waking a receive task if necessary ]
[ unlock RxQueue, waking a send task if necessary ]
taskENTER_CRITICAL();
{
--( pxQueue->xTxLock ); /*unlock the queue */
/* Data was posted while the queue was locked. Are any tasks
blocked waiting for data to become available? */
/* Tasks that are removed from the event list will get added to
the pending ready list as the scheduler is still suspended. */
if( xTaskRemoveFromEventList(
&( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
prvUnlockQueue() - 2
}
} /* end if !listLIST_IS_EMPTY()*/ Code to process outstanding
Tx operations
}
taskEXIT_CRITICAL();
a Queue
/* There is room in the queue, copy the data into the queue. */
prvCopyQueueData( pxQueue, pvItemToQueue );
xReturn = pdPASS;
}
else
{
xReturn = errQUEUE_FULL;
}
}
taskEXIT_CRITICAL();
XQueueSend() - 2
Send a message from a task to
a Queue
/* Resume the scheduler - making ready any tasks that were woken
by an event while the scheduler was locked. Resuming the
scheduler may cause a yield, in which case there is no point
yielding again here. */
if( !xTaskResumeAll() )
{
taskYIELD();
}
3S
}
else
{
XQueueSend() - 3
/* Resume the scheduler - making ready any tasks that were woken
by an event while the scheduler was locked. */
}
}
xTaskResumeAll();
return xReturn;
FreeRTOS QueueReceive()
tjwc - 17-Mar-09
2.108
taskENTER_CRITICAL();
{
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 ) {
pxQueue->pcReadFrom += pxQueue->uxItemSize;
if( pxQueue->pcReadFrom >= pxQueue->pcTail )
{
pxQueue->pcReadFrom = pxQueue->pcHead;
}
--( pxQueue->uxMessagesWaiting );
memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom,
( unsigned ) pxQueue->uxItemSize );
}
else
{
xReturn = pdFAIL;
}
}
taskEXIT_CRITICAL();
XQueueReceive() - 2
return xReturn;
XQueueReceive() - 3
Task receive a message from a
queue
return xTaskPreviouslyWoken;
/* If the queue is locked we do not alter the event list. This will
be done when the queue is unlocked later. */
if( pxQueue->xTxLock == queueUNLOCKED )
{
/* We only want to wake one task per ISR, so check that a task has
not already been woken. */
if ( !xTaskPreviouslyWoken )
{
if ( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
if ( xTaskRemoveFromEventList(&( pxQueue->xTasksWaitingToReceive ))
!= pdFALSE )
{
return pdTRUE;
}
} else /* the queue is locked */
{
/* Increment the lock count so the task that unlocks the queue
knows that data was posted while it was locked. */
++( pxQueue->xTxLock );
tjwc - 17-Mar-09
2.114
2.115
Portability
Minimise code specific to a given architecture/compiler
Scalability
Make feature-set configurable, so the same system can be
configured for very small, or large, systems
Performance
Low interrupt-level & task-level latency
Interested in maximum limit, not average
Rich Feature-set?
Ways to deal with priority-inversion
Deadline scheduling
Rich set of comms & synch primitives
tjwc - 17-Mar-09
2.116
Task suspend
Message Queue write from ISR
TaskDelay()
TaskDelayUntil()
2.117
Write RTOS in C
Use C preprocessor to switch
features on/off
Use C macros for efficient
implementation of hardwaredependent primitives
tjwc - 17-Mar-09
2.118
Analysis
Real-time introduces a wide variety of
problems
RMA is best quantitative technique to
ensure correctness- works with
prioritised system
Liveness problems are a big issue in
real-time systems which can only be
addressed through careful attention at
application design stage
Deadlock crucial but straightforward
Starvation easy to mend but more
difficult to detect
Livelock even more difficult to detect
Priority inversion must be fully
understood. A variety of RTOSspecific solutions are available
tjwc - 17-Mar-09
Implementation
RTOS implementation is still relatively
immature, with competing methods for
the various internal functions
Unlike other OS, scalability is
essential, with ability to run on both
very resource-constrained systems
and relatively large systems a merit
To achieve this RTOS must be
configurable with code size dependent
on selected feature-set
RTOS can relatively easily be ported
to new architectures port depends
on details of CPU, C compiler, and
assembler.
It is sometimes possible to use inline
assembly code embedded in C
functions and avoid using a separate
assembler
2.119
Exam
Types of question:
Analysis of given RTS
RMA & extended RMA
liveness analysis
RTOS implementation
2.120