a c++ framework for active objects in embedded real-time systems – bridging the gap between...

38
A C++ Framework for Active Objects in Embedded Real- Time Systems – bridging the gap between modeling and implementation Michael E. Caspersen Centre for Pervasive Computing Department of Computer Science University of Aarhus, DK

Post on 20-Dec-2015

221 views

Category:

Documents


0 download

TRANSCRIPT

A C++ Framework for Active Objects in

Embedded Real-Time Systems

– bridging the gap between modeling and implementation

Michael E. CaspersenCentre for Pervasive Computing

Department of Computer ScienceUniversity of Aarhus, DK

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 2

Summary

A simple and powerful approach to extending C++ with constructs for object-oriented concurrent programming that

integrates the notions of object and process is based on well-known and well-understood concepts

and constructs

A flexible C++ framework that implements the extension to C++ adapts a target environment to match object models enables a seamless transition from modeling to

implementation

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 3

Overview

Background

Approaches to Combining OO and Concurrency Transformational approaches Hand-in-hand modeling of objects and processes

Language Constructs for Concurrency

A Framework for Active Objects in C++ Bridging the gap Aspects of the Implementation

Application for a CD Player

Concluding Remarks

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 4

Background

Research project in Centre for Object Technology, 1998-2000

Architecture of Embedded Systems

Partners Bang & Olufsen Danfoss The Danish Technological Institute University of Aarhus

Five projects CD Player, B&O Master (TV, Video, Radio, CD) Frequency Converter (general, and for cranes) Flow Measurer

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 5

Combining OO and Concurrency Our focus is on object technology in the context of

embedded real-time systems

A few textbooks exists B. Selic et al., Real-Time Object-Oriented Modeling (1994) M. Awad et al., Object-Oriented Technology for Object-

Oriented Systems – A Practical Approach Using OMT and Fusion (1996) OCTOPUS

B.P. Douglass, Real-Time UML: Developing Efficient Objects for Embedded Systems (1998)

B.P. Douglass, Doing Hard Time (1999)

Transformational approaches (TA) Object modeling task modeling implementation on

the target platform

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 6

The Transformational Approach (TA)

Task design

while2: mov #toc, R1 cmp R1, R2 jmp while2 psh R1 psh PC jsr envoi pop 4 lda R2, x

Code on targetClass model

0..*Master 1..*

CD DVD

PlaybackPower

CD-player0..* 1..*

Media

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 7

TA is Problematic It violates one of the corner stones of object-orientation

maintaining the same fundamental structure at all levels of description

The modeling of domain level concurrency is as important as traditional class modeling

An analysis model that claims to cover all essiential aspects of a domain must encompass a model of concurrency inherent to the domain

Late modeling of concurrency might distort the object model

Modeling of concurrency in terms of low-level message-based communication integrates poorly with method calls in object-oriented languages

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 8

OCTOPUS on TA

The suggestions in the litterature is rooted in necessity, not desire!

Commonly used object-oriented languages, such as C++, are sequential by nature. They do not support implicit concurrency of the objects [...]. Because of this deficiency, the required feature is made available through the operating system. [...]

Unfortunately, this preselection requires a combination of two distinct concepts, processes and objects, which in itself is not without problems. [...]

It may be that the relationship between processes and objects is only a difficulty for practitioners, because the existing litterature does not give a clear answer to the question.

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 9

A Switching of the Mind-Set

The transformational approach

The object structure is transformedto match the target environment

Our approach

The target environment is adopted(once and for all)

to match the object structure

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 10

Classical Concurrency Constructs

Process method where several calls can execute concurrently

Semaphore low-level synchronization primitive with two atomic

operations (signal, wait) Monitor

class with atomic (synchronized) methods

Integrates well with concepts in object-oriented languages!

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 11

Producer/Consumer in C-Pascal

Producer

Buffer

put( )get( )

Consumer

process Producer(b: Buffer); var t: item;begin while true do begin produce(t); b.put(t)end end;

var p: Producer; c: Consumer b: Buffer;begin p(b) || c(b) end.

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 12

