///////////////////////////////////////////////////////////////////////////// // 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 //////////////////////////////////////////////////////////////////////////// // class WaitUntilList --- singleton // class WaitUntilList { typedef std::list 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