Contenu connexe Similaire à Safe and Reliable Embedded Linux Programming: How to Get There (20) Safe and Reliable Embedded Linux Programming: How to Get There1. 7 June 2012
Safe and Reliable Embedded Linux Programming
How to Get There
José F. Ruiz
Senior Software Engineer
AdaCore
EWiLi 2012, Lorient
Copyright © 2012 AdaCore Slide: 1
2. Outline
• Safety issues
– Language matters
• Concurrent execution on monoprocessors
– Ada Ravenscar Profile
• Tasking on linux
• Parallel execution on multiprocessors
– Processor affinities
Copyright © 2012 AdaCore Slide: 2
4. Safety-Critical Software: Background
• What is “safety critical” software?
– Failure can cause loss of human life or have other catastrophic consequences
• How does safety criticality affect software development?
– Regulatory agencies require compliance with certification requirements
– Safety-related standards may apply to the finished product, to the development process,
or both
• Choice of programming language has large impact on the cost of
developing / certifying safety-critical systems
– Dilemma: modern features that help in developing maintainable systems interfere with
safety certification
– Examples: Object-Oriented Programming, generics, exceptions, concurrency
– Traditional approach: select subset (profile) amenable to safety certification
– Chosen features depend on the analysis methods to be used (or dictate which
methods are feasible)
Copyright © 2012 AdaCore Slide: 4
5. Some language requirements (I)
• Reliability
– Support for development of readable, correct code
– No “traps and pitfalls”
– Intuitive lexical and syntactic features
– Support for good software engineering practice
– Encapsulation
– Avoidance of concurrency bugs
– Race conditions
– Deadlock / livelock
– Early error detection
– Compile-time checking whenever possible
– Run-time checking, at least
• Predictability
– Unambiguous language semantics
– No undefined / implementation-dependent behavior
– Ability to demonstrate statically that time and space constraints will be satisfied
– Deadlines will be met
– Stack and heap space will not be exhausted
Copyright © 2012 AdaCore Slide: 5
6. Some language requirements (II)
• Analyzability
– Control and data flow analysis
– Detects / prevents references to uninitialized data
– Information flow analysis
– Identify dependencies between a routine’s inputs and outputs
– Formal code verification
– Range checking
– Traceability between program representations and different levels
– Dynamic analysis (testing)
• Expressiveness
– General-purpose features consistent with the above requirements
– Support for specialized processing typical in embedded systems (safety)
– Interrupt handling
– Low-level programming
– Fixed-point arithmetic
Copyright © 2012 AdaCore Slide: 6
7. Modern programming languages
• Many features help
– Encapsulation / namespace control
– Limit data coupling
– Strong typing, compile-time checking
– Early error detection
• Some features present difficulties
– High expressive power vs. need to constrain feature
– Dynamic flexibility vs. need for static analysis
– High-level features vs. need to certify the code that actually runs
– Generated code may contain implicit loops, conditionals
– Run-time library, API need to be certifiable
– How, if at all, use features such as exceptions, concurrency, dynamic allocation
Copyright © 2012 AdaCore Slide: 7
8. Modern programming languages – basic issues
• No general-purpose language is appropriate for highest safety/security levels
– Conflicts with reliability, predictability, analyzability
• Key issue: can the language be subsetted so that applications restricted to the
subset can be certified
– Is/are the subset(s) precisely defined?
– Can compliance with the subset(s) be enforced by a tool?
– Who defines the subset(s)?
– Standards agency? Tool/compiler vendor? Application developer?
– Are there intrinsic problems with the language that cannot be solved by subsetting?
• Current approaches
– C-based
– MISRA C / C++
– Ada-based
– Ada profiles
– SPARK Ada
– Java-based
– Real-Time / Safety-Critical Java Technology
Copyright © 2012 AdaCore Slide: 8
9. MISRA C
• Intended for embedded automotive systems
– Around 170 rules
• Prevent or restrict usage of C constructs with unpredictable behavior
• Encourage static checking tools that enforce compliance with the subset
Strengths Weaknesses
– “Best practices” for C programming – C was not designed to meet the
– General good style needs of high-integrity systems
– Avoids C features intrinsically non- – Error-prone
portable / ill-defined
– Lacks features such as
– Simplicity of C compared with other encapsulation, namespaces
languages
– C (and thus MISRA C) does not
– Smaller run-time library
– Easier certification
“scale up” to large systems
– Large population of candidate users – C standard has ambiguities and thus
– And tools, service providers, etc. so does MISRA C
– May be appropriate for small systems – Some rules are not enforceable by
on specialized hardware lacking static tools
compilers for alternative languages – Usage of MISRA C requires license
– MISRA-C code may be produced as from MISRA
output of source-to-source translator
Copyright © 2012 AdaCore Slide: 9
10. Ada – introduction
• What is Ada?
– General-purpose methodology-neutral strongly-typed ISO standard language
– Intended for large, long-lived systems
– Fits reliability-critical embedded real-time applications
• Ada in a nutshell
– Pascal-style foundation (syntax, basic data types)
– Exception handling
– Packages / encapsulation
– Generic templates
– Concurrency support (“tasking”)
– Object-Oriented Programming
– Support for “contracts”
– Since Ada 2012
– Specialized support for particular domains, including:
– Systems programming
– Real-time systems
– High-Integrity applications
Copyright © 2012 AdaCore Slide: 10
11. Ada for safety-critical systems (I)
• Full Ada not appropriate
– Run-time library too large / complex
– High level features interfere with traceability and analyzability
• Why consider Ada for safety/security-critical software
– General design philosophy promotes sound software engineering
– Successful history from Ada 83
• Standard support for safety/security-critical systems
– High-Integrity Systems Annex
– Contracts
– Profiles
– Such as the Ravenscar profile
– User-defined tailoring, specifying features that are not used (pragma Restrictions)
– Compiler rejects programs that use these features
– Executable program excludes run-time libraries for these features
• Guidelines documents
– Guide for Ada in High-Integrity Systems (an ISO Technical Report)
– Guide for Ada Ravenscar Profile in High-Integrity Systems
Copyright © 2012 AdaCore Slide: 11
12. Ada for safety-critical systems (II)
• Reliability
– Very few features have surprising effects
– Prevention of dangling references to declared objects, subprograms
– Specification of intent on operation inheritance
– Contracts
– No garbage collection
– Programmer responsible for memory management
• Predictability
– Language semantics are generally well-defined, in an ISO standard
– But there are features whose effects are implementation defined, implementation
dependent, unspecified, or “bounded errors”
– Implementation decisions can affect time or space predictability
– Functions returning unconstrained arrays
– Solutions in practice
– Analyze source program (e.g. no read of uninitialized object)
– Adhere to subset (no functions returning unconstrained arrays)
– Analyze object code so that implementation decision is known
Copyright © 2012 AdaCore Slide: 12
13. Ada for safety-critical systems (III)
• Analyzability
– Some features help analyzability
– Child units may be used for testing packages with encapsulated state
– But full language is too complex; need to subset
– Key features are pragma Restrictions and pragma Profile
– Ada is in effect a family of profiles, where user can select features à la carte
– No such thing as the safety-critical Ada profile
– Troublesome OOP features are easily avoided
– But no standard annotation facility
• Expressibility
– Support for low-level and real-time programming
– Ravenscar Profile for certifiable concurrent applications
– Good inter-language interfacing facilities, to incorporate certifiable libraries from other
languages
– Some weaknesses
– Limited support for distribution / networking
Copyright © 2012 AdaCore Slide: 13
14. Ada examples
Configuration Spec (design by contract)
pragma Profile (Ravenscar); package Arith is
-- Only Ravenscar tasking allowed procedure Double (X : in out Integer) with
Pre => X >= Integer'First / 2 and then
pragma Restrictions (No_Allocators); X <= Integer'Last / 2,
-- Avoid dynamic memory Post => X = 2 * X'Old;
end Arith;
pragma Restrictions (No_Access_Subprograms);
-- No pointers to subprograms
System programming
type Parity_Kind is (Even, Odd); for UART_Data_Register use
record
type Reserved_21 is mod 2**21; Data at 0 range 0 .. 7;
for Reserved_21'Size use 21; Data_Ready at 0 range 8 .. 8;
Parity at 0 range 9 .. 9;
Type UART_Data_Register is Parity_Error at 0 range 10 .. 10;
record Reserved at 0 range 11 .. 31;
Data : Character; end record;
Data_Ready : Boolean; for UART_Data_Register'Size use 32;
Parity : Parity_Kind;
Parity_Error : Boolean; UART_A : UART_Data_Register;
Reserved : Reserved_21; pragma Atomic (UART_A);
end record; for UART_A’Address use To_Address (16#8000_0100#);
Copyright © 2012 AdaCore Slide: 14
15. Ada evaluation
• Strengths
– Sound base language for programming high-reliability systems
– Allows construction of tailored high-integrity subsets that are:
– Powerful enough to use for real systems
– Simple enough to be amenable to certification
– Scales up to large systems
– ISO Standard
– Concurrency support / Ravenscar Profile
– Design by contract
– Free and publicly available documents
– Ada Reference Manual, Rationale
– Guidelines documents
– Good track record in avionics, train control, other safety-critical domains
• Weaknesses
– Whole language is too large, so must be subsetted
– Aside from the standard Ravenscar Profile, others are vendor specific
– Language has some features with implementation-dependent or unspecified behavior
– Such as referencing a variable before its initialization
– Smaller user / tool vendor community than other languages
Copyright © 2012 AdaCore Slide: 15
16. SPARK introduction (I)
• SPARK is
– A language, plus
– Static analysis tools based on underlying principle of correctness by construction
• Facilitate rigorous, static demonstration that program does what it is supposed
to do
– And only that
• Guarantee bounded time and space requirements
• Allow simple run-time library amenable to certification
• Ada-based language
– Ada plus contracts minus features that interfere with above principle
– Contracts are special comments handled by the SPARK tools
• Language restrictions (Ada features intentionally omitted)
– Features that complicate analysis / formal proofs, e.g.:
– Exceptions, goto statement, generic templates, function side effects
– Features that interfere with bounded time / space requirement, e.g.:
– Recursion, pointers, dynamically-sized arrays
Copyright © 2012 AdaCore Slide: 16
17. SPARK introduction (II)
• Language features include:
– Most of Ada’s “static semantic” features, including packages, private types,
unconstrained array types, “OOP Lite”
– Concurrency (Ravenscar tasking profile)
• Contracts
– Data / information flow (use of global variables, formal parameters)
– Inter-module dependencies
– Specification of dynamic behavior (pre / post-conditions, assertions)
• Analysis performed by SPARK tools
– Static semantic analysis – detect aliasing, function side effects, …
– Control flow analysis – detect dead code, banned constructs (goto, …)
– Data-flow analysis – detect unused or uninitialized variables, …
– Information-flow analysis – check input / output variable coupling
– Verification condition generation – generate theorems
– Theorem proving
Copyright © 2012 AdaCore Slide: 17
18. SPARK example
Contracts and flow information
procedure Process
(Output : out T;
Input1, Input2 : in T);
--# global out Global_Output;
--# in Global_Input;
--# derives Output from Input1, Input2 &
--# Global_Output from Global_Input, Input2;
--# pre Input1 /= 0;
--# post Output = Input2 / Input1;
Copyright © 2012 AdaCore Slide: 18
19. SPARK for safety-critical systems
• Reliability
– Inherits Ada’s general advantages (few syntactic surprises)
– Avoids some errors that may occur in full Ada
– Reference to uninitialized variable
• Predictability
– Unambiguous specification with no implementation dependencies
– But not a formal standard
– Contracts allow statically checkable assertions about resource requirements
• Analyzability
– SPARK Ada subset eliminates features that are complicated to analyze
• Expressibility
– Missing some useful functionality (e.g. generics) but does include some tasking features
Copyright © 2012 AdaCore Slide: 19
20. SPARK evaluation
• Strengths
– Designed from the start to satisfy high-integrity requirements
– Language rules are unambiguous, implementation independent
– Insecurities (e.g., “aliasing” of formal parameter and global variable) and many kinds of
hard-to-detect bugs (e.g. use before initialization) are prevented
– Contracts show programmer’s intent, aid readability
– Support for concurrency (Ravenscar profile)
– Tedious aspects of constructing proofs are automated
– Positive experience across a range of high-integrity projects
– Lower certification costs and post-delivery bug rates
– Excellent reference material
• Weaknesses
– Language lacks some useful features
– No “pointers”, but in many kinds of safety critical systems a restricted style for pointers is
permitted
• Pointers to statically declared data
• Dynamic allocation at system startup
– Some restrictions (e.g. no recursion) require stylistic workarounds
– Contracts require different development style than what most programmers are used to
– Relatively small user community
– Small number of suppliers for tools, services
Copyright © 2012 AdaCore Slide: 20
22. Concurrency in Ada (short history)
• Concurrency a first-class citizen in Ada
– Easy to use and analyze
– Since the beginning
– Well-developed tasking in Ada 83
– Ada 95, Ada 2005 , Ada 2012 improved and extended tasking
Ada
Decades of experience in using Ada on multiprocessors
Copyright © 2012 AdaCore Slide: 22
23. Why Ravenscar
• Use concurrency in embedded real-time systems
– Verifiable
– Simple
– Implemented reliably and efficiently
• Scheduling theory for accurate analysis of real-time behavior
– Preemptive fixed priority scheduling
– Rate Monotonic Analysis (RMA)
– Response Time Analysis (RTA)
– Priority Ceiling Protocol (PCP)
– Avoids unbounded priority inversion and deadlocks
• Tool support
– RMA and RTA
– Static simulation of concurrent real-time programs
Copyright © 2012 AdaCore Slide: 23
24. What is the Ravenscar profile
• A subset of the Ada tasking model
• Defined to meet safety-critical real-time requirements
– Determinism
– Schedulability analysis
– Memory-boundedness
– Execution efficiency and small footprint
– Suitability for certification
• State-of-the-art concurrency constructs
– Adequate for most types of real-time software
Copyright © 2012 AdaCore Slide: 24
25. Tasks
• Fixed set of tasks
– Only at library level
– No dynamic allocation
– No nested declaration of tasks
– Statically created
– Task descriptors, stacks, …
• Each task is infinite loop
– Single “triggering” action (delay or event)
• Task creation and activation is very simple and deterministic
– All tasks are created at initialization
– Then all activated and executed according to their priority
Copyright © 2012 AdaCore Slide: 25
26. How tasks look like in Ravenscar
Time-triggered task Event-triggered task
task body Cyclic is
Period : constant Time_Span := Milliseconds (10);
Activation : Time := Clock; task body Sporadic is
begin begin
loop loop
delay until Activation; Monitor.Wait_Event; -- Protected entry
-- Do something -- Do something
Something; Something;
end loop;
-- Compute next activation time end Sporadic;
Activation := Activation + Period;
end loop;
end Cyclic;
Copyright © 2012 AdaCore Slide: 26
27. Periodic activity in Ada and C
static void *periodic (void *arg) {
struct timespec activation;
clock_gettime (CLOCK_REALTIME, &activation);
C Periodic while (1) {
clock_nanosleep (CLOCK_REALTIME, TIMER_ABSTIME,
&activation, NULL);
Freq = 10 Hz
/* Do something */
something ();
/* Compute next activation time */
if (1000000000 - activation.tv_nsec < 100000000)
{
task body Periodic is activation.tv_sec += 1;
Activation : Time := Clock; activation.tv_nsec += 100000000 - 1000000000;
begin } else {
loop activation.tv_nsec += 100000000;
delay until Activation; }
}
-- Do something }
Something; int main(void) {
pthread_t thread;
-- Compute next activation time pthread_attr_t attr;
Activation := pthread_attr_init (&attr);
Activation + Milliseconds (100);
end loop; pthread_create (&thread, &attr, &periodic, NULL);
end Periodic; …
}
Copyright © 2012 AdaCore Slide: 27
28. Synchronization in Ravenscar
protected body Buffer is
protected Buffer is procedure Put (Element : Item)
procedure Put (Element : Item); is
entry Get (Element : out begin
Item); Container := Element;
private Received := True;
Container : Item; end Put;
Received : Boolean := False;
end Buffer; Pr Buffer entry Get (Element : out Item)
when Received is
Put
begin
Get
Element := Container;
Received := False;
C Producer end Get;
end Buffer;
S Consumer
task body Producer is
Period : constant Time_Span := Milliseconds
(10);
Activation : Time := Clock;
Element : Item;
begin
loop task body Consumer is
delay until Activation; Element : Item;
begin
Element := Produce_It; loop
Buffer.Get
Buffer.Put (Element); (Element);
Activation := Activation + Period; Consume (Element);
end loop; end loop;
end Producer; end Consumer;
Copyright © 2012 AdaCore Slide: 28
29. Interrupt support in Ravenscar
protected Monitor is
pragma Priority (Interrupt_Priority’Last);
Pr Monitor procedure Handler;
External Interrupt pragma Attach_Handler (Handler,
Handler
Interrupt_ID);
Wait
entry Wait;
private
Signaled : Boolean := False;
end Monitor;
S Interrupt_Task
protected body Monitor is task body Interrupt_Task
procedure Handler is is
begin begin
Signaled := True; loop
end Put; Monitor.Wait;
entry Wait when Signaled is Handle_Interrupt;
begin end loop;
Signaled := False; end Interrupt_Task;
end Wait;
end Monitor;
Copyright © 2012 AdaCore Slide: 29
31. The model – Ada tasks
• Ada task runs on top of operating system thread
– One-to-one correspondence
• Task dispatching policy
– Can be selected with pragma Dispatching_Policy
– SCHED_OTHER by default
– Preemptive priority scheduling
– pragma Dispatching_Policy (FIFO_Within_Priorities)
• pthread_setschedparam (Thread, SCHED_FIFO, Param’Access)
– Means run until blocked (or preempted), no time slicing
– Reduces non-determinism
– NOTE!!: Requires special (root) privileges
• Xenomai
– Real-time behavior
– The Ada run-time library can call the Xenomai API to create tasks in kernel domain
Copyright © 2012 AdaCore Slide: 31
32. The model – Synchronization
• A protected type is a data object with locks
– Data encapsulation, accessible through interface (locked access routines)
– functions (read the data with read lock)
– procedures (read/write the data with write lock)
– entries (wait until some condition is met, then read/write the data with write lock)
• Priority inheritance
– Guard against priority inversion
– low priority task grabs resource X
– high priority task needs resource X, waits
– medium priority task preempts low priority task, and runs for a long time, holding up high priority task
– Solution, while high priority task is waiting, lend high priority to low priority task
• Implementation
– Mutual exclusion
– Mutex
– Waiting / Signaling operations
– Conditional variable
Copyright © 2012 AdaCore Slide: 32
33. The model – System programming
• Clock and delay
– Clock uses gettimeofday
– Delay operations use timed conditional variables
– We can wakeup the task before expiration if needed
• Interrupt handling
– Underlying signal mechanism
– A server task per interrupt served
– With specific mask to serve the required signal
– Call to sigwait
Copyright © 2012 AdaCore Slide: 33
35. Why addressing multiprocessors?
• The answer to increasing processing demands
– We cannot increase the clock frequency forever
– We cannot increase the instruction-level parallelism forever
– Provides higher performance for less consumed energy
Courtesy IEEE
Computer, January
2011, page 33.
Copyright © 2012 AdaCore Slide: 35
36. Periodic activity in Ada and C (multiprocessor version)
static void *periodic (void *arg) {
struct timespec activation;
clock_gettime (CLOCK_REALTIME, &activation);
while (1) {
C Periodic clock_nanosleep (CLOCK_REALTIME, TIMER_ABSTIME,
&activation, NULL);
Freq = 10 Hz /* Do something */
CPU affinity = 1 something ();
/* Compute next activation time */
if (1000000000 - activation.tv_nsec < 100000000) {
activation.tv_sec += 1;
activation.tv_nsec += 100000000 - 1000000000;
task Periodic with CPU => 1; } else {
activation.tv_nsec += 100000000;
task body Periodic is }
Activation : Time := Clock; }
begin }
loop
delay until Activation; int main(void) {
cpu_set_t cpuset;
-- Do something pthread_t thread;
pthread_attr_t attr;
Something;
CPU_ZERO (&cpuset);
-- Compute next activation time CPU_SET (0, &cpuset);
pthread_attr_init (&attr);
Activation :=
pthread_attr_setaffinity_np
Activation + Milliseconds (100);
(&attr, sizeof (cpu_set_t), &cpuset);
end loop;
end Periodic; pthread_create (&thread, &attr, &periodic, NULL);
…
}
Copyright © 2012 AdaCore Slide: 36
37. Some advantages of Ada
• Better readability
– No doubts, right?
• Semantics
– The Ada run time enforces required dispatching policy, signal mask, master-dependent
tasks, …
• Portability
Platform Ada C
Linux
Solaris
Windows
VxWorks
Bare board
Copyright © 2012 AdaCore Slide: 37
38. Ada 2012
• Ada 2012 added explicit support for controlling processor allocation
– Dispatching_Domain
• Ravenscar profile for multiprocessors
• Parallel task synchronization
• Memory barriers
Copyright © 2012 AdaCore Slide: 38
39. Concurrent / parallel execution in Ada
• Ada has always taken into account parallel architectures
– Allow concurrent/parallel execution
– Multicomputers, multiprocessors, interleaved execution
– Even allow parallel execution of a single task
– … if its effect is as executed sequentially
– A task can be on the ready queues of more than one processor
– Many partitioning schemes allowed
– Via implementation-defined pragmas or non standard library packages
Copyright © 2012 AdaCore Slide: 39
40. Synchronization and communication of parallel activities
• Task synchronization
– Protected objects
– No language-defined ordering or queuing presumed for tasks competing to start a
protected action
• Tasks are intended to spin lock on multi-processors
– Shared variables
– Cache coherence
– Rendezvous
– The call to the task entry is blocking
Copyright © 2012 AdaCore Slide: 40
41. Symmetric Multi-Processor (SMP)
• Several similar processors
– All processors can perform the same functions
• Centralized memory with uniformed access time
– Problem of cache coherence
Processor Processor Processor Processor
One or One or One or One or
more cache more cache more cache more cache
levels levels levels levels
Main memory I/O System
Copyright © 2012 AdaCore Slide: 41
42. Partitioned versus global scheduling
Partitioning Global Scheduling
• Tasks assigned to a given • Task migration is permitted
processor – Overhead of task migration
• How to schedule a group of tasks increases with the number of CPUs
on a processor is known – Reduced cache performance
– Rate Monotonic Scheduling (static
priorities)
– Earliest Deadline First (dynamic None is better than the other in
priorities) terms of guaranteed CPU utilization
• But, dividing the tasks into groups
is NP-hard
Copyright © 2012 AdaCore Slide: 42
43. Typical OS support for multiprocessors
• Set CPU affinity
– Allocate tasks to one CPU (or to a group of CPUs)
• Get CPU affinity
• Task migration
– From one CPU to another
– Either user-requested or performed by the OS
• Spin locks
– Tasks wait in a loop until lock is free (busy waiting)
– Multiprocessor synchronization
Copyright © 2012 AdaCore Slide: 43
44. Support for multiprocessors in Ada 83, 95, 05
• Ada has always allowed a program’s implementation to be on a
multiprocessor system
– Real parallelism
– Inter-processor synchronization
• No direct support for affinities
– The OS can decide the best allocation
– The developer
– Implementation-defined pragmas or non standard library packages
• Allows the full range of partitioning
– But no user control defined in the standard
Copyright © 2012 AdaCore Slide: 44
45. Explicit support for multiprocessors in Ada 2012
• Notion of dispatching domain
• Safe multiprocessor tasking
• Parallel task synchronization
• Memory barriers
Copyright © 2012 AdaCore Slide: 45
46. Ada 2012 dispatching domains
• Focus on SMPs
• Handle mapping of tasks to processors
– Support all schemes
– Partitioned
• Tasks allocated to a subset of CPUs
– Global
• Implicit task migration supported
• Explicit task migration allowed
• Notion of processor dispatching domain
– Group of processors across which global scheduling occurs
– Non-overlapping dispatching domains
– Tasks are assigned to an unique dispatching domain
– A task may be allocated to a given processor within the dispatching domain
– Or free to be in any of the domain
Copyright © 2012 AdaCore Slide: 46
47. Static allocation to processors
task type Allocated_Task (Affinity : CPU)
with CPU => Affinity;
T1 : Allocated_Task (1);
T2 : Allocated_Task (2);
T3 : Allocated_Task (3);
T4 : Allocated_Task (4);
GroupA : aliased Dispatching_Domain := Create (1, 2);
GroupB : aliased Dispatching_Domain := Create (3, 4);
GroupC : aliased Dispatching_Domain := Create (5, 6);
GroupD : aliased Dispatching_Domain := Create (7, 8);
task type Grouped_Task (Group : access Dispatching_Domain)
with Dispatching_Domain => Group.all;
T1, T2, T3, T4 : Grouped_Task (GroupA’Access);
T5, T6 : Grouped_Task (GroupB’Access);
T7, T8, T9 : Grouped_Task (GroupC’Access);
T10, T11 : Grouped_Task (GroupD’Access);
Copyright © 2012 AdaCore Slide: 47
48. Dynamic affinity handling
GroupA : Dispatching_Domain := Create (1, 2);
GroupB : Dispatching_Domain := Create (3, 4);
GroupC : Dispatching_Domain := Create (5, 6);
GroupD : Dispatching_Domain := Create (7, 8);
task body T_In_A is
Current_CPU : CPU;
begin
-- In processor 1 or 2
Do_Something;
task T_In_A with Dispatching_Domain =>
GroupA; -- In processor 1 only
task T_Non_Allocated;
Set_CPU (1);
task body Driver is Do_Something;
begin
-- Allocate T_Non_Allocated to GroupB -- In processor 2 only
Assign_Task Set_CPU (Get_Last_CPU (GroupA));
(GroupB, 3, T_Non_Allocated’Identity); Do_Something;
Do_Something;
-- Now again in processor 1 or 2
-- Move it to a different processor
Set_CPU (Not_A_Specific_CPU);
if Proc_3_Overloaded then Do_Something;
Set_CPU (4, T_Non_Allocated’Identity);
end if; -- Now I am lost. Where am I?
Do_Something;
Current_CPU := Get_CPU;
end Driver; pragma Assert
(Current_CPU = Not_A_Specific_CPU);
end T_In_A;
Copyright © 2012 AdaCore Slide: 48
49. Handle affinity and dispatching policy
• What I want
– Create a group of processors
– Define an specific scheduling policy for
the group pragma Priority_Specific_Dispatching
(FIFO_Within_Priorities, 20, 25);
– Execute a set of tasks within the group
Group : Dispatching_Domain := Create (1, 2);
task T1
• What I have to do with Dispatching_Domain => Group,
Priority => 22;
– Create a dispatching domain
– Define a non-overlapping priority band task T2
with Dispatching_Domain => Group,
– Allocate tasks to the dispatching domain Priority => 23,
CPU => 1;
– Use priorities in the priority band
task T3
with Dispatching_Domain => Group,
Priority => 24;
Copyright © 2012 AdaCore Slide: 49
50. Synchronization on multiprocessors
• Protected objects
– There is a lock-free optimization for monoprocessors (using priorities)
– No longer viable on multiprocessors
– Currently Ada advise that tasks should busy-wait (spin) at their active priority for the lock
• Task entries
– Requires internal synchronization primitives aware of multiprocessor
– Spin locks
Copyright © 2012 AdaCore Slide: 50
51. Multicores for real-time safety-critical embedded systems
• We need to address:
– Reliability
– Predictability
– Analyzability
• The Ravenscar profile for monoprocessors is
– Deterministic
– Time analyzable
– Simple to use and implement
• Extend the Ravenscar profile model from monoprocessor to multiprocessor
– Fully partitioned model
– Fixed-priority scheduling
– Static model
• Allow for
– Simple implementation
– Verifiable
– Schedulability analysis
Copyright © 2012 AdaCore Slide: 51
52. Static model
• Concurrent entities fixed and static
– Tasks and shared memory defined before execution
• Static fixed priority scheduling algorithm
– Preemptive fixed priority scheduling in each CPU
– Analyzable as in Ravenscar for monoprocessors
– Dynamic-priority scheduling algorithms could increase CPU utilization but:
– Higher complexity
– Higher run-time overhead
– Lower predictability, lower robustness in case of overload
• Partitioned
– Each task allocated to an user-defined processor forever
– CPU utilization of partitioned scheduling is neither better nor worse than global
– It relies on very well known monoprocessor techniques for priority allocation and timing
analysis
– It is much simpler to implement
– No task migration
Copyright © 2012 AdaCore Slide: 52
53. Task scheduling
• Tasks statically allocated to
processors
Ravenscar system on monoprocessor
– No task migration
• Preemptive fixed-priority
scheduling 0
1
• Single shared run time
2
– Per-CPU ready queues
– Spin-locks to protect shared data 3
– Disabling interrupts is not
enough
task Cyclic
with Priority => 100,
• Operations on a different CPU => 3;
end Cyclic;
processors
– Triggering an special interrupt in the
target processor
Copyright © 2012 AdaCore Slide: 53
54. Task synchronization
• Library-level protected objects
– Shared data with mutual exclusion
– Both for inter- and intra-processor communication
• Simple and efficient mutual exclusion changing priority for intra-processor
communication
– As in Ravenscar monoprocessor
– Could be statically detected
– Efficiency
– Simple timing analysis
• Spin-locking for inter-processor synchronization
• Awaking tasks from other processors
– Inter-processor interrupt facility to modify the ready queues
Copyright © 2012 AdaCore Slide: 54
55. Parallel task synchronization
• Goal
– Effective parallel task synchronization
– Set of tasks blocked and released at once
• Typical case
– A group of tasks must wait until all of them reach a synchronization point
– And then be released together to work in parallel
• Mimic the POSIX barrier mechanism
Copyright © 2012 AdaCore Slide: 55
56. Parallel barrier example
package Ada.Synchronous_Barriers is
pragma Preelaborate (Synchronous_Barriers);
subtype Barrier_Limit is Positive range 1 .. <imp-
def>;
type Synchronous_Barrier
(Release_Threshold : Barrier_Limit) is limited
private;
procedure Wait_For_Release
(The_Barrier : in out Synchronous_Barrier;
Notified : out Boolean);
Number_Of_Tasks : constant := 8;
private
Barrier : Synchronous_Barrier (Number_Of_Tasks);
-- not specified by the language
end Ada.Synchronous_Barriers;
task type Worker (Affinity : CPU) with CPU => Affinity;
task body Worker is
Notified : Boolean;
begin
loop
Wait_For_Release (Barrier, Notified);
-- Do something in parallel at the same time
Something;
if Notified then
-- Only one task does this
Ask_For_More_Work;
end if;
end loop;
end Worker;
Copyright © 2012 AdaCore Slide: 56
57. Memory barriers
• Goal
– Have control over cache memories
• Typical case
– Non-blocking algorithms to effectively exploit hardware parallelism
– lock-free and wait-free
• Problem to solve
– How to ensure the correct order of loads and stores with multi-level caches
– Modern multicores do not guarantee this ordering between processors
– Optimizations that can result in out-of-order execution
– Unless special instructions are used
• How to do it with Volatile
– Until Ada 2005
– They can never be in cache or registers
– The Ada 2012 (more realistic) approach
– Volatiles can be handled in cache memories, but
– Guarantee serial ordering
• All tasks of the program (on all processors) that read or update volatile variables see the
same order of updates to the variables
• May need the use of an appropriate memory barrier to flush the cache
Copyright © 2012 AdaCore Slide: 57
58. Example of memory barriers
Shared_Data : Integer;
pragma Volatile (Shared_Data);
• In Ada 83, 95, 2005
Barrier : Boolean := False;
pragma Volatile (Barrier); – Shared_Data and Barrier can never be in
cache
task Producer with CPU => 1;
task Consumer with CPU => 2;
• In Ada 2012
task body Producer is
begin – Shared_Data and Barrier can be in cache
…
Produce (Shared_Data);
Barrier := True;
…
end Producer;
task body Consumer is
begin
…
while not Barrier loop
null;
end loop;
-- If we see that Barrier has been updated,
-- we must see the produced value of
-- Shared_Data.
Use(Shared_Data);
…
end Consumer;
Copyright © 2012 AdaCore Slide: 58
59. Conclusion
• There is support in programming environments for high-integrity
• Embedded programming can use high-level abstraction constructs
• Real-time support
– Computational model amenable to timing analysis
• Ada has supported execution on parallel architectures since its inception
– Ada 2012 dispatching domains
– Good flexibility and analyzability
– Implementable on top of typical operating systems and kernels
– Ravenscar for multiprocessors
– Simple extension to Ravenscar on monoprocessors
– Partitioning into a set of monoprocessor Ravenscar systems
– Keep desired properties found in monoprocessor Ravenscar
Copyright © 2012 AdaCore Slide: 59