Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

49
Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011

Transcript of Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Page 1: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Concurrent issues in Java, Ada and Posix

Y Kermarrec

Ecole Temps Réel 2011

Page 2: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Aims

To present various forms of concurrency expression

To present issues when integrating concurrency units in programming languages• Support at run time• Integration in the semantics

To compare language approaches (with Java, Ada) and POSIX and to (try to) explain why things are getting complex

… but not to cover everthing !

ETR 2011page 2

Page 3: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Agenda

Concurrency based on API or integrated in languages

Concurrency expression and issues• In Ada, Java and POSIX

Conclusions References to know more

ETR 2011page 3

Page 4: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Why do we need concurrency ?

Because of the inherent parallelism in the real world

And real-time systems are inherently concurrent and their “sequential programming” is a difficult alternative• An alternative is the design of the cyclic execution of a

program sequence to handle the various concurrent activities• This is difficult and when changes occur, everything must be

fixed and redesigned• The resulting programs are confusing, obscure and complex

Operating system have made available processes (at first) and then thread ... for a long time

Page 5: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Created

Non-existingNon-existing

Initializing

Executable

Terminated

A typical thread life cycle

Page 6: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

How to program threads ?

Library approach :• a standard sequential language, e.g. C• a set of packages that provide concurrency• The C program makes calls to the library units

With a dedicated concurrent programming language• Syntax and semantics to deal with concurrency,

synchronization and communication• Tasks are independent, competing and

cooperative/communication (initial proposal with T. Hoare’s CSP)

Nom du cours - Notes de courspage 6

Page 7: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

POSIX thread library

The original Pthreads API was defined in the ANSI/IEEE POSIX 1003.1 - 1995 standard.

The POSIX standard has continued to evolve through revisions (eg version of 2004)

The subroutines which comprise the Pthreads API can be informally organized into four major groups:• Thread management• Mutexes• Condition variables• Synchronization : barriers, locks, ..

ETR 2011page 7

Page 8: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

One API subroutine: Thread creation

pthread_create arguments: • thread: An opaque, unique identifier for the new

thread returned by the subroutine. • attr: An opaque attribute object that may be used to

set thread attributes. You can specify a thread attributes object, or NULL for the default values.

• start_routine: the C routine that the thread will execute once it is created.

• arg: A single argument that may be passed to start_routine. It must be passed by reference. NULL may be used if no argument is to be passed.

ETR 2011page 8

Page 9: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

A simple program (extracted from C)

void *PrintHello(void *threadid) {

long tid;

tid = (long)threadid;

printf("Hello World! It's me, thread #%ld!\n", tid);

pthread_exit(NULL);

}

int main(int argc, char *argv[]) {

pthread_t threads[NUM_THREADS];

int rc; long t;

for(t=0;t<NUM_THREADS;t++){

printf("In main: creating thread %ld\n", t);

rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);

if (rc){ printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); }

/* Last thing that main() should do */

pthread_exit(NULL); }

Page 10: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

A more advanced program (extracted from Blaise Barney’s tutorial)

int main (int argc, char *argv[]) {

pthread_t thread[NUM_THREADS];

pthread_attr_t attr; int rc; long t; void *status;

/* Initialize and set thread detached attribute */

pthread_attr_init(&attr);

pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

for(t=0; t<NUM_THREADS; t++) {

printf("Main: creating thread %ld\n", t);

rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t);

if (rc) { printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); }

}

/* Free attribute and wait for the other threads */

pthread_attr_destroy(&attr);

for(t=0; t<NUM_THREADS; t++) {

rc = pthread_join(thread[t], &status);

if (rc) { printf("ERROR; return code from pthread_join() is %d\n", rc); exit(-1); }

printf("Main: completed join with thread %ld having a status of %ld\n",t,(long)status);

}

printf("Main: program completed. Exiting.\n"); pthread_exit(NULL); }

Page 11: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Issues

Posix thread API : around 100 subroutines• Simple and subtile …• Tough for teaching and labs : do not present the

details! Default values : • Eg attribute value set to NULL for pthread_create

Who is testing return values and error codes ? Implementation dependency and portability ? Semantics ?

ETR 2011page 11

Page 12: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Concurrent programming language

• “Concurrent computing is a form of computing in which programs are designed as collections of interacting computational processes that may be executed in parallel” (BenAri)

• Concurrent Pascal : (begin A, B end)• CSP (and then Occam) with processes and

channels• ... And numerous contributions (Ada, Java, ....)• The emergence of tasks / threads (that may be

implicit or explicit) as units for programmers....• A main program is more or less a process / thread

ETR 2011page 12

Page 13: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Concurrent execution unit

From fine grained (Occam at the instruction level) to coarse granularity (Ada with tasks, Java with threads …)

Initialization with parameter passing when creating the new unit or ‘initial’ communication…

