• No results found

Freertos Arm Cortex

N/A
N/A
Protected

Academic year: 2021

Share "Freertos Arm Cortex"

Copied!
344
0
0

Loading.... (view fulltext now)

Full text

(1)

ARM Cortex

Embedded System Multitasking

Programming Using

FreeRTOS

Andrew Eliasz

Feb 2013

(2)

FreeRTOS

Overview

(3)

FreeRTOS - The Who

● FreeRTOS was developed by a “very clever” software engineer Richard Barry ● As it says on the Lulu website who publish his books

● Richard Barry graduated with 1st Class Honors in Computing for Real Time

Systems.

● He's been directly involved in the start up of several companies, primarily

working in the industrial automation and aerospace and simulation markets.

● Barry is currently a director of Real Time Engineers Ltd. (owners of FreeRTOS)

and

● Head of Innovation at Wittenstein High Integrity Systems.

● Interestingly the only books on developing with FreeRTOS are those written by

Richard

● In this respect FreeRTOS has something in common with Micriums' uCOS operating

system

● The books on developing with uCOS II / uCOS III are written by the developer of

uCOS - Jean Labrosse

● Both FreeRTOS and uCOS have API (Application Programming Interface)s that are

(4)

FreeRTOS - Some claims

● Aims to:

● "Provide a free product that surpasses the quality and service demanded by

users of commercial alternatives"

● FreeRTOSTM is a market leading RTOS from Real Time Engineers Ltd. that supports

33 architectures and received 103000 downloads during 2012.

● It is professionally developed, strictly quality controlled, robust, supported, and free to

embed in commercial products without any requirement to expose your proprietary source code

● FreeRTOS has become the de facto standard RTOS for microcontrollers by removing

common objections to using free software, and in so doing, providing a truly compelling free software model

● Question: Which other operating systems use the FreeRTOS API ?

● Question: Are there any embedded operating systems that use the Posix API ( or a

subset of the Posix API ) ?

(5)

FreeRTOS - More Technical Claims

● FreeRTOS never performs a non-deterministic operation, such as walking a linked

list, from inside a critical section or interrupt

● Question: What does this mean ?

● FreeRTOS uses an efficient software timer implementation that does not use any

CPU time unless a timer actually needs servicing

● Software timers do not contain variables that need to be counted down to zero ● Question: Timers are, essentially, counters that generate a time even when the

timer overflows/reaches 0 [depending on whether it counts up or down]

● Lists of Blocked (pended) tasks do not require time consuming periodic servicing. ● Question: What does this mean ?

● The FreeRTOS queue usage model manages to combine simplicity with flexibility (in

a tiny code size) - attributes that are normally mutually exclusive

● Question: How is this possible ?

● FreeRTOS queues are base primitives on-top of which other communication and

synchronisation primitives are build

● The code re-use opportunities that result reduce overall code size

This, in turn, assists testing and helps ensure robustnessQuestion: How would you test this claim ?

(6)

FreeRTOS - Technology Highlights

(7)

Wikipedia - FreeRTOS Description

FreeRTOS provides methods for multiple threads or tasks, mutexes,

semaphores and software timers.

A tick-less mode is provided for low power applications.

Thread priorities are supported.

In addition there are four schemes of memory allocation provided

Allocate only

Allocate and free - using simple but fast, algorithm

A more complex fast allocate and free algorithm with memory

coalescence;

A C library supporting allocate and free with some mutual exclusion

protection

FreeRTOS has none of the features typical of operating systems such as

Linux or Microsoft Windows i.e. no support for

Device drivers

(8)

Wikipedia - FreeRTOS Description ctd.

FreeRTOS can be thought of as a 'thread library' rather than an 'operating

system'

Command line interface and POSIX like IO abstraction add-ons are

available

FreeRTOS+IO provides a Linux/POSIX like

open(), read(),

write(), ioctl() type interface to peripheral driver libraries

VxWorks from Wind River Systems has a proprietary API and also

supports a Posix API (i.e. the software was not designed with a Posix

API in mind)

The Rowebots RTOS was implemented with a Posix API in mind

FreeRTOS implements multiple threads by

Having the host program call a thread tick method at regular short

intervals

The thread tick method switches tasks depending on priority and a

round-robin scheduling scheme

Switching is driven via a hardware timer interrupt

(9)

Mastering FreeRTOS - Plan of Action

● FreeRTOS, although a tiny operating system, is far from simple

● Mostly written in generic C code, but, also some platform specific C and assembler ● This course is focused on ARM Cortex M3/M4 processors

● How much of the M3/M4 processor architecture do you need to understand ? ● Which compilers and IDEs can you use for developing applications ? - e.g.

– Keil (now owned by ARM) IDE – IAR

Code Sourcery (Lite / commercial Eclipse based) - compiler is GCCCode Red (widely favoured by NXP)

● Which drivers and protocols stacks will you be using ?

– Open source ? – Commercial ?

Developed in house ?

● Complex systems and protocols

– USB ?

Ethernet and TCP/IP ?

– CAN (Controller Area Network) ? – Rich GUIs ?

(10)

Mastering FreeRTOS - Plan of Action - ctd.

● Start off with something that works e.g.

● Evaluation board approximating the capabilities your project will need and for

which a port of FreeRTOS exists and for which there are some demonstrator programs that work

– Ideally there is a port that uses the IDE you will be using in your project

● Evaluate and organise the available documentation and forum discussions ● The published FreeRTOS books are good, but only take you so far

● Areas of “obscurity”

Architecture specific details

Complex libraries and peripherals are not part of the package

● USB ? ● TCP/IP ?

● LCD graphics libraries ? ● CAN bus support ?

Libraries supplied with your IDE and Microcontroller vendor ?

● Have these libraries been integrated with FreeRTOS ? ● If not ... then who will integrate them ?

(11)

FreeRTOS - Analysis and Design Issues

