Buffer is a concrete class derived from Atomic. This
class has a single input port in, an pull and an out
(in this example, phase is a
string; m_Clients is a buffer keeping incoming clients
whose type is tmValue; m_OAvail is a vector of
boolean values tracking the availability of servers;
m_OSzie stores the number of connected servers; and
send_index is an int which tracks the server index
to which Buffer will send output.
class Buffer: public Atomic {
public:
InputPort* in;
vector<InputPort*> pull;
vector<OutputPort*> out;
protected:
string m_phase;
deque<tmValue*> m_Clients;
vector<bool> m_OAvail;
const int m_Osize;
int send_index;
The function C1 updates member data as a function of an
input event x. If x comes through the input port
in, C1 casts the value of x to tmValue
and pushes it back to the buffer m_Clients. Otherwise,
x comes through one of pull ports. So C1
searches the server index i, checking the identity of
pull[i] and the incoming event's port, and updates
m_OAvail[i]=true which marks the i-th server as
being available.
void C1(const PortValue& x)
{
if(x.port == in){ //receiving a client
tmValue* client = dynamic_cast<tmValue*>(x.value);
if(client) {
m_Clients.push_back(client);
} else
THROW_DEVS_EXCEPTION("Dynamic Casting Failed!");
}
else // receiving a pull signal
{
for(int i=0; i<m_Osize; i++) {
if(x.port == pull[i]) {
m_OAvail[i]= true; // server_i is available
break;
}
}
}
}
The function Matched() first checks to see if there is a
waiting client in m_Clients and then checks to see if there
exists an available server from 0 to m_Osize-1. If a match
is found, the function sets m_OAvail[i]=false, remembers
the index i at send_index, then returns true.
Otherwise it returns false which means no match.
bool Matched()
{
if(m_Clients.empty() == false){
for(int i=0; i < m_Osize; i++){// select server
if(m_OAvail[i] == true){// server i is available
m_OAvail[i]=false;//Mark server_i non-available
send_index = i; // remember i in send_index
return true;
}
}
return false;
}else
return false;
}
The function C2 creates an the output event and removes the
first client from m_Clients when C2's phase is
SENDTO.
void C2(PortValue& y) {
if(m_phase == SENDTO){
y.Set(out[send_index], m_Clients[0]);
m_Clients.pop_front();// remove the first client
}
}
The function init() of Buffer resets phase to
IDLE, assigns m_OAvial[i]=true for all indices, and
clears all clients in m_Clients.
/*virtual*/ void init()
{
m_phase = IDLE;
m_OAvail.clear(); // clear first
for(int i=0; i<m_Osize; i++)
m_OAvail.push_back(true); // add variable
while(m_Clients.empty() == false)
{
tmValue* cl = m_Clients[0];
m_Clients.pop_front();
delete cl;
}
}
Buffer's tau() returns
for IDLE and
returns 2.0 for SENDTO.
/*virtual*/ Time tau() const {
if(m_phase == IDLE)
return DBL_MAX;
else
return 2.0;
}
The input transition function delta_x of Buffer
updates member data by calling C1(x) and then, if the phase
of the server is IDLE, checks the returning value of
Matched(). If the value is true, the phase of the
server changes into SENDTO.
/*virtual*/ bool delta_x(const PortValue& x)
{
C1(x);
if(m_phase == IDLE){
if(Matched()){
m_phase = SENDTO;
return true; // reschedule as active
}
}
return false;
}
When the server is ready to exit the SENDTO state, it gets
y by calling C2(y), if Matched() returns
true, the phase stays at SENDTO. Otherwise, the
phase returns to IDLE.
/*virtual*/ void delta_y(PortValue& y) {
C2(y);
if(Matched())
m_phase = SENDTO;
else
m_phase = IDLE;
}
Recall that Buffer class contains the overriding
Get_Statistics_s() and GetPerformance(), which were
investigated in Section 4.2.3. For the
codes of Buffer::Get_s(), the reader should refer to
Buffer.h.