Termination • completion of execution (reaching the end

statement)• suicide• abortion, through the explicit action of another task;• occurrence of an unhandled error• “End” on condition (eg for servers which are

implemented as never ending loops)

Page 14: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Towards hierarchies of concurrent units

Concurrent units are considered as ‘normal’ programming units and therefore can be nested (similar to nested procedures / functions)

Relationships• Creation: Parent/Child - the parent may be delayed

while the child is being created and initialized• Termination: Guardian/Dependant - a task may

depend on a specific unit and this latter cannot terminate before all its dependents are terminated

Very nice for the developer but very strong impact on the run time !!!

Page 15: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Created

Non-existingNon-existing

Initializing

Executable

Terminated

A typical thread life cycle (from A Wellings)

Waiting ChildInitialization

Waiting DependentTermination

Page 16: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Concurrency unit coding

Fork and Join• Inspired from OS features directly• Synchronization between the parent and the

dependant unit Co-begin / Co-end• Transition from the “;” to the “,” and towards

concurrency syntactic expression Explicit Task / Thread construction• Integration of the task in the programming language

features - combination with other features : type, data structures, OO

• Integration into the semanticsETR 2011page 16

Page 17: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Variations in the Task Model structure • static, dynamic

level • Flat or nested

initialization • with or without parameter passing

• => impact at run time

granularity• fine or coarse grain

termination • natural, suicide• abortion, untrapped error• never, when no longer needed

representation • fork/join, cobegin, explicit task

declarations

Page 18: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur-18-

Overview of Ada Concurrency Support (1) Ada 95 preliminaries• Software engineering and real time features from the very

beginning (Ada 83) ; ISO approved ; compiler “validation”• A core language + optional annexes• “Specialized Needs Annexes” to address specific issues:

real time systems, distributed systems, numerics, safety … Basic concurrency model• Unit of concurrency is the task

- Task specification = interface to other tasks- Task body = implementation (algorithm) + own storage area- Task type serves as a template for tasks which perform the same algorithm- Task may be declared or dynamically allocated

Page 19: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Overview of Ada Concurrency Support (2)

Example of a declared task

with Ada.Text_IO;procedure Example1 is Count : Integer := 60; task Writer; -- Specification

task body Writer is – Body -- private declarations begin for I in 1..Count loop Ada.Text_IO.Put_Line( "Hello" & Integer'Image(I)); delay 1.0; -- Suspend for at least 1.0 second end loop; end Writer;begin -- Writer activated null; -- Main procedure suspended until Writer terminatesend Example1;

Page 20: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Overview of Ada Concurrency Support (3)

with Ada.Text_IO;procedure Example2 is task type Writer(Count : Natural); -- Specification

type Writer_Ref is access Writer; Ref : Writer_Ref;

task body Writer is -- Body begin for I in 1..Count loop Ada.Text_IO.Put_Line( "Hello" & I'Img); delay 1.0; -- Suspend for at least 1.0 second end loop; end Writer;

begin Ref := new Writer(60); -- activates new Writer task object -- Main procedure suspended until Writer object terminatesend Example2;

Page 21: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Overview of Ada Concurrency Support (4)

Lifetime properties• Declared task starts (is activated) implicitly at the

begin of parent unit• Allocated task (dynamic with new) starts at the point

of allocation• Task statements execute “concurrently” with

statements of parent• Task completes when it reaches its end• “Master” is suspended when it reaches its end, until

each child task terminates (this is to prevent dangling references to local data)

ETR 2011page 21

Page 22: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Overview of Ada Concurrency Support (5)

Mutual exclusion• Shared data, pragma Volatile / Atomic

• Protected objects / type : Data + “protected” operations that are executed with mutual exclusion (multiple readers or single writer)

• “Passive” task that sequentializes access to a data structure via explicit communication (rendezvous) : only solution with Ada 83

• Explicit mutex-like mechanism (definable as protected object/type) that is locked and unlocked

ETR 2011page 22

Page 23: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur-23-

Overview of Ada Concurrency Support (6)

Coordination / communication• Pass data to task via discriminant (at creation) or

rendezvous • Suspension_Object : A single task can await a given

Suspension_Object becoming “true” and will suspend until another task sets that state.

• Rendezvous model : inter-task communication• Implicit wait for dependent tasks

Asynchrony• Event handling via dedicated task, interrupt handler• abort statement: • Asynchronous transfer of control via timeout or

rendezvous request

Page 24: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Overview of Ada Concurrency Support (7)

Interaction with exception handling• Tasking_Error raised at language-defined points• Task that propagates an (unhandled) exception

terminates silently More features which are extremely powerful:• Select, accept, requeue, …

ETR 2011page 24

Page 25: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Task States in Ada (from A Wellings)

executable

created

non-existing

finalising

activating completed

non-existing

terminated

waiting child activation

create child task

child task activation complete

create child task

child task activation complete

exit a master block

dependent tasks

terminate

waiting dependent termination

exit a master blockdependent tasks

terminate

dependent tasks terminate

Page 26: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Real time system annex

Task Priorities priority Scheduling • TheTask Dispatching Model • The Standard Task Dispatching Policy

priority Ceiling Locking entry Queuing Policies dynamic Priorities preemptive Abort Tasking Restrictions monotonic Time delay Accuracy Synchronous Task Control (suspend_until_true, suspension obj) Asynchronous Task Control (hold, resume on task id)

ETR 2011page 26

Page 27: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Ravenscar : when too much is too much

The Ravenscar profile is a subset of the Ada tasking features designed for safety-critical efficient hard real-time computing

pragma Profile (Ravenscar);

page 27

pragma Task_Dispatching_Policy (FIFO_Within_Priorities);   pragma Locking_Policy (Ceiling_Locking);    pragma Restrictions ( No_Abort_Statements, No_Dynamic_Attachment, No_Dynamic_Priorities, No_Implicit_Heap_Allocations, No_Local_Protected_Objects, No_Local_Timing_Events, No_Protected_Type_Allocators, No_Relative_Delay, No_Requeue_Statements, No_Select_Statements, No_Specific_Termination_Handlers, No_Task_Allocators, No_Task_Hierarchy, No_Task_Termination, Simple_Barriers, Max_Entry_Queue_Length => 1, Max_Protected_Entries => 1, Max_Task_Entries => 0, No_Dependence => Ada.Asynchronous_Task_Control, No_Dependence => Ada.Calendar, No_Dependence => Ada.Execution_Time.Group_Budget, No_Dependence => Ada.Execution_Time.Timers, No_Dependence => Ada.Task_Attributes);

 

Page 28: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

More with Ada for real time

The Ada rationale : A great document for understanding issues with Ada and real time systems in general• http://www.adahome.com/LRM/95/Rationale/

rat95html/rat95-contents.html

ETR 2011page 28

Page 29: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur-29-

Overview of Java Concurrency Support (1) Java Preliminaries• OO language with built-in support for concurrency,

exception handling• Dynamic data model

Basic concurrency model• Unit of concurrency is the thread• Dynamically allocated

- an instance of the class java.lang.Thread or one of its subclasses

- run() method = algorithm performed by each instance of the class

- If implementing Runnable, construct a Thread object passing a Runnable as parameter

Page 30: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur-30-

Overview of Java Concurrency Support (2) Example of simple thread

public class Writer extends Thread{ final int count;

public Writer(int count){this.count=count;}

public void run(){ for (int i=1; i<=count; i++){ System.out.println("Hello " + i); } } public static void main( String[] args ) throws InterruptedException{ Writer w = new Writer(60); w.start(); // New thread of control invokes w.run() w.join(); // Wait for w to terminate } }

Page 31: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Overview of Java Concurrency Support (3)

Lifetime properties• Constructing a thread creates the resources that the

thread needs (stack, etc.)• “Activation” is explicit, by invoking start()• Started thread runs “concurrently” with parent• Thread terminates when its run method returns• Parent does not need to wait for children to

terminate

- Restrictions on “up-level references” from inner classes prevent dangling references to parent stack data

ETR 2011page 31

Page 32: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur-32-

Overview of Java Concurrency Support (4)

Mutual exclusion• Shared data (volatile fields)• synchronized blocks/methods

Thread coordination/communication• Pass data to new thread via constructor• Single event - wait() / notify()• Broadcast event - wait() / notifyAll()• join() suspends caller until the target thread completes

Page 33: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Overview of Java Concurrency Support (5)

Asynchrony• interrupt() sets a bit that can be polled• Asynchronous termination• event / interrupt handling, ATC

Interaction with exception handling• No asynchronous exceptions• Various thread-related exceptions• Thread propagating an unhandled exception

Other functionality• Thread group, dæmon threads, thread local data

ETR 2011page 33

Page 34: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Overview of Java Concurrency Support (6)

Standard Java is not enough to handle real-time constraints.

Java (and JVM) lacks semantic for standard real-time programming techniques.

The lack of confidence in real-time garbage collection is one of the main inhibitors to the widespread use of Java in real-time and embedded systems

Eg, he RTSJ has introduced an additional memory management facility based on the concept of memory areas

ETR 2011page 34

Page 35: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Real-time Spec. for Java (RTSJ)

IBM, Sun and other partners formed Real-time for Java Expert Group sponsored by NIST in 1998.

It came up with RTSJ to fill this gap for real-time systems.

http://www.rtsj.org/ RTSJ proposed seven areas of enhancements to

the standard Java.

ETR 2011page 35

Page 36: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Real-time Spec. for Java (RTSJ)

1. Thread scheduling and dispatching.

2. Memory management.

3. Synchronization and Resource sharing.

4. Asynchronous Event Handling.

5. Asynchronous Transfer of Control.

6. Asynchronous Thread Termination.

7. Physical Memory Access.

ETR 2011page 36

Page 37: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur-37-

Overview of POSIX Concurrency Support (1)

Basic concurrency model• A thread is identified by an instance of (opaque) type

pthread_t

• Threads may be allocated dynamically or declared locally (on the stack) or statically

• Program creates / starts a thread by calling pthread_create, passing an “attributes” structure, the function that the thread will be executing, and the function’s arguments

Page 38: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur-38-

Overview of POSIX Concurrency Support (2)

Lifetime properties• Thread starts executing its thread function as result of

pthread_create, concurrent with creator• Termination

– A thread terminates via a return statement or by invoking pthread_exit - cleanup handlers are

– Here is how to lock a mutex mut in such a way that it will be unlocked if the thread is canceled while mut is locked:

» pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); pthread_mutex_lock(&mut); /* do some work */ pthread_mutex_unlock(&mut);

pthread_cleanup_pop(0);

Page 39: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Overview of POSIX Concurrency Support (3)

• Detachment and recycling– A thread is detachable or joinable– A terminated detachable thread is recycled, releasing all

system resources

• No hierarchical relationship among threads» Created thread has a pointer into its creator’s memory

danger of dangling references

• Main thread is special in that when it returns it terminates the process, killing all other threads

- To avoid this mass killings, main thread can pthread_exit rather than return

ETR 2011page 39

Page 40: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur-40-

Overview of POSIX Concurrency Support (4)

Mutual exclusion• Shared (volatile) data• Mutexes (pthread_mutex_t type) with lock/unlock

functions Coordination / communication• Condition variables (pthread_cond_t type) with pulsed

and broadcast events• Semaphores• Data passed to thread function at pthread_create,

result delivered to “joining” thread at return or pthread_exit

Page 41: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Overview of POSIX Concurrency Support (5)

Asynchrony• Thread cancellation with control over immediacy and

ability to do cleanup Interaction with exception handling• Complicated relationship with signals• Consistent error-return conventions

– The result of each pthread function is an int error code (0 normal)

– If the function needs to return a result, it does so in an address (“&”) parameter

ETR 2011page 41

Page 42: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Agenda

Concurrency based on API or integrated in languages

Concurrency expression and issues• In Ada, Java and POSIX

Conclusions References to know more

ETR 2011page 42

Page 43: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur-43-

Comparison: Basic Model / Lifetime

Points of difference• Nature of unit of concurrency: class, task, function• Implicit versus explicit activation• How parameters / results are passed• What the programmer should perform and

understand !!! Methodology / reliability• Ada and Java provide type checking, prevent

dangling references

Page 44: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Comparison: Basic Model / Lifetime

Flexibility / generality• All three provide roughly the same expressive power• POSIX allows a new thread to be given its

parameters explicitly on thread creation• POSIX allows a thread to return a value to a “joining

thread Efficiency• Ada requires run-time support to manage task

dependence hierarchy

ETR 2011page 44

Page 45: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Comparison: communication/synchronization

A wide spectrum of features:• Locks, semaphores, monitors• Protected objects and rendez-vous for Ada• Various forms of interactions with threads

Returns of experiences• Major changes from Ada 83 to Ada 95 : from

rendezvous to lighter mechanisms• Similar for the definition of RTS Java

ETR 2011page 45

Page 46: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Final words ?

Hard to compare! And the selection of criteria is arguable• Clarity / precision of the concepts• Teaching and use• Assumed programmer expertise• Assumed programmer actions

=> I am back with Ada for teaching concurrency• Rules and issues can be raised and discussed• Ada provides several paradigms … and the

transition to Java is straightforward• GNAT and RTEMS to connect to POSIX

ETR 2011page 46

Page 47: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

To know more …

A more complete comparison of features• http://cs.nyu.edu/courses/fall02

A. Wellings’ courseware material• http://www.cs.york.ac.uk/rts/books/

RTSbookFourthEdition/slides/ POSIX tutorial : B Barney from L Livermore labs• https://computing.llnl.gov/tutorials/pthreads/

RTEMS and GNAT• http://rtems.org/

ETR 2011page 47

Page 48: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Great books ...

ETR 2011page 48

Page 49: Concurrent issues in Java, Ada and Posix Y Kermarrec Ecole Temps Réel 2011.

Dpt/Auteur

Web site

http://public.enst-bretagne.fr/~kermarre/Ada/ http://public.enst-bretagne.fr/~kermarre/ETR2011

ETR 2011page 49