<
aspect xmlns:cpp="
http://www.sdml.info/srcML/cpp"
xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsl="
http://www.w3.org/1999/XSL/Transform"
xmlns="
http://control.ee.ethz.ch/XWeaver/AspectX"
xmlns:src="
http://www.sdml.info/srcML/src"
xsi:schemaLocation="
http://control.ee.ethz.ch/XWeaver/AspectX ../../../../src/xsd/aspectX.xsd"
name="
PassiveToSporadic">
<
description>
This sample aspect transforms passive classes into active (sporadic) classes. A <
i>
passive class</
i>
is a class whose object instances do not
have their own execution thread. An <
i>
active class</
i>
is instead a class whose instances
have an execution thread associated to them.
This apsect demonstrates how to turn a passive class into a <
i>
sporadic class</
i>
i.e. a class with its own
thread of execution that is triggered by some external entity.
<
p />
This aspect operates on base code that sporadically calls <
code>
activate()</
code>
method
of class <
code>
Task</
code>
. These calls are invoked from the function
<
code>
scheduler()</
code>
which acts as a source of sporadic triggers.
<
p />
The aspect replaces the original <
code>
activate()</
code>
function defined in the passive class
by the a new function <
code>
_activate()</
code>
. This function contain an infinite loop.
On every cycle the <
i>
condition variable</
i>
<
code>
trigger</
code>
is checked. If
it has a zero value the execution of the thread is suspended until the value of the
<
code>
trigger</
code>
variable is non-zero. On release the original function
<
code>
activate()</
code>
is called. At the end of every cycle the value of the trigger is set back to
zero.
<
p />
Since the trigger acts act as a <
i>
condition variable</
i>
it has to be protected
against access by more then one thread at the same time. The protection
if this critical section is implemented using <
code>
mutex</
code>
object.
<
p />
The aspect also replaces the body of the original <
code>
scheduler()</
code>
function
by function <
code>
_scheduler()</
code>
.
It creates and runs the thread of the <
code>
Task</
code>
object. It also emulates
two sporadic events by setting up the <
code>
trigger</
code>
to non-zero values.
<
p />
The activation code uses synchronization primitives provided by the POSIX standard.
<
author>
A. Pasetti, O. Rohlik</
author>
<
see>
PassiveToCyclical</
see>
<
see>
Entry</
see>
</
description>
<
pointcut name="
targetInitializationUnit"
type="
src:unit">
<
description>
Points to the <
code>
unit</
code>
that contains <
code>
main()</
code>
method. In srcML, a <
code>
unit</
code>
is
a source file (a definition file, a declaration file, or
an inline file). The pointcut is restricted to include only those units that contain
function whose full name is 'main'.
</
description>
<
restriction type="
contain">
<
pointcut type="
src:function"
constraint="
src:name='main'" />
</
restriction>
</
pointcut>
<
pointcut name="
targetSchedulerMethodBody"
type="
src:block"
constraint="
../src:name='scheduler' and ../src:block[1]">
<
description>
Points to the body of the function <
code>
scheduler()</
code>
.
</
description>
</
pointcut>
<
pointcut name="
targetTaskClassDeclaration"
type="
src:class"
constraint="
contains(src:name,'Task')">
<
description>
Points to the target class to which the declaration of the <
code>
_activate()</
code>
method
should be added. The class that must be modified is identified by its full name: <
code>
Task</
code>
.
</
description>
</
pointcut>
<
pointcut name="
targetTaskClassDefinition"
type="
src:unit">
<
description>
Points to the target unit where is defined class <
code>
Task</
code>
.
</
description>
<
restriction type="
isDefinitionOf">
<
pointcutRef ref="
targetTaskClassDeclaration"
type="
src:class" />
</
restriction>
</
pointcut>
<
advice type="
add"
name="
addSynchronizationDefinition">
<
description>
Adds declaration and initialization of three variables
needed to implement the mutual exclusive access
to the condition variable <
code>
trigger</
code>
.
<
p />
This advice has to precede other advices that modify code
in the main unit.
</
description>
<
pointcutRef ref="
targetInitializationUnit"
type="
src:unit" />
<
codeModifier type="
declaration">
<
text>
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;</
text>
<
text>
pthread_cond_t condvar=PTHREAD_COND_INITIALIZER;</
text>
<
text>
int trigger = 0;</
text>
<
text />
</
codeModifier>
</
advice>
<
advice type="
add"
name="
addSynchronizationDeclaration">
<
description>
Adds <
i>
external</
i>
declaration of three variables
needed to implement the mutual exclusive access
to the condition variable <
code>
trigger</
code>
.
</
description>
<
pointcutRef ref="
targetTaskClassDefinition"
type="
src:unit" />
<
codeModifier type="
definition">
<
text>
extern pthread_mutex_t mutex;</
text>
<
text>
extern pthread_cond_t condvar;</
text>
<
text>
extern int trigger;</
text>
</
codeModifier>
</
advice>
<
advice name="
addSporadicActivateDeclaraion"
type="
add">
<
description>
Add declaration of <
code>
_activate()</
code>
method to the class declaration.
This method is to be called as a POSIX thread. Therefore its
return value must be a pointer (<
code>
void *</
code>
) and must have
one untyped pointer as a parameter.
</
description>
<
pointcutRef ref="
targetTaskClassDeclaration"
type="
src:class" />
<
codeModifier type="
declaration">
<
accessModifier type="
public" />
<
text>
void * _activate(void * param); // added by aspect </
text>
</
codeModifier>
</
advice>
<
advice name="
addSporadicActivateDefinition"
type="
add">
<
description>
Add definition of <
code>
_activate()</
code>
method to class definition files.
<
p />
The method body contains an infinite loop. The <
code>
activate()</
code>
method of the
same class is called if the condition variable has non-zero value.
</
description>
<
pointcutRef ref="
targetTaskClassDefinition"
type="
src:unit" />
<
codeModifier type="
definition">
<
accessModifier type="
public" />
<
text>
void * Task::_activate(void * param){
cout << "Sporadic task running..." << endl;
while(1) {
pthread_mutex_lock(&mutex);
while (!trigger) { // non-zero value == do action, otherwise wait
pthread_cond_wait(&condvar,&mutex); // waits for notification
}
cout << endl << "Sporadic task triggered..." << endl;
activate();
cout << "Sporadic task waiting for next trigger..." << endl;
trigger=0; // it is over, trigger is set back to zero
pthread_cond_signal(&condvar); // notify others that trigger is available
pthread_mutex_unlock(&mutex); // release mutex
}
}
</
text>
</
codeModifier>
</
advice>
<
advice name="
addActivationHelperFunctions"
type="
add">
<
description>
Adds definition of helper a function
<
code>
_activate()</
code>
to tha main program unit. This function
activates the thread of a sporadic object. It
passes the call to the <
code>
_activate()</
code>
method of the object
<
code>
task</
code>
- an instance of class <
code>
Task</
code>
.
Helper functions are used because POSIX function
<
code>
pthread_create()</
code>
does not allow
to use <
i>
C++ method</
i>
as a parameter - only <
i>
C functions</
i>
are accepted.
</
description>
<
pointcutRef ref="
targetInitializationUnit"
type="
src:unit" />
<
codeModifier type="
definition">
<
text>
void * _activate(void * param) {
return task._activate(param);
}
</
text></
codeModifier>
</
advice>
<
advice type="
add"
name="
addIncludesToMain">
<
description>
Add the <
code>
#include "main.h"</
code>
preprocessor instruction.
Header file <
code>
main.h</
code>
contains signature of function
<
code>
_activate()</
code>
which is inserted to the main module. Since
function is woven at the end of the file its declarations have to
be inserted at the beginning of the unit using the header file.
</
description>
<
pointcutRef ref="
targetInitializationUnit"
type="
src:unit" />
<
codeModifier type="
include">
<
text>
#include "main.h" // added by aspect </
text>
</
codeModifier>
</
advice>
<
advice name="
replaceSchedulerBody"
type="
around">
<
description>
Replaces the body of <
code>
schedule()</
code>
function.
It inserts the code that
initialize the thread of an active object, emulates
two sporadic events by setting the <
code>
trigger</
code>
variable to non-zero value, and suspend the
execution of the main thread.
<
p />
he threads are executed using helper functions
<
code>
_activate()</
code>
that passes the call to the <
code>
_activate()</
code>
method
defined in the class <
code>
Task</
code>
.
</
description>
<
pointcutRef ref="
targetSchedulerMethodBody"
type="
src:block" />
<
codeModifier type="
codeFragment">
<
text>
int retcode;
pthread_t a;
void * retval;
cout << "Scheduler starts, it triggers the sporadic task in t=0+2 and t=0+5 " << endl;
retcode = pthread_create(&a, NULL, _activate, NULL);
if (retcode != 0) cerr << "Create failed " << retcode << endl;
cout << "Sporadic class activated, waiting for external trigger (it will come in 2 seconds) " << endl;
MicroTime::microSleep(2000000);
pthread_mutex_lock(&mutex);
trigger = 1; // set up condvar to non-zero value
pthread_cond_signal(&condvar);
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&condvar);
MicroTime::microSleep(3000000); // another activation comes after 3 seconds
pthread_mutex_lock(&mutex);
trigger = 2; // set up condvar to non-zero value
pthread_cond_signal(&condvar);
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&condvar);
retcode = pthread_join(a, &retval);
if (retcode != 0) cerr << "Join failed " << retcode << endl;
return 0; </
text></
codeModifier>
</
advice>
</
aspect>
v