/////////////////////////////////////////////////////////////////////////////
// facility.cc
//
// SIMLIB version: 2.18
// Date: 2006-10-17
//
// Copyright (c) 1991-2006 Petr Peringer
//
// This library is licensed under GNU Library GPL. See the file COPYING.
//
//
// class Facility implementation
//
////////////////////////////////////////////////////////////////////////////
// interface
//
#include "simlib.h"
#include "internal.h"
////////////////////////////////////////////////////////////////////////////
// implementation
//
SIMLIB_IMPLEMENTATION
// don't change!!!
#define _OWNQ1 0x01
#define CHECKQUEUE(qptr) if (!qptr) SIMLIB_error(QueueRefError)
#define CHECKFACILITY(fptr) if (!fptr) SIMLIB_error(FacilityRefError)
#define CHECKENTITY(fptr) if (!fptr) SIMLIB_error(EntityRefError)
////////////////////////////////////////////////////////////////////////////
// constructors
//
Facility::Facility()
{
dprintf(("Facility::Facility()"));
_Qflag = 0;
Q1 = new Queue("Q1");
_Qflag |= _OWNQ1;
Q2 = new Queue("Q2");
in = NULL;
}
Facility::Facility(const char *name)
{
dprintf(("Facility::Facility(\"%s\")", name));
SetName(name);
_Qflag = 0;
Q1 = new Queue("Q1");
_Qflag |= _OWNQ1;
Q2 = new Queue("Q2");
in = NULL;
}
Facility::Facility(Queue * queue)
{
dprintf(("Facility::Facility(%s)", queue->Name()));
_Qflag = 0;
CHECKQUEUE(queue);
Q1 = queue;
Q2 = new Queue("Q2");
in = NULL;
}
Facility::Facility(const char *name, Queue * queue)
{
dprintf(("Facility::Facility(\"%s\",%s)", name, queue->Name()));
SetName(name);
_Qflag = 0;
CHECKQUEUE(queue);
Q1 = queue;
Q2 = new Queue("Q2");
in = NULL;
}
////////////////////////////////////////////////////////////////////////////
// destructor
//
Facility::~Facility()
{
dprintf(("Facility::~Facility() // \"%s\" ", Name()));
Clear();
if (OwnQueue())
delete Q1; // delete input queue
delete Q2;
}
////////////////////////////////////////////////////////////////////////////
// SetQueue
//
void Facility::SetQueue(Queue * queue)
{
CHECKFACILITY(this);
CHECKQUEUE(queue);
if (OwnQueue()) {
if (QueueLen() > 0)
SIMLIB_warning(SetQueueError);
delete Q1; // delete internal input queue
_Qflag &= ~_OWNQ1;
}
Q1 = queue;
}
////////////////////////////////////////////////////////////////////////////
// Seize -- seize facility by entity e
//
// possible waiting in queue
//
void Facility::Seize(Entity * e, ServicePriority_t sp)
{
//
// TODO: remove parameter e, use Current
//
dprintf(("%s.Seize(%s,%u)", Name(), e->Name(), (unsigned) sp));
CHECKFACILITY(this);
CHECKENTITY(e);
if (e != Current)
SIMLIB_error(EntityRefError);
e->_SPrio = sp;
if (!Busy()) {
in = e; // seize by entity
tstat(1); // update statistics
return;
}
if (sp > in->_SPrio) { // special case: service interrupted
dprintf((" service interrupt "));
if (in->Idle())
SIMLIB_error(FacInterruptError);
// compute the rest of service time
in->_RestTime = SQS::ActivationTime(in) - Time;
QueueIn2(*in); // interrupted into queue
in->Passivate(); // wait in queue2 =====================
in = e; // seize by entity
tstat(1); // update statistics
} else { // go into main queue
QueueIn(e, sp); // insert in priority queue
e->Passivate(); // wait in queue, activated by Release()
// =======================================================
// continue after activation
dprintf(("%s.Seize(%s,%u) from Q1", Name(), e->Name(),
(unsigned) sp));
}
}
////////////////////////////////////////////////////////////////////////////
// Release -- release fafility by entity e
//
// release causes Seize if queues not empty
//
void Facility::Release(Entity * e)
{
//
// TODO: remove parameter e, use Current
//
dprintf(("%s.Release(%s)", Name(), e->Name()));
CHECKFACILITY(this);
CHECKENTITY(e);
if (!in)
SIMLIB_error(ReleaseNotSeized); // not seized
if (e != in)
SIMLIB_error(ReleaseError); // seized by other entity
in = NULL; // empty
tstat(0); // record
tstat.n--; // correction !!
bool flag = false; // correction: 5.12.91, bool:1998/08/10
if (!(Q1->empty() || Q2->empty())) {
flag =
(static_cast<Entity *>(Q1->front())->_SPrio >
static_cast<Entity *>(Q2->front())->_SPrio);
}
if (!flag && !Q2->empty()) // interrupt queue not empty
{ // seize from interrupt queue...
// TODO: this is old implementation -- error in statistics, problems
Entity *ent;
ent = static_cast<Entity *>(Q2->GetFirst()); // remove from queue
dprintf(("%s.Seize(%s,%u) from Q2",
Name(), ent->Name(), (unsigned) ent->_SPrio));
in = ent; // seize again
tstat(1);
tstat.n--; // correction !!!
ent->Activate(Time + ent->_RestTime); // schedule end of service
return;
}
if (!Q1->empty()) { // input queue not empty -- seize from Q1
Entity *ent;
ent = Q1->front(); // points to first entity in queue
ent->Out(); // remove from queue
in = ent; // seize by entity [should be here]
tstat(1); // update statistics
ent->Activate(); // activation of entity behavior
return;
}
}
////////////////////////////////////////////////////////////////////////////
// QueueIn -- go into input queue
//
void Facility::QueueIn(Entity * e, ServicePriority_t sp)
{
//
// TODO: remove parameter e, use Current ???
//
dprintf((" %s --> Q1 of %s ", e->Name(), Name()));
CHECKFACILITY(this);
CHECKENTITY(e);
e->_SPrio = sp;
#if 0 // _INS_FROM_BEGIN_SLOWER
Queue::iterator p = Q1->begin();
Queue::iterator end = Q1->end();
ServicePriority_t Sprio = e->_SPrio;
for (; p != end && static_cast<Entity *>(*p)->_SPrio > Sprio; // higher service priority first
++p);
ServicePriority_t prio = e->Priority;
for (; p != end && static_cast<Entity *>(*p)->_SPrio == Sprio && static_cast<Entity *>(*p)->Priority >= prio; // higher priority first
++p);
#else
Queue::iterator begin = Q1->begin();
Queue::iterator p = Q1->end();
ServicePriority_t Sprio = e->_SPrio;
while (p != begin) {
Queue::iterator q = p;
--p;
if (static_cast<Entity *>(*p)->_SPrio >= Sprio) { // higher service priority first
p = q;
break;
}
}
ServicePriority_t prio = e->Priority;
while (p != begin) {
Queue::iterator q = p;
--p;
if (static_cast<Entity *>(*p)->_SPrio > Sprio ||
static_cast<Entity *>(*p)->Priority >= prio) { // higher priority first
p = q;
break;
}
}
#endif
Q1->PredIns(e, p);
}
////////////////////////////////////////////////////////////////////////////
// go into interrupt queue
//
void Facility::QueueIn2(Entity * e)
{
dprintf((" %s --> Q2 of %s", e->Name(), Name()));
ServicePriority_t ps = e->_SPrio;
Queue::iterator p = Q2->begin();
for (; p != Q2->end()
&& static_cast<Entity *>(*p)->_SPrio > ps; // higher service priority first
++p);
ServicePriority_t prio = e->Priority;
for (; p != Q2->end()
&& static_cast<Entity *>(*p)->_SPrio == ps
&& static_cast<Entity *>(*p)->Priority >= prio; // higher priority first
++p);
// next sorting -- _RestTime????###
Q2->PredIns(e, p);
}
////////////////////////////////////////////////////////////////////////////
// initialization
//
void Facility::Clear()
{
CHECKFACILITY(this);
dprintf(("%s.Clear()", Name()));
//////// check !!! ###
// only own queues!!!
//
if (OwnQueue())
Q1->Clear();
Q2->Clear();
tstat.Clear();
in = NULL; // empty
}
////////////////////////////////////////////////////////////////////////////
// have own queue?
//
bool Facility::OwnQueue() const
{
return (_Qflag & _OWNQ1) != 0;
}
// end
syntax highlighted by Code2HTML, v. 0.9.1