● How to progress from initial requirements analysis and design to code specification

and implementation

● UML based requirements analysis and desing

● Hatley-Pirbhai or Ward-Mellor analysis and design ● How might you realise an object oriented design in C ? ● How is code to be “split up into modules”

● How is code to be partitioned into tasks ? ● Testing and integration

● MISRA guidelines ● Unit testing

● Code tracing and debugging

● How will the embedded systems targets be upgraded ? ● Patches and Bug fixes ?

● Enhancements ?

(12)

CMSIS-RTOS Standard

Based on

ARM Technical Documentation

as well as a Hitex Presentation

(13)

CMSIS

CMSIS represents an attempt by ARM to standardise many aspects

of device driver and associated library implementation across multiple

processors and multiple IDEs

The areas of standardization includes:

Hardware Abstraction Layer (HAL) for Cortex-M processor

registers

Standardized definitions for the SysTick, NVIC, System

Control Block registers, MPU registers, and core access

functions.

Standardized system exception namesso that RTOS and

middleware components can use system exceptions without

running into compatibility issues.

Standardized methods to organize header files- to facilitate

learning how to program new Cortex-M microcontroller products

and improve software portability.

(14)

CMSIS - ctd.

Common methods for system initialization to be used by each

MCU vendor e.g.

Standardized

SystemInit() function, provided in each device

driver library, for configuring the clock.

Standardized intrinsic functions - normally used to produce

instructions that cannot be generated by IEC/ISO C

Standardized intrinsic functions, improve software re-usability

and portability

Standardized ways to determine the system clock frequency

through a software variable

SystemFrequency, defined in the device driver. Allows RTOS to

(15)

CMSIS - Versions

● v1 - Core ● v2 - DSP ● v3 - RTOS

(16)

CMSIS - Organisation

The CMSIS follows a layered architecture approach

Core Peripheral Access Layer

Provides name definitions, address definitions, and helper

functions to access core registers and core peripherals.

Device Peripheral Access Layer (MCU specific)

Deals with name definitions, address definitions, and driver

code to access peripherals.

Access Functions for Peripherals (MCU specific and optional)

Implements additional helper functions for peripherals as

(17)

CMSIS - Organisation - ctd.

(18)

CMSIS - RTOS Architecture

Kernel (RTK)

Scheduling

Mutual exclusion

Executive (RTE)

Inter-task communication & synchronisation

Memory management

RTOS

File management System

FAT file system

Networking

E.g. TCP/IP, CAN

Graphical User Interface support

E.g. OpenGL ES, Embedded Qt

(19)

CMSIS Components

The CMSIS consists of the following components:

CMSIS-CORE: provides an interface to Cortex-M0, Cortex-M3,

Cortex-M4, SC000, and SC300 processors and peripheral

registers

CMSIS-DSP: DSP library with over 60 functions in fixed-point

(fractional q7, q15, q31) and single precision floating-point (32-bit)

implementation

CMSIS-RTOS API: standardized programming interface for

real-time operating systems for thread control, resource, and real-time

management

CMSIS-SVD: System View Description XML files that contain the

programmer's view of a complete microcontroller system including

peripherals

The standard is fully scalable across the Cortex-M processor series of

(20)

CMSIS v3 Architecture

(21)

CMSIS - RTOS - Services

(22)

Mutual Exclusion

● Support for mutual exclusion comes from the implementation of mutexes and

(23)

Interthread Communication

● Multithreading interthread communication and synchronisation is provided by the implementation of primitives such as

● Signals

● Message queues ● Mailboxes

(24)

CMSIS - DSP Library

● The CMSIS-DSP library provides functions supporting ● Vector operations ● Matrix computing ● Complex arithmetic ● Filter functions ● Control functions ● PID controller ● Fourier transforms

● Most algorithms are available in floating-point and various fixed-point formats and are

optimized for the Cortex-M series processors.

● The Cortex-M4 processor implementation uses the ARM DSP SIMD (Single

Instruction Multiple Data) instruction set and floating-point hardware

● The CMSIS-DSP library, is written entirely in C

– The source code is provided and the algorithms can be adapted for specific

(25)

CMSIS SVD

The CMSIS-SVD System View Description XML specification

Describes the programmer's view of the microcontroller system

including the peripheral registers

SVD files can be used to create the CMSIS-CORE header files

which will include peripheral register and interrupt definitions.

CMSIS-DVD files can also be used to create peripheral

awareness dialogs for debuggers

ARM provides downloadable SVD files for many devices

(26)

CMSIS v3 Adaptation to some RTOS

(27)

Some RTOSes and IDEs to Consider

RTOSes

Free RTOS

ChibiOS/RT

Keil RTX

IDEs

IAR

Keil

Atollic True Studio

Rowley Associates - Cross Works

(28)

CMSIS - Device Driver Architecture

● For each device, the MCU vendor should provide a header file that pulls-in additional

header files required by the device driver library and the Core Peripheral Access Layer

● Include the file device_family.h into the source code.

● In order to be CMSIS-compliant, the vendor implementation must use the predefined

exception and interrupt constants, core functions, and middleware functions for accessing device peripherals

● CMSIS-compliant device drivers will contain a startup-code file, which will include the

vector table for various supported compilers

● Typical CMSIS-compliant source code files

● device_family.h - the header file defining the device. ● core_cm3.h - the header file defining the device core. ● core_cm3.c - implements core intrinsic functions.

● system_device_family.h - implements device specific interrupt and peripheral

register definitions.

● system_device_family.c - impoements system functions and the initialization

code.

(29)

CMSIS - Device Driver Architecture

(30)

FreeRTOS View on CMSIS-RTOS

http://www.embedded.com/electronics-blogs/industry-comment/ , March 6

2012

While the hardware interface to a Cortex-M core is common across all

Cortex-M microcontrollers, the software interface to an RTOS is different in

every case.