Buffer Monitor in C-Pascal

Buffer = monitor procedure entry put(x: item); function entry get(): item; function empty: boolean; function full: boolean; var t: item; count: integer = 0;end;

procedure entry put(x: item);begin await not full; t:= x; count:= count+1end;

if not full then delay(sender);t:= x;count:= count+1;continue(receiver)

var sender, receiver: queue;

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 13

A Concurrency Framework for C++

We have defined CC++ Concurrent C++ = Concurrent Pascal + C++

Two conceivable implementations Language extension (pre-processor) Framework (class library)

We chose the latter...

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 14

The Framework (User Perspective)

New “keywords”entryawait

ConditionMonitor

Process

handleEvent( )

RelTimer AbsTimer

Semaphore

wait( )signal( )

Entry

Monitor

TimerProcess

newRelTimer( )newAbsTimer( )

Timer

start( )stop( )

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 15

Bridging the Gap Between...

ModelingProducer

run( )

<<Active object>>Consumer

run( )

<<Active object>>Buffer

put( )get( )

<<Monitor>>

Implementation

Producer

run( )

Consumer

run( )

Buffer

put( )get( )

ConditionMonitor

Process

Framework

Application

and

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 16

Producer/Consumer in CC++

class Producer : public Process {public: Producer(Buffer _b) : Process() b(_b) {}

virtual void run() { forever { item t; produce(t); b.put(t); } }

private: Buffer& b;};

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 17

Buffer Monitor in CC++

class Buffer : public ConditionMonitor {public: void put(item x); item get();private: bool empty() { ... } bool full() { ... } item t; int count = 0;};

void Buffer::put(item x) {entry await( !full() ); t = x; count++;}

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 18

Aspects of the Implementation (1)

void Buffer::put(item x) { enter();  await( !full() ); t = x; count++;  exit();}

void Buffer::put(item x) { entry await( !full() ); t = x; count++;}

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 19

Aspects of the Implementation (2)

class Monitor { friend class Entry;protected: Monitor(); void enter() { ... s.wait(); ... } void exit() { ... s.signal(); ... } virtual void notifyAll() {}private: Semaphore s; Process* p; // used for nested callsprotected: int entryCount; // used for nested calls};

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 20

Aspects of the Implementation (3)

class Entry {public: Entry(Monitor& mm) : m(mm) { m.enter(); } ~Entry() { m.notifyAll(); m.exit(); }private: Monitor& m;}; #define entry Entry e(*this);

Scoped Locking (Doug Schmidt)

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 21

Aspects of the Implementation (4)

class ConditionMonitor : public Monitor {protected: ConditionMonitor(); void wait() { ... exit(); c.wait(); ... enter(); ) virtual void notifyAll() { ... c.signal(); ... }private: Semaphore c; int conditionCount;}; #define await(cond) while (!(cond)) wait()

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 22

Framework Architecture

Framework AbstractOS

OS 1 OS 2...

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 23

Application for a CD Player

Same principle as in Producer/Consumer, but the run method has vanished from the application code (the traditional “task loop” is inherited from the framework)

The application code becomes essential code (i.e. problem specific code)

The technical details are swept under the rug!

Our driving force was modeling – our motive was “bridging the gap...”

Pleasant side benefit: a considerable reduction of the code size of more than 50% (in some cases up to 85%)

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 24

Class diagram for CD-player

CDModulInterface

isSpinning()spinUp()readTOC()gotoTrack()pollTimeout()stop()check()

<<Interface>>

KeyInterface

TOC

MinTrackMaxTrackLeadOut

CREATE()

TrackInfo

startTimenumber

LoadCD

MasterInterface

receiveTelegram()connected()playing()mediumEnded()requestStby()inStby()noMedium()

<<Interface>>

AudioCD

getCurrentTime()getCurrentTrack()setCurrentTrack()setCurrentToMinTrack()CREATE()

CDSourceControl

connectionState

connect()connected()stbyTimeout()disconnect()

CDLoaderInterface

state

isOpen()isClosed()close()open()

StandbyControl

state

setInStby()CDIsStopped()loaderIsClosed()interruptStby()

PlaybackCD

playState : int

play()newTrack()CDHasEnded()loaderIsClosed()CDIsSpinning()CDIsPressent()powerIsOn()TOCIsAvailable()CDIsUnknownFormat()loaderIsOpend()CDIsStopped()

PowerSupplyInterface

state

on()off()

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 25

Class Diagram, close-up

PlaybackCD

playState : int

play()newTrack()CDHasEnded()loaderIsClosed()CDIsSpinning()CDIsPressent()powerIsOn()TOCIsAvailable()CDIsUnknownFormat()loaderIsOpend()CDIsStopped()

StandbyControl

state

setInStby()CDIsStopped()loaderIsClosed()interruptStby()

PowerSupplyInterface

state

on()off()

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 26

Sequence diagram for CD playback

: CDSourceControl

: PlaybackCD : StandbyControl

: AudioCD : CDModulInterface

: PowerSupplyInterface

: CDLoaderInterface

1: connect( )2: play( )

3: interruptStby( )

5: connect( )

6: connected( )

4: on( )

7: powerIsOn( )

10: spinUp( )

8: isOpen( )

9: isSpinning( )

11: CDIsSpinning( )

12: getCurrentTrack( )

13: gotoTrack( )

14: playing( )

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 27

Sequence diagram, close-up

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 28

PowerSupplyInterface (1)class PowerSupplyInterface : TTimerProcess {public: PowerSupplyInterface(PlaybackCD* thePlayBackCD) { freeOfNoiseTimer = newRelTimer(200, ONE_SHOT, freeOfNoise); powerIsOnTimer = newRelTimer(500, ONE_SHOT, powerIsOn); } void on(); void off();private: void freeOfNoise(); void powerIsOn(); TTimer *freeOfNoiseTimer, *powerIsOnTimer; PlaybackCD *thePlaybackCD; PowerState state;};

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 29

PowerSupplyInterface (2)PowerSupplyInterface::on() { write_port_pin(GP1, ACTIVE); freeOfNoiseTimer->start(); // 200 ms}

PowerSupplyInterface::freeOfNoise() { write_port_pin(GP0, ACTIVE); powerIsOnTimer->start(); // 500 ms}

PowerSupplyInterface::powerIsOn() { state = SOn; thePlaybackCD->powerIsOn();}

PowerSupplyInterface::off() { ... }

turn on main supply;wait 200 ms to avoid noise on serial port;turn on serial port;wait 500 ms to be sure power is on;

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 30

PowerSupplyInterface, before (1)PROCESS power_process(void){ static MESSAGE_BLOCK mb; /* == Initialize Message Block =======*/ initialize_message_block(&mb); /* == Initialize Timer Part ==========*/ /* == Initialize Modules ==========*/ /* == Process loop ===================*/ for (;;) { auto APOS_EVENT apos_event; /* Make Main Command Loop; Await new process job */ do { if( (apos_event = receive_message(qid_power_p, &mb)) == NO_MESSAGE) { if( (apos_event = get_expired_timer()) == NO_EXPIRED_TIMER) { wait_event(); } } } while(apos_event == NO_INFORMATION); switch(apos_event) { case OS_TIMER1: /* === Perform treatment of timeout === */ SERIAL_PORT_ON; control_timer(OS_TIMER2, STOP_TIMER ); initialize_timer(OS_TIMER2, ONE_SHOT, RELATIVE,SERIAL_ON_TIME ); control_timer(OS_TIMER2, RESET_AND_START_TIMER ); break; case OS_TIMER2: /* === Perform treatment of timeout === */ send_message(qid_cd_sys_p,NO_POINTER,POWER_IS_SWITCHED_ON,0); break;

case MESSAGE_ENCLOSED: /* === Perform treatment of data === */ if (mb.event == SWITCH_POWER_ON) { control_timer(OS_TIMER1, STOP_TIMER ); initialize_timer(OS_TIMER1, ONE_SHOT, RELATIVE,POWER_ON_TIME ); control_timer(OS_TIMER1, RESET_AND_START_TIMER ); POWER_PORT_ON; } else if (mb.event == SWITCH_POWER_OFF) control_timer(OS_TIMER1, STOP_TIMER ); control_timer(OS_TIMER2, STOP_TIMER ); SERIAL_PORT_OFF; POWER_PORT_OFF; send_message(qid_cd_sys_p,NO_POINTER,POWER_IS_SWITCHED_OFF,0); }

/* === Release dynamic memory if requested === */ switch (mb.attr) { case NO_POINTER: case DONT_DEALLOCATE_DATA: /* Do nothing */ break;

case FREE_DATA: free((void *)mb.message); break;

case DELETE_DATA: delete_repository((void *)mb.message); break; }

/* === Allways give accept === */ respond_message(&mb); break; } }}

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 31

PowerSupplyInterface, before (2)/*-------------------------------------------------------------- Entry functions--------------------------------------------------------------*/extern void initialize_power_process(void)/*--------------------------------------------------------------Input : -Output : -Store : -Uses : -Function : ---------------------------------------------------------------*/{ write_port_pin(GP0, INACTIVE); write_port_pin(GP1, INACTIVE);

pid_power_p = create_process("POWP", POWER_P_PRIO, STACK_SIZE_POWER_P); activate_process(pid_power_p, power_process); qid_power_p = create_queue("POWQ", UNLIMIT, NEVER_FULL, pid_power_p); connect_timer(pid_power_p, NOF_TIMERS_POWER_P);}/*-------------------------------------------------------------- End module code--------------------------------------------------------------*/

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 32

Critique of Monitors

Monitor

Writer

Readers

. . .

A monitor provides mutual exclusion among all methods; often this is unnecessarily restrictive.

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 33

Alternative: Common Class

Monitor

Writer

Readers

. . .

Peter Møller-Nielsen and Jørgen Staunstrup (1983)

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 34

Alternative: Common Class

Monitor

Writer

Readers

. . .

Peter Møller-Nielsen and Jørgen Staunstrup (1983)

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 35

Common Class, Abstract CodeRWBuffer = common class var state nr, nw: integer; data item: T;

procedure entry write(e: T); begin entry: [when nw + nr = 0 do nw:= nw + 1] body: item:= e exit: [nw:= nw - 1] end;

procedure entry read(var e: T); begin entry: [when nw = 0 do nr:= nr + 1] body: e:= item exit: [nr:= nr - 1] end;

begin nr:= 0; nw:= 0; item:= ... end

I Møller-Nielsens og Staunstrups note præsenteres en implementation af shared class i Concurrent Pascal, og denne er meget kompliceret.

entry- og exit-statements udføres udeleligt og med gensidig udelukkel-se i forhold til alle andre entry- og exit-statements i klassen.

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 36

Common Class in CC++

class RWBuffer : public ConditionMonitor {private: int nr, nw; // state item: T; // data void entryWrite() { entry await(nw + nr == 0); nw++; } void exitWrite() { entry nw--; } void entryRead() { entry await(nw == 0); nr++; } void entryRead() { entry nr--; }public: RWBuffer(T e) : nr(0), nw(0), item(e) { } void write(T e) { entryWrite(); item = e; exitWrite(); } void read(T& e) { entryRead(); e = item; exitRead(); }};

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 37

Concluding Remarks Class modeling and modeling of domain level

concurrency integrates well! Active objects become “first-class-citizens” in all phases,

also in analysis

The class model is maintained throughout We avoid transformations and distortion of the model This is necessary in order to maintain documentation In the technical design, classes may be added (e.g. due to

application of design patterns); in that case it is demanding to have a well-known class model as the basis

Real-Time Operating System (RTOS) The RTOS can be encapsulated in a framework The target environment can be adapted to fit the object

structure, so that the object structure is minimally (i.e. not!) distorted

© Michael E. Caspersen IDA, Sønderborg, 7. februar 2001 38

Web

www.daimi.au.dk/~mec/links.html