a c++ framework for active objects in embedded real-time systems – bridging the gap between...
Post on 20-Dec-2015
221 views
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 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