POSIX, a common operating system interface in use for many years, is

generally not regarded as an optimal solution for smaller devices, such

as Cortex-M3 microcontrollers, so will CMSIS be a better choice?

The cynic might say that ARM has such a strong position in the

microcontroller market that, if it put its weight behind it, CMSIS RTOS will be

successful whether it technically merits the success or not.

Ultimately, however, its success (or otherwise) will depend on whether

customers want it.

For customers to want it, they have to see a benefit.

One clear benefit is that of having a single API for a set of two or more

(31)

FreeRTOS View on CMSIS-RTOS

The end-user perspective :

A common interface to multiple RTOS solutions will make software more

portable and facilitate migrating application code between different RTOS

suppliers.

From the engineering point of view, especially for high-volume products, the

selected microcontroller will be the lowest cost and smallest possible for the

task in hand.

The software running on the microcontroller will be trimmed down.

Where space, time, or responsiveness are at a premium, any software

that is not adding value to that application will be removed.

An RTOS abstraction layer will, by its very nature, not add to the RTOS

functionality, but will make the code bigger and slow down the execution

speed.

The RTOS abstraction layer will , therefore, always be a prime

candidate for removal.

A commercial RTOS is a financial investment and it is unlikely that

(32)

FreeRTOS View on CMSIS-RTOS

Open-source RTOS vendor perspective

Because of the financial investment required to select a new commercial

RTOS, CMSIS RTOS compliance will provide more mobility to, and

between, free open-source RTOS products.

Potentially a big benefit to open-source suppliers.

The potential investment made by commercial silicon, RTOS, and

tool vendors in CMSIS-RTOS-compliant infrastructure will be equally

applicable to open-source-compliant products

However, by its very nature, an RTOS abstraction layer will make the

RTOS larger and less responsive.

Counter productive as an RTOS should be designed to be small or

fast (or both).

Using the abstraction layer will not allow the RTOS to be used to its

full potential, or provide the maximum potential benefit to the end

user.

Maybe the abstraction layer will be removed in end products that

(33)

FreeRTOS View on CMSIS-RTOS

Commercial RTOS vendor perspective

The plus points listed above for an open-source RTOS vendor may very

well be negative points for a commercial vendors.

Commercial RTOS vendors invest in their products to differentiate them

in a number of different ways.

Performance, size, price, support, etc. are all attributes used to

position an RTOS.

Anything that homogenizes RTOS offerings in the market, and in so

doing reduces any differentiation gained by technical and/or

marketing investments, makes the RTOS market a tougher market in

which to work.

It may also make future investment harder to justify.

Tools and middleware will become the key differentiator, until they, too

(34)

FreeRTOS View on CMSIS-RTOS

The non-RTOS-affiliated middleware supplier

Supply software that must work with any RTOS their

customers might be using.

Need to provide their own abstraction layer to, and test

with, a number of different RTOS solutions.

Replacing these multiple abstraction layers with a single

abstraction layer is a benefit.

The benefit will only become a reality however if the end

users are actually using CMSIS RTOS in the products

they are designing and shipping.

(35)

FreeRTOS View on CMSIS-RTOS

The microcontroller vendor

Typically, provides software (predominantly drivers) that

must interface with any system their customers are using - a

standard such as CMSIS - RTOS is beneficial especially

when drivers other than those based on a simple model

need to be provided

The tool vendor

Provides products such as execution trace and profiling

tools, as well as kernel aware debugger plug-ins.

Generally such tools do not access the RTOS through

the RTOS's API, so will largely be unaffected.

Also, these tools are predominantly supplied by the

RTOS vendors themselves

Hence unlikely to want their tools to be used with any

(36)

Patterns of Inter-process

Communication and Synchronisation

A Generic Approach

(37)

Rationale

● There are a number of patterns for inter-process / inter-task communication ● These patterns apply to most pre-emptive multi-tasking operating systems

● Knowing these patterns makes it easier to structure code development for a variety

of operating system APIs

● In this course the target OS API is the FreeRTOS API

● The FreeRTOS specific examples and code snippets will be covered in a follow on

section

● The examples in this section will be given in pseudo-code and C.

● The examples will be general in the sense that they will not be targeted at any

particular operating system ( real time or otherwise ).

● From time to time specific operating system API interfaces will be mentioned to

illustrate real world code examples.

● The most important thing is to understand the underlying mechanisms, as well as the

various patterns of programming with the various operating system intertask communication primitives.

(38)

Tasks

● Real time and embedded systems need to be able to handle multiple inputs and

multiple outputs within relatively tight time constraints.

● A practical concurrent design decomposes the application into ● Small

● Sequential ● Schedulable ● program units.

● The design and implementation objective is to do this in such a way that when the

system is multi-tasking the design performance and timing requirements are satisfied.

● A typical RTOS kernel provides ● Task objects

● Task management services

(39)

Definition of a Task

● Formally a task is

● An independent thread of execution

● Competes with other concurrent tasks for processor execution time

● Is schedulable - competes for execution time based on some pre-determined

scheduling algorithm

● Upon creation is given a distinct set of parameters and supporting data

structures

– Name – Unique id

Priority ( if associated with a preemptive scheduler) – Task control block

– Stack

Task routine

● Typically, when a kernel starts,

● It creates its own set of system tasks and ● Allocates a suitable priority to each task

(40)

System Tasks

Typical system tasks include

Startup ( initialisation ) task

Idle task - uses up CPU idle cycles when there is nothing

else to do

Logging task - logs system messages

Exception-handling task

(41)

Finite State Machine Approach to Task Scheduling

A common pattern when designing schedulers is to specify a number

of possible states any given task can be in.

A simple pattern, typical of many pre-emptive scheduling kernels

envisions the following states

Ready state - task eligible to run, but cannot run because a higher

priority task is executing

Blocked state - occurs where the task

Has requested a resource that is not immediately available

Has requested to wait until some event occurs

Has voluntarily delayed itself for some duration

Running state - the task is currently the one with the highest

(42)
(43)

Priority Levels

Where a kernel supports more than one task per priority level

The kernel maintains a task-ready list

One per priority level or

A single combined list

Without blocked states lower priority tasks could not run.

A task can only move to the blocked state by making a blocking

call - requesting that some blocking condition be met.

If higher priority tasks are not designed to block then CPU

starvation may occur

A blocked task remains blocked until the blocking condition is

(44)

Priority Levels

Common blocking conditions include

A semaphore token for which a task is waiting being

released

A message on which a task is waiting arriving in a message

queue

A time delay imposed on the task expiring

When a task becomes unblocked

It will move from the blocked state to the ready state if it is

not the highest priority task

If it is the highest priority task it moves directly to the running

state and preempts the currently running task

The preempted task is itself moved into the appropriate

(45)

Task Creation and Task Management Services

● Typically, a kernel will provide a task-management services API for manipulating

tasks with methods for

● Creating and deleting tasks ● Controlling task scheduling

● Obtaining information about tasks ● Some kernels allow a program to

● First create the task ● Then start the task

● Some kernels provide user-configurable hooks which

● Make it possible to run programmer-supplied functions when some specific

kernel event occurs

● The programmer registers the function with the kernel - by passing in the

corresponding function pointer as one of the arguments to the relevant kernel API function

● Possible kernel events

● When a task is first created

● When a task is suspended and a context switch occurs ● When a task is deleted

(46)

Task Deletion

● Deletion of tasks in embedded applications needs to be thought about. ● An executing task

● Can acquire memory

● Access resources using other kernel objects

● If a task is not deleted correctly its resources may not be released correctly and this

may result in unfortunate system behaviour e.g.

● A task obtains a semaphore to obtain exclusive access to a shared data

structure

● The task is deleted while operating on this data structure ● The abrupt deletion of the task may result in

A corrupt data structure - because the write operation did not complete

An unreleased semaphore - which means that other tasks will not be able to

acquire the resource

– A data structure that is inaccessible - because of the unreleased semaphore

● i.e. the premature deletion of a task can result in memory or resource

(47)

Task Scheduling API Functionality

Many kernels provide an API that permits manual scheduling.

A typical set of operations supported by such an API might include the

following :

Suspend - to suspend a task

Resume - to resume a task

Delay - to delay a task

Restart - to restart a task

GetPriority - to get the priority of the current task

SetPriority - to dynamically set the priority of some task

Preemption lock - to lock out higher priority tasks from preempting

the current task

(48)

Obtaining Task Information

Kernel API Functionality for Obtaining Task Information is useful

e.g. when monitoring or debugging an application

Information typically retrieved includes details such as

The IDs of the installed tasks

The Task Control Block of the current task

The resources owned by the task

The state of the resource

(49)

Varieties of Tasks

A common classification of tasks involves classifying them

as either

Run to completion tasks, or

(50)

Run-to-completion tasks

The pseudocode demonstrating a run-to-completion task might look

as follows

In this example of a run-to-completion task

A high priority task

Initialises and starts up up a collection of tasks associated with

the application and then

Ends itself.

ARunToCompletionTask()

{

InitialisationApplication;

Create a number of infnite loop tasks;

Create required kernel objects/resources;

Delete/Suspend this task

(51)

Infinite Loop Tasks

Infinite loop tasks must include blocking calls if other tasks are to have a

chance of running.

The pseudocode for an infinite loop task might look as follows

The important point to bear in mind with the above examples is that they are

based on a co-operative multi-tasking model

At the highest priority level a task runs to completion or till it voluntarily

makes a blocking call.

InfniteLoopTask()

{

Initialisation steps

Loop Forever

{

body of loop code - includes one or more blocking calls

}

(52)

Intertask Communication

Typical kernel objects for interprocess communication and

synchronisation include

Semaphores

Message queues

Signals

(53)

Semaphores

● Formally - A semaphore is a kernel object that one or more threads of execution

(tasks) can acquire or release for the purposes of synchronisation or mutual exclusion.

● When a semaphore object is created the kernel assigns a data structure - a

semaphore control block (SCB) to it. The kernel also assigns a unique ID, a count value and a task-waiting list.

(54)

Semaphores

Semaphore

A semaphore can be thought of as a key which a task must

have in order to access some resource

If the task can acquire the semaphore then it can access the

resource

If a task cannot acquire the semaphore it must wait till some

other task releases it.

There are two main kinds of semaphore

Binary

(55)

Binary Semaphores

● A binary semaphore can have only two possible values 0 and 1. ● When a semaphore is not held by any task it has the value 1. ● When a task acquires a semaphore its value is set to 0.

● No other task can acquire the semaphore whilst its value is 0.

● A binary semaphore is a global resource - shared by all tasks that need it

● Hence, it is possible for a task other than the task that initially acquired the

semaphore to release the semaphore

● It is the choreography of semaphore usage amongst tasks that makes

(56)

Counting Semaphores

● A counting semaphore can be acquired or released multiple times. It does this via a

counter.

● If the count value is 0 the counting semaphore is in the unavailable state. If the

count is greater than 1 then the semaphore is available.

● When a counting semaphore is created its initial count can be specified.

● In some operating systems the maximum count value can also be specified - i.e. the

counting semaphore is a bounded semaphore ( the count is bounded ). In other operating systems the count may be unbounded.

● Acquiring a counting semaphore reduces the counter value by 1, and releasing the

(57)

Mutual Exclusion Semaphores (Mutexes)

● A mutex is a binary semaphore - that may, in some implementations, have additional

features such as

● Ownership

● Recursive locking ● Task deletion safety

● Priority inversion avoidance protocol

● The mutex can be in one of two states locked (0), or unlocked (1).

● A mutex is initially created in the unlocked state - and can be acquired by a task. ● When a mutex is acquired its state becomes the locked state.

● When a mutex is released (by the task that owns it) its state becomes the

unlocked state.

● [ In some implementations the verbs lock and unlock are used in place of acquire

and release ]

● Ownership

● When a task acquires a mutex it is said to acquire ownership

(58)

Recursive Locking

Recursive locking means that a task that owns a mutex can acquire it

multiple times in the locked state.

Such a mutex is called a recursive mutex.

In some implementation recursive locking may be automatically built into the

mutex , in others it may be a property that can be explicitly enabled.

A recursive mutex permits nesting of attempts to lock the mutex. A

function that acquires the mutex can call another function that can

acquire the mutex again, and can release the mutex just before it

returns.

Task Deletion Safety

Premature task deletion can be avoided by using a task deletion lock when a

task locks and unlocks the mutex.

The task cannot be deleted while it owns the mutex. The mutex is said to

(59)

Priority Inversion Avoidance

● Priority inversion occurs when

● A higher priority task is blocked because it is waiting for a lower priority task to

release a needed mutex, and where

● The lower priority task has itself been preempted by an intermediate level priority

task.

● Effectively the priority of the high priority task has been inverted to that of the low

priority task.

● Protocols associated with mutex implementation have been devised to avoid priority

inversions

● Priority inheritance protocol - the priority of the lower priority task that has

acquired the mutex is raised to the priority level of the task that requested the mutex when inversion happens.

– Once the low priority task releases the mutex its priority reverts to the low

level.

● Ceiling priority protocol - the priority level of the task that acquires the mutex is

automatically set to the highest priority of all possible tasks the might request that mutex when the task acquires the mutex, and

(60)
(61)

Typical Semaphore Operations

Typical semaphore operations are

Creating and deleting a semaphore

Acquiring and releasing a semaphore

Clearing the task-waiting list associated with a semaphore

Obtaining information about a semaphore

Calls for implementing different kinds of semaphores (where a kernel

supports multiple semaphores) may provide extra functionality e.g.

Binary semaphore - specify initial semaphore state and

task-waiting order

Counting semaphore - specify initial semaphore value, bound on

the count and the task-waiting order

Mutex - specify the task-waiting order, enable task deletion safety,

(62)

Semaphore Operations

Deleting a Semaphore

When a semaphore is deleted

Any blocked tasks in the task-waiting list are unblocked and moved

into the ready state ( or into the running state if they are the highest

priority tasks )

Any task attempting to acquire a deleted semaphore returns with an

error message

N.B. - a semaphore should not be deleted if it is acquired.

Acquiring and Releasing Semaphores

Typical ways of acquiring semaphore

Wait forever - task remains blocked until it is able to acquire the

semaphore

Wait with a timeout - task remains blocked until it can acquire the

semaphore, or till the time-out period specified expires ( in which

case the task is placed on the ready list )

Do not wait - if a semaphore token is not available then the task does

not block - it simply returns ( usually returning some value / setting

some variable ) indicating it was not able to acquire the semaphore.

(63)

Semaphore Operations - ctd.

Interrupt Service Routines (ISRs) and Semaphores

ISRs may release binary and counting semaphores.

It is not (in general) meaningful to acquire a binary or counting

semaphore inside an ISR

Locking and unlocking of mutexes inside an ISR is also not meaningful

( and most kernels do not support such an action )

Binary and Counting Semaphores and Mutexes

Any task can release a binary or counting semaphore

A mutex can only be release by the task that acquired it

Clearing Semaphore Task Waiting Lists

Some kernels provide a flush operation for clearing all tasks on a

semaphore task-waiting list.

The flush operation can be used as a mechanism for broadcast ( more

(64)

Thread Rendezvous

A possible use of the flush mechanism

A set of tasks need to finish their particular operations,

and then to block by trying to acquire a common

semaphore that is made unavailable

When the last task has finished its particular operations it

can execute a semaphore flush operation on the common

semaphore

This will free all the tasks waiting on the semaphore's

(65)

Getting Semaphore Information

Needed in monitoring and debugging situations

Typical semaphore information operations are

Show information - provides general information about the

semaphore

Show blocked tasks - gets a list of IDs of tasks blocked on

(66)

Semaphore Usage Patterns

Typical Semaphore Usage Patterns

Wait and signal synchronisation

Multiple task wait and signal synchronisation

Credit tracking synchronisation

Single shared resource access synchronisation

Recursive shared resource access synchronisation

Multiple shared resource access synchronisation

(67)

Wait and Signal Synchronisation

Here two tasks communicate for the purpose of synchronisation

without the exchange of information.

Wait and Signal Synchronisation can be accomplished using a

binary semaphore

Initially the binary semaphore is unavailable ( value = 0 )

The higher priority task (the wait task) runs first

At some point it makes a request for the semaphore

But is blocked because the semaphore is not available

This gives the lower priority task ( the signal task) an

opportunity to run

At some point the lower priority task releases the semaphore

thus

Unblocking the higher priority task which

(68)

Multiple Task Wait and Signal Synchronisation

In this pattern there are several higher priority tasks ( the wait

tasks )

Initially the binary semaphore is unavailable ( value = 0 )

The higher priority tasks (the wait tasks) run first

At some point each makes a request for the semaphore

But is blocked because the semaphore is not

available

This gives the lower priority task ( the signal task) an

opportunity to run

At some point the lower priority task flushes the semaphore

thus

Unblocking the higher priority tasks which then pre-empt

(69)

Credit Tracking Synchronisation

● In this pattern - the signaling task executes at a higher rate than the signaled task

( the wait task ), and the signaling task runs at a higher priority than the signaled task

● Some mechanism is needed to count signalling occurrences ● This can be done using a counting semaphore

When a signaling task signals the semaphore count is ( atomically )

incremented ( a release operation is performed on it )

– When the signaled task is able to run it tries to acquire the counting

semaphore - and either blocks ( if the semaphore counter is at zero ) or succeeds and decrements the semaphore count ( atomically ) by one

– The underlying assumption is that the signaling task may signal in bursts -

and the signaled task has a chance to "catch up" in between bursts

● Example scenario:

● An Interrupt Service Routine (ISR)

– Executes at high priority when the interrupt is triggered

– Offloads remaining processing to a lower priority task waiting on a

(70)

Credit Tracking Synchronisation - ctd.

Pseudo code for credit tracking synchronisation

tWaitTask ()

{

..

Acquire counting semaphore

..

}

tSignalTask ()

{

..

Release counting semaphore

..

(71)

Synchronising Access to a Shared Resource

A semaphore can be used to Synchronise Access to a Shared

Resource

The objective is to ensure that only one task / concurrent thread of

execution at a time can access the shared resource.

The strategy is as follows:

Create a binary semaphore - initially in the available state

In order to access the shared resource a task must first acquire

the semaphore

Any other task attempting to acquire this semaphore will now

block

When a task has finished with the shared resource it releases the

semaphore

A task that was blocked in its attempt to acquire the semaphore is

now unblocked and can proceed to make use of the shared

resource

(72)

Synchronising Access to a Shared Resource

● Pseudo code for shared resource access synchronisation

● Questions:

● What if a task accidentally releases the semaphore - e.g. a task that did not

acquire the semaphore in the first place ?

● What if there is more than one task blocking on the semaphore when the

semaphore is released ?

● How might the use of a mutex semaphore ( a semaphore that supports the

concept of ownership wherein only the task that successfully acquired the mutex can release it ) help ?

tAccessTask () {

..

Acquire binary semaphore

Make use of the shared resource ( e.g. read or write to it ) Release the binary semaphore

.. }

(73)

Synchronising Recursive Access to a Shared Resource

● The scenario is as follows

A task, tAccessTask, calls routine A which in turn calls routine B and all three

need access to the same shared resource

● The pseudo code for such a scenario might be

tAccessTask() { .. Acquire mutex

Access shared resource Call Routine A

Release mutex .. }

Routine A() { .. Acquire mutex

Access shared resource Call Routine B

Release mutex .. }

Routine B() { .. Acquire mutex

Access shared resource Release mutex ..

}

In this scenario , using a regular mutex ,

- Routine A would end up blocking on a semaphore that the task it is running in already owns.

One solution to such a problem would be to use a

recursive mutex - here once a task has acquired a mutex then additional attempts from the task itself, or from

routines called by that task to acquire the mutex will succeed

(74)

Controlling Access to Multiple Equivalent Shared Resources

The strategy here is to use a counting semaphore

Initialise the count of the semaphore to the number of

equivalent shared resources

When a task requests the semaphore

The semaphore count will be decremented by one if it

is greater than zero

The task will block if the semaphore count is zero

Problems can arise if a task releases a semaphore it did not

(75)

Message Queues

A message queue can be used by tasks and ISRs to communicate and to

synchronise with data - it

Utilises a buffer like object - a pipeline that, temporarily, holds messages

from a sender(s) till the target receiver is able to read them

Decouples sending and receiving tasks

When a message queue is created, then, typically,

An associated Queue Control Block (QCB) is assigned to it

A message queue name and a unique ID are assigned to it

Memory buffers are assigned to it - based on properties such as queue

length and maximum message length

One or more task waiting lists may be associated with it - typically

A sending task - blocks when the message queue is full

A reading task - blocks when the message queue is empty

(76)

Message Queues - ctd.

● Messages are read from the head of the message queue and added to the tail of the

(77)

Message Queue - State Behaviour

● When a message queue is created its initial state will be the empty state

● If a task attempts to receive messages from an empty message queue it will block ● if the task wishes to it is held in the task waiting list ( in e.g. a FIFO or priority-based

order )

● If a message is sent to a task blocking on an empty message queue then it will be

delivered directly to the blocked task

● The task will be removed from the task-waiting list and moved to either the ready

state or to the run state

● The message queue remains in the empty state

● If a message is sent to an empty message queue and there is no blocked task then

the message queue is in the non-empty state

● Additional messages will be queued up till the number of messages reaches the

maximum number the queue can hold ( the queue length )

● When the queue is in the full state then any tasking sending a message to that

queue will fail

Failure may be indicated ( depending on kernel implementation details ) e.g.

by

● Getting the sending function to return an error code to that task

(78)
(79)

Message Sending Mechanisms

The details are dependent on

The implementation of the kernel, and also, on whether

Virtual memory management is in operatio and

The various tasks are running in their own virtual address spaces.

Here are some possibilities:

The message is copied twice

Firstly from the task's memory area to the message queue's memory

area

Secondly from the message queue's memory area to the receiving

task's memory area, however,

If there is a receiving task already blocked on the message

queue then ( in some kernel implementations ) the message may

be copied directly from the sending task's memory are to the

receiving task's memory area

In real time embedded systems the cost in terms of CPU cycles and memory

(80)

Memory Allocation for Message Queues

Memory locations for message queues are also kernel implementation

dependent

The kernel may provide a system memory pool

All queues share this common memory area

Helps reduce memory requirements if it is reasonable to assume that

it will be rare for all message queues to be full to capacity at the

same time

Problems may arise in the case of message queues needing to hold

large messages which use up ( on occasions ) a large share of the

available system memory

Thus causing other message queues to fail because there is not

enough available memory

When a message queue is created a private buffer is allocated to it

Uses up more memory

More reliable - as ensures there is adequate memory available for all

(81)

Operations on Message Queues

● Create message queue ● Delete message queue

● Send message to message queue ● Blocking policy

● Non-blocking - ISRs and tasks ● Blocking with timeout - tasks only ● Blocking for ever - tasks only

● Queueing discipline

● FIFO

● LIFO

● Broadcast a message ● Multicast a message

● Query message queue for status information

● Get information about the message queue ( e.g. queue ID, queuing order ( e.g. FIFO

or priority based ), number of queued messages )

(82)

Operations on Message Queues - ctd.

● Receive message from message queue

● Blocking policy - on an empty message queue - blocked receiving tasks fill the task

list

● Blocking with timeout ● Blocking for ever

● Message reading policy

● Destructive read - message permanently removed from message queue's

storage buffer

● Mon-destructive read - receiving task "peeks" at message at head of queue but

does not remove it

● Queuing order

● FIFO

(83)

Message Queue - Use Patterns

Typical Patterns for Using Message Queues

Non-interlocked , one-way data communication

Interlocked , one-way data communication

Interlocked , two-way data communication

Broadcast communication

What other patterns of message queue usage have you come

across ?

What happens when message queueing is to be attempted on

(84)

Loosely Coupled Data Communication

Non-Interlocked, One-Way ( Loosely Coupled ) Data Communication

involves

A sending task - which sources messages

A message queue

A receiving task - which acts as a sink for messages

Details of behaviour will depend on the relative priorities of the sending and

receiving tasks

Where the receiving task has higher priority it will run first until it blocks

on an empty message queue

When the sending task sends a message the receiving task will

unblock and run again

Where the receiving task has the lower priority then the sending task will

fill the message queue with messages till it blocks ( or suspends itself )

The receiving task will "wake up" and start processing the received

(85)

ISRs and Message Queues

Interrupt Service Routines (ISRs) typically use the

non-interlocked, one-way data communication pattern

The receiving task runs and waits on a message queue

When triggered, the ISR places one or more message on

the message queue

ISRs must send messages in a non-blocking way

If the message queue if full then messages may be lost or

overwritten

(86)

Interlocked, One-Way Data Communication

In this pattern the sending task sends a message and waits to see if the

message has been received

If the message is, for some reason, not received correctly then it can be

re-transmitted

The pattern can be used as means of closing a synchronisation loop so

that the sending and receiving tasks operate in lockstep with one another

possible implementation of lockstep - involving a sending task, a message

queue ( with a length of 1 ) , a receiving task and a binary semaphore

The initial value of the binary semaphore is 0

The sending task sends a message to the message queue and blocks

on the binary semaphore

The receiving task receives the message and increments the binary

semaphore

The sending task unblocks and sends the next message

The semaphore is, in effect, acting as a simple acknowledgement to the

(87)

One-Way Data Communication example

● Pseudocode for Interlocked, One-Way Data Communication example

tSenderTask() {

...

Send message to message queue Acquire binary semaphore

... }

tReceiverTask() {

...

Receive message from message queue Release binary semaphore

... }

(88)

Interlocked, Two-Way Data Communication

● Interlocked, Two-Way Data Communication involves two tasks and two message

queues

● Synchronisation details depend on the kind of data that needs to be exchanged

For two way exchange of data two message queues are requiredFor simple acknowledgement a semaphore can be used

tClientTask() {

...

Send message to server's requests message queue Acquire binary semaphore

... }

tServerTask() {

...

Receive message from server's responses message queue Release binary semaphore

... }

(89)

Broadcast Communication

● A broadcast communication pattern involves

● A broadcast sending task, a message queue, a number of receiving tasks ● The broadcast sender sends a message to the message queue

● Each of the receiving tasks receives the message from the message queue ● Questions:

● How might a kernel implementation support broadcast communication involving

a message queue

● How would a receiver task associate itself with a message queue?

● Would it make sense for receiver tasks to block on an empty message queue? ● What if a response was expected from 0 or 1 receiver tasks only - and a

response from two or more receiver tasks was an error ?

● How would the above scenarios be modified / extended if sender and receiver

tasks were running on different machines / processors?

● Suppose it was necessary to distinguish between ordinary messages and urgent

(90)

PIPES

● Pipes are kernel objects provided by operating systems such as Unix/Linux and

Windows

● A pipe

● Supports unidirectional stream oriented data exchange

● Is made up of two descriptors - that are returned when an instance of the pipe is

created

One for the reading end - data is read from the read descriptorOne for the writing end - data is written to the write descriptor

● Data is held ( buffered ) in the pipe as an unstructured byte stream ● Data is read from the pipe in fifo order

● The reader process blocks when the pipe is empty ● The writer process blocks when the pipe is full

● Unlike a message queue a pipe

● Cannot store multiple messages

● The data in the pipe is not structured

● The data in the pipe cannot be prioritised

● Via the select operation a task can block an wait for a specified condition to

(91)
(92)

PIPE - Control Block - Creation

Pipe Creation and Pipe Control Blocks

Pipes can be created and destroyed dynamically

When a pipe instance is created the kernel creates a pipe control block

A pipe control block contains pipe specific information ( maintained by

the kernel ) e.g.

Size of pipe buffer - specified at creation time and then remains fixed

Current data byte count

Input and output position indicators

Two descriptors in file i/o space - which will be unique

These descriptors are returned to the task creating the pipe

Details vary from kernel to kernel

There are two task waiting lists associated with a pipe

List of tasks waiting to write to the pipe ( blocked when pipe buffer is

full )

List of tasks waiting to read from the pipe ( blocked when the pipe

(93)
(94)

PIPE Operations

● Create pipe ● Destroy pipe ● Read from pipe

● Returns data to calling task

● Calling task specifies how much data to read

● Task may opt to block - waiting for remaining data to arrive - if amount of data

requested is greater than what is available in the pipe

● Pipe reads are destructive - data IS REMOVED FROM THE PIPE ● Once data has been read it is not available to other readers

● Write to pipe

● Appends new data to existing byte stream in the pipe

● Task may choose to block - waiting for additional buffer space to become

available - if the amount of data to be written is greater than the space available currently in the pipe buffer

● Because there are no message boundaries in a pipe it is not possible to

determine the original producer of the data bytes

● Data written to a pipe CANNOT BE PRIORITISED - DO NOT USE A PIPE IF

(95)

PIPE Operations - ctd.

● Pipe Control, Flush and Select Operations ( Typical )

● Control - the fcntl operation - used to alter the behaviour / attributes of the pipe

e.g. - whether a task should block if a read operation is attempted on an empty pipe or a write operation is attempted on a full pipe

● Flush

This command removes all data from the pipe and clears all conditions in the

pipe so that the pipe reverts to the state it had when it was created

– Useful for e.g. removing data that has been kept in the pipe for too long and

is now out of date

● Select - probably the main advantage of a pipe over a message queue

– Used to permit a task to block for some specified condition to occur in one or

more pipes e.g.

● Waiting for data to become available in a pipe(s) ● Waiting for data to be emptied from a pipe(s)

● Example - using select a task may be waiting to read from one of two

pipes and write to a third

Select returns when data becomes available in one or other of the two pipes

being read from, or when space becomes available in the pipe being written to

(96)

PIPE - Example

Example - using pipes for inter-task synchronisation

Two tasks ( A and B ) and two pipes

One pipe opened so that it is written to by A and read from by B

Other pipe opened so that it is read from by A and written to by B

A and B both issue a select operation on the pipes

Task A can issue a non-blocking call to write to the pipe and perform

other operations until the pipe becomes writeable ( because task B

has read some data from the pipe ( i.e. task A can wait

asynchronously for the data pipe to become writeable )

Task A can wait asynchronously for arrival of a transfer

acknowledgement from task B

Task B can wait asynchronously for the arrival of a transfer

acknowledgement from task A

Task B can wait for the other pipe to become writeable before

(97)

Event Registers

● An event register

● Is associated with a task

● Details are hardware and kernel specific ● Is a collection or binary event flags

● Typically 8, 16 or 32 bits

– Each bit in the event register is associated with some specific event – Each bit can either be set or cleared

● Used by a task to check for the occurrence / non-occurrence of a particular event ● Can be used by an ISR to inform a task that a particular event has occurred

● A task performs conditional checks specified by a combination ( using ANDs and

ORs ) of the event register bit flags

● Event checking strategies can be ● No wait

● Wait indefinitely ● Wait with timeout

(98)

Event Registers - ctd.

● The event register control block is (typically) part of the task control block and

(typically) contains the following fields

● Wanted events register

● Events the task wishes to receive ● Received events

Events that have "arrived" are recorded here

● Timeout value

Set by task to indicate how long it wishes to wait for the arrival of the events

it is "interested in"

● Notification conditions

Specify (to the kernel) the conditions (occurring as a result of event arrivals)

under which the task wishes to be woken up

● The main event register operations ( typically ) are ● Send - an event is sent to a task

● Receive - used by a calling task to receive events from external sources

A task can specify whether or not it wishes to wait, and,

If waiting, whether it wishes to wait indefinitely or only for a specified timeout

(99)

Using Event Registers

No data is associated with an event when an event is sent through an

event register

Pending events in the event register do not change the execution

state of the receiving task

There is no mechanism for identifying the source of an event

Identifying protocols need to be agreed upon between senders

and receivers - e.g.

A particular task sends a particular event by setting a particular

bit in the event register )

Events in the event register are not queued

An event register cannot count the number of occurrences of an

(100)

Signals

A signal is a software interrupt

Generated in response to some event occurring

Triggers the asynchronous execution ( in the target task ) of the

associated signal handler routine ( as specified by the task for dealing

with that signal )

The numbers and types of available signals are system and operating

system dependent

Typical types of events associated with signals

An attempt to perform an illegal operation during program execution

e.g. a divide by zero

Notification from a task to another task that it is about to terminate

Some user gesture - e.g. typing in a combination of characters

corresponding to a "quit" command

A signal is identified by a signal number ( vector number ) - which is its

(101)

Signal Control Block

● The signal control block is ( typically ) part of the task control block ● Maintains a list of signals the task is prepared to handle ( catch )

● A task can specify a signal handler for each signal it wishes to process, or,

simply rely on a default handler

● A signal interrupt is often referred to as "raising a signal in the interrupted task"

– If a signal arrives while a task is processing another signal

● The additional signal is placed in a signals pending list

As soon as a task finishes processing a signal the next signal in the signals

pending list can "raise a signal" on that task

● It is possible for a task to partially process a signal and then to pass the signal on

for further processing by the default handler

● It is possible for a task to block the delivery of a signal during certain "critical"

stages in that task's processing

– The task tells the kernel to block certain signals by setting the appropriate

values in the "blocked signals set"

● The kernel will not deliver a signal listed in the "blocked signals set" until

References

Related documents

Smart Card Personalization Allows access data and sessions which are to be available to a smartcard user to be written to an IGEL smartcard.. Touchscreen Calibration Allows

Generally speaking, priority inversion occurs when two tasks of differing priority share a resource, and the higher- priority task cannot obtain the resource from the

• Priority based scheduling: highest priority task is executed. • Designed for

Figure 1 Aimed to increase recombinant quality and solubility, co-production of individual chaperones or chaperone sets has been a common strategy since the role of these proteins

Careers Open to All Graduates Accountancy Banking Distribution Insurance Journalism Marketing Public relations Purchasing Sales Administration IT Financial management

This global state can be out of sync with the state of the local pools, hence the thread attempts to find a local task with a higher priority (lower level index) and schedule the task

In some In some cases, the middleman provides Day Old Chicks and other farm inputs (feed, etc.) to cases, the middleman provides Day Old Chicks and other farm inputs (feed, etc.) to

3.- Assessment of the efficiency of biogas production in small anaerobic digesters and treatment of digestates using an anaerobic thermophilic process of short duration in