/////////////////////////////////////////////////////////////////////////////
// waitunti.cc
//
// SIMLIB version: 2.18
// Date: 2004-01-25
//
// Copyright (c) 1991-2004 Petr Peringer
//
// This library is licensed under GNU Library GPL. See the file COPYING.
//
//
// class WaitUntilList --- not good implementation
// (uses list of waiting processes, and checks conditions after each
// activated event)
// better implementation will use objects in WUexpressions
//
// 199808 updated: uses standard list<>
////////////////////////////////////////////////////////////////////////////
// interface
//
#include "simlib.h"
#include "internal.h"
////////////////////////////////////////////////////////////////////////////
// implementation
//
SIMLIB_IMPLEMENTATION
//==========================================================================
#ifdef NEW_WULIST
#include <list>
////////////////////////////////////////////////////////////////////////////
// class WaitUntilList --- singleton
//
class WaitUntilList {
typedef std::list<Process *> container_t;
container_t l;
static WaitUntilList *instance; // unique list
public:
typedef container_t::iterator iterator;
static iterator begin() { return instance->l.begin(); }
static iterator end() { return instance->l.end(); }
static bool empty() { return instance->l.empty(); }
static void InsertCurrent(); // insert current process into list
static void GetCurrent(); // get current process
static void WU_hook(); // active: next process in WUlist or 0
static void Remove(Process *p) { // find and remove p
dprintf(("WaitUntil::Remove(%s)", p->Name()));
instance->l.remove(p); // should be in list
}
static void clear(); // empty
static void create() { // create single instance
if(instance==0) instance = new WaitUntilList;
else SIMLIB_internal_error(); // called twice
INSTALL_HOOK(WUclear, WaitUntilList::clear);
SIMLIB_atexit(destroy); // last SIMLIB module cleanup calls this
}
static void destroy() { // destroy single instance
clear(); // remove all contents
delete instance;
instance = 0;
}
private:
WaitUntilList() { dprintf(("WaitUntilList::WaitUntilList()")); }
~WaitUntilList() { dprintf(("WaitUntilList::~WaitUntilList()")); }
// destructor never called ###???
static iterator current;
#ifndef NDEBUG
friend void WU_print();
#endif
};
#ifndef NDEBUG
void WU_print() {
_Print("WaitUntilList:\n");
if(WaitUntilList::instance == 0) { _Print("none\n"); return; }
WaitUntilList::iterator i = WaitUntilList::begin();
for( int n=0 ; i!=WaitUntilList::end() ; ++i, ++n )
_Print(" [%d] %s\n", n, (*i)->Name() );
}
#endif
// WaitUntilList single instance
WaitUntilList *WaitUntilList::instance = 0; // static
WaitUntilList::iterator WaitUntilList::current; // static
////////////////////////////////////////////////////////////////////////////
static bool flag = false; // valid iterator in WUList
////////////////////////////////////////////////////////////////////////////
// main WUlist interface function
void WaitUntilList::WU_hook() { // get ptr to next process in WUlist or 0
dprintf(("WaitUntilList::WU_hook"));
// PRECONDITION: WUList not empty
if(WaitUntilList::empty()) // this should never happen
SIMLIB_internal_error();
if(!flag) { // start processing, (first call or after remove)
current = WaitUntilList::begin(); // reset to first process
flag = true;
// loop_count++;
// if(loop_count>LIMIT) error("waituntil-loop");
SIMLIB_Current = *current; // always OK
return;
}
++current; // next waiting process
if( current != WaitUntilList::end() ) { // not end
SIMLIB_Current = *current;
return;
}
flag = false; // no next process --- end of WaitUntil processing
// loop_count = 0;
SIMLIB_Current = 0; // not needed ???###
return;
}
////////////////////////////////////////////////////////////////////////////
// Process::
////////////////////////////////////////////////////////////////////////////
// _WaitUntil --- wait to condition
// this is hidden by macro WaitUntil(b), useable in Process::Behavior
//
bool Process::_WaitUntil(bool test)
{
dprintf(("%s._WaitUntil(%s)", Name(), test?"true":"false" ));
if(test) { // true --- end of wait
WaitUntilList::GetCurrent(); // ***** remove from WUList
_wait_until = false; // not in WUlist
return false; // continue checking WaitUntil condition
} else { // false --- wait
if (SIMLIB_Current != this) SIMLIB_internal_error();
WaitUntilList::InsertCurrent(); // ***** insert into WUList
_wait_until = true; // is in WUlist
Passivate(); // deactivation = wait
return true; // repeat test (after activation)
}
}
////////////////////////////////////////////////////////////////////////////
// _WaitUntilRemove() --- remove process from WUlist (called from destructor)
//
void Process::_WaitUntilRemove() {
if(_wait_until)
WaitUntilList::Remove(this);
_wait_until = false; // is not in WUlist
}
////////////////////////////////////////////////////////////////////////////
// InsertCurrent --- insert current process reference into WUlist
// (only called from Process::_WaitUntil)
//
void WaitUntilList::InsertCurrent()
{
if(flag) return; // is in WUlist
//CONDITION: current process is not in WUlist
Process *e = (Process*) SIMLIB_Current; // static_cast<>
dprintf(("WaitUntilList.Insert(%s)", e->Name()));
if(instance==0)
create(); // create singleton instance
if(empty()) // it was empty
INSTALL_HOOK(WUget_next, WaitUntilList::WU_hook); // install hook
iterator pos;
for( pos = begin(); // find place from beginning
pos != end() && (*pos)->Priority >= e->Priority; // higher first
++pos );
instance->l.insert(pos,e); // insert at position
//e->_wait_until = true; // mark process as inserted
}
////////////////////////////////////////////////////////////////////////////
// GetCurrent --- get selected process from WUlist
// (called from Process::* )
//
void WaitUntilList::GetCurrent()
{
if(!flag) return; // process is not in WUlist
//PRECONDITION: WUlist is initialized, not empty
Process *p = *current;
dprintf(("WaitUntilList.Get(); // \"%s\" ", p->Name()));
instance->l.erase(current); // remove item pointed by iterator (fast)
if(empty())
INSTALL_HOOK(WUget_next, 0); // uninstall hook if last item removed
flag = false; // iterator invalid, start from beginning
}
////////////////////////////////////////////////////////////////////////////
// clear --- remove all records (called from Init())
//
void WaitUntilList::clear()
{
if(instance==0) return;
// remove all processes in WaitUntilList
// we can do this, because all processes in list are passivated
iterator i=begin();
while(i!=end()) { // destroy all processes in WUlist
Process *p = *i;
++i;
p->_WaitUntilRemove(); // unmark and remove process
if( p->IsAllocated() ) delete p; // the same behavior as Calendar###???
}
if(!instance->l.empty())
SIMLIB_internal_error(); // for sure
INSTALL_HOOK(WUget_next, 0); // uninstall hook if empty
}
#else // old waul
static int _WUFlag = false; // in-test flag ###
class WaitUntilList; // (internal)
////////////////////////////////////////////////////////////////////////////
// class WUEventNotice = item of WaitUntilList
//
class WUEventNotice : public Link {
public:
Process *Ent; // which process has record
//
WUEventNotice(Process *e) : Link(0,0,0) { Ent = e; }
~WUEventNotice() { // remove from WUList
/*if(where()!=0)*/ Out();
}
void Output() {};
virtual const char * Name() { return "WUEventNotice"; }
//
friend class WaitUntilList;
};
////////////////////////////////////////////////////////////////////////////
// class WaitUntilList
//
class WaitUntilList : List {
public:
typedef List::iterator iterator;
WaitUntilList();
~WaitUntilList();
virtual void Output() {};
virtual const char *Name() { return "WaitUntilList"; };
List::empty; // public
List::begin; // public
List::end; // public
void Insert(Process *p); // insert p into list
Process *GetCurrent(); // get active process
void clear(); // empty
List::iterator act; // activity
bool active() { return act!=end(); }
Process *front() {
act=List::begin();
return active() ? ((WUEventNotice*)*act)->Ent : 0;
}
Process *next() {
++act;
return active() ? ((WUEventNotice*)*act)->Ent : 0;
}
};
////////////////////////////////////////////////////////////////////////////
// object WaitUntilList
//
static WaitUntilList WUList; // unique list
#ifndef NDEBUG
void WU_print() {
WaitUntilList::iterator i = WUList.begin();
for( int n=0 ; i!=WUList.end() ; ++i, ++n )
_Print(" [%d] %s\n", n, ((WUEventNotice*)*i)->Ent->Name() );
}
#endif
////////////////////////////////////////////////////////////////////////////
// SIMLIB_DoActions -- central calling of interruptible procedures !!!
//
// Warning!!!:
// SIMLIB_Current->_Run() _must_ be called only from this function!!!
// achieved by friendship
//
void SIMLIB_DoActions()
{
SIMLIB_Current->_Run(); // perform event -- dispatch
// test all WaitUntil conditions
if (!WUList.empty()) {
dprintf(("*START SIMLIB_WaitUntilTests"));
SIMLIB_Current = WUList.front();
while(SIMLIB_Current!=0) {
_WUFlag = true; // Current is from WAUL, not Calendar!
SIMLIB_Current->_Run(); // problem deleting active item!!!
_WUFlag = false;
if(!WUList.active()) // activity lost
SIMLIB_Current = WUList.front(); // activity to first ###!!!
else
SIMLIB_Current = WUList.next(); // activity to next
}
dprintf(("*END SIMLIB_WaitUntilTests"));
}
}
////////////////////////////////////////////////////////////////////////////
// _WaitUntil -- wait to condition
//
int Process::_WaitUntil(int test)
{
dprintf(("%s._WaitUntil(%s)",Name(),test?"true":"false"));
if(test) { // true -- end of wait
if (_WUFlag) WUList.GetCurrent(); // from WUList
return false; // continue
} else { // false -- wait
if (!_WUFlag) WUList.Insert(this); // into WUList
Passivate(); // deactivation = wait
return true; // repeat test (after activation)
}
}
////////////////////////////////////////////////////////////////////////////
// Insert -- in WUList
//
void WaitUntilList::Insert(Process *e)
{
dprintf(("WaitUntilList.Insert(%s)",e->Name()));
WUEventNotice *evn = new WUEventNotice(e);
Entity::tPriority prio = e->Priority;
List::iterator p = begin();
for( ;
p!=end() &&
((WUEventNotice *)(*p))->Ent->Priority >= prio; // higher first
++p);
List::PredIns((Link*)evn,*p);
}
////////////////////////////////////////////////////////////////////////////
// GetCurrent -- get current process record
//
Process *WaitUntilList::GetCurrent()
{
if(empty())
SIMLIB_error(EmptyWUListError);
Process *e = ((WUEventNotice*)*act)->Ent;
dprintf(("WaitUntilList.GetCurrent(); // \"%s\" ", e->Name()));
delete *act; // out of list, disconnect entity, remove
act = begin(); // reset activity
_WUFlag = false; // must be!!! ###???
return e; // entity
}
////////////////////////////////////////////////////////////////////////////
// SIMLIB_WUClear -- remove all items in WaitUntil list
//
void SIMLIB_WUClear()
{
WUList.clear();
}
////////////////////////////////////////////////////////////////////////////
// constructor
//
WaitUntilList::WaitUntilList() : List("WaitUntilList"), act(begin())
{
dprintf(("WaitUntilList::WaitUntilList()"));
if (this!=&WUList) SIMLIB_internal_error();
}
////////////////////////////////////////////////////////////////////////////
// destructor
//
WaitUntilList::~WaitUntilList()
{
dprintf(("WaitUntilList::~WaitUntilList()"));
clear(); // remove
}
////////////////////////////////////////////////////////////////////////////
// Clear -- remove all records
//
void WaitUntilList::clear()
{
while(!empty()) {
WUEventNotice *evn = (WUEventNotice*)GetFirst(); // select
Process *e = evn->Ent;
delete evn; // delete record
if (e->IsAllocated()) delete e; // delete entity
}
}
#endif // new WUlist
// end
syntax highlighted by Code2HTML, v. 0.9.1