X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fstructure%2Fevent_mgr.cxx;h=cd3de3b91af7cc0fd7ba569f0e1b3a1de4ee04ca;hb=5b92575ed31ab0577d5ece4da42a88cfb88b4ad7;hp=9ffb184be4d1576bac9b690e9a60ba1c6b3e10ec;hpb=7ae57483f39a6c60703921d930d3bd2bce198f39;p=simgear.git diff --git a/simgear/structure/event_mgr.cxx b/simgear/structure/event_mgr.cxx index 9ffb184b..cd3de3b9 100644 --- a/simgear/structure/event_mgr.cxx +++ b/simgear/structure/event_mgr.cxx @@ -1,258 +1,208 @@ -// -// SGEventMgr.cxx -- Event Manager -// -// Written by Bernie Bright, started April 2002. -// -// Copyright (C) 2002 Curtis L. Olson - curt@me.umn.edu -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// $Id$ - #ifdef HAVE_CONFIG_H # include #endif -#include +#include "event_mgr.hxx" #include -#include "event_mgr.hxx" - -SGEvent::SGEvent() - : _name(""), - _callback(0), - _subsystem(0), - _repeat_value(0), - _initial_value(0), - _ms_to_go(0), - _cum_time(0), - _min_time(100000), - _max_time(0), - _count(0) +void SGEventMgr::add(const std::string& name, SGCallback* cb, + double interval, double delay, + bool repeat, bool simtime) { + // Clamp the delay value to 1 usec, so that user code can use + // "zero" as a synonym for "next frame". + if(delay <= 0) delay = 0.000001; + + SGTimer* t = new SGTimer; + t->interval = interval; + t->callback = cb; + t->repeat = repeat; + t->name = name; + t->running = false; + + SGTimerQueue* q = simtime ? &_simQueue : &_rtQueue; + + q->insert(t, delay); } -SGEvent::SGEvent( const char* name, - SGCallback* cb, - interval_type repeat_value, - interval_type initial_value ) - : _name(name), - _callback(cb), - _subsystem(NULL), - _repeat_value(repeat_value), - _initial_value(initial_value), - _cum_time(0), - _min_time(100000), - _max_time(0), - _count(0) +SGTimer::~SGTimer() { - if (_initial_value < 0) - { - this->run(); - _ms_to_go = _repeat_value; - } - else - { - _ms_to_go = _initial_value; - } + delete callback; + callback = NULL; } -SGEvent::SGEvent( const char* name, - SGSubsystem* subsystem, - interval_type repeat_value, - interval_type initial_value ) - : _name(name), - _callback(NULL), - _subsystem(subsystem), - _repeat_value(repeat_value), - _initial_value(initial_value), - _cum_time(0), - _min_time(100000), - _max_time(0), - _count(0) +void SGTimer::run() { - if (_initial_value < 0) - { - this->run(); - _ms_to_go = _repeat_value; - } - else - { - _ms_to_go = _initial_value; - } + (*callback)(); } - -SGEvent::~SGEvent() +void SGEventMgr::update(double delta_time_sec) { - //delete callback_; + _simQueue.update(delta_time_sec); + + double rt = _rtProp ? _rtProp->getDoubleValue() : 0; + _rtQueue.update(rt); } -void -SGEvent::run() +void SGEventMgr::removeTask(const std::string& name) { - SGTimeStamp start_time; - SGTimeStamp finish_time; - - start_time.stamp(); - - // run the event - if (_callback) - { - (*_callback)(); - } else if (_subsystem) - { - _subsystem->update(_repeat_value); - } - - finish_time.stamp(); - - ++_count; - - unsigned long duration = finish_time - start_time; - - _cum_time += duration; - - if ( duration < _min_time ) { - _min_time = duration; - } - - if ( duration > _max_time ) { - _max_time = duration; - } + SGTimer* t = _simQueue.findByName(name); + if (t) { + _simQueue.remove(t); + } else if ((t = _rtQueue.findByName(name))) { + _rtQueue.remove(t); + } else { + SG_LOG(SG_GENERAL, SG_WARN, "removeTask: no task found with name:" << name); + return; + } + if (t->running) { + // mark as not repeating so that the SGTimerQueue::update() + // will clean it up + t->repeat = false; + } else { + delete t; + } } -void -SGEvent::print_stats() const -{ - SG_LOG( SG_EVENT, SG_INFO, - " " << _name - << " int=" << _repeat_value / 1000.0 - << " cum=" << _cum_time - << " min=" << _min_time - << " max=" << _max_time - << " count=" << _count - << " ave=" << _cum_time / (double)_count ); -} - - +//////////////////////////////////////////////////////////////////////// +// SGTimerQueue +// This is the priority queue implementation: +//////////////////////////////////////////////////////////////////////// -SGEventMgr::SGEventMgr() +SGTimerQueue::SGTimerQueue(int size) { + _now = 0; + _numEntries = 0; + _tableSize = 1; + while(size > _tableSize) + _tableSize = ((_tableSize + 1)<<1) - 1; + + _table = new HeapEntry[_tableSize]; + for(int i=0; i<_tableSize; i++) { + _table[i].pri = 0; + _table[i].timer = 0; + } } -SGEventMgr::~SGEventMgr() + +SGTimerQueue::~SGTimerQueue() { + for(int i=0; i<_numEntries; i++) { + delete _table[i].timer; + _table[i].timer = 0; + } + _numEntries = 0; + delete[] _table; + _table = 0; + _tableSize = 0; } -void -SGEventMgr::init() +void SGTimerQueue::update(double deltaSecs) { - SG_LOG( SG_EVENT, SG_INFO, "Initializing event manager" ); - - event_table.clear(); + _now += deltaSecs; + while(_numEntries && nextTime() <= _now) { + SGTimer* t = remove(); + if(t->repeat) + insert(t, t->interval); + // warning: this is not thread safe + // but the entire timer queue isn't either + t->running = true; + t->run(); + t->running = false; + if (!t->repeat) + delete t; + } } -void -SGEventMgr::reinit() +void SGTimerQueue::insert(SGTimer* timer, double time) { -} + if(_numEntries >= _tableSize) + growArray(); + _numEntries++; + _table[_numEntries-1].pri = -(_now + time); + _table[_numEntries-1].timer = timer; -void -SGEventMgr::bind() -{ + siftUp(_numEntries-1); } -void -SGEventMgr::unbind() +SGTimer* SGTimerQueue::remove(SGTimer* t) { + int entry; + for(entry=0; entry<_numEntries; entry++) + if(_table[entry].timer == t) + break; + if(entry == _numEntries) + return 0; + + // Swap in the last item in the table, and sift down + swap(entry, _numEntries-1); + _numEntries--; + siftDown(entry); + + return t; } -void -SGEventMgr::update( double dt ) +SGTimer* SGTimerQueue::remove() { - int dt_ms = int(dt * 1000); - - if (dt_ms < 0) - { - SG_LOG( SG_GENERAL, SG_ALERT, - "SGEventMgr::update() called with negative delta T" ); - return; + if(_numEntries == 0) { + return 0; + } else if(_numEntries == 1) { + _numEntries = 0; + return _table[0].timer; } - int min_value = 0; - event_container_type::iterator first = event_table.begin(); - event_container_type::iterator last = event_table.end(); - event_container_type::iterator event = event_table.end(); + SGTimer *result = _table[0].timer; + _table[0] = _table[_numEntries - 1]; + _numEntries--; + siftDown(0); + return result; +} - // Scan all events. Run one whose interval has expired. - while (first != last) - { - if (first->update( dt_ms )) - { - if (first->value() < min_value) - { - // Select event with largest negative value. - // Its been waiting longest. - min_value = first->value(); - event = first; - } - } - ++first; +void SGTimerQueue::siftDown(int n) +{ + // While we have children bigger than us, swap us with the biggest + // child. + while(lchild(n) < _numEntries) { + int bigc = lchild(n); + if(rchild(n) < _numEntries && pri(rchild(n)) > pri(bigc)) + bigc = rchild(n); + if(pri(bigc) <= pri(n)) + break; + swap(n, bigc); + n = bigc; } +} - if (event != last) - { - event->run(); - - if (event->repeat_value() > 0) - { - event->reset(); - } - else - { - SG_LOG( SG_GENERAL, SG_DEBUG, "Deleting event " << event->name() ); - event_table.erase( event ); - } +void SGTimerQueue::siftUp(int n) +{ + while((n != 0) && (_table[n].pri > _table[parent(n)].pri)) { + swap(n, parent(n)); + n = parent(n); } + siftDown(n); } -void -SGEventMgr::add( const SGEvent& event ) +void SGTimerQueue::growArray() { - event_table.push_back( event ); - - SG_LOG( SG_EVENT, SG_INFO, "registered event " << event.name() - << " to run every " << event.repeat_value() << "ms" ); + _tableSize = ((_tableSize+1)<<1) - 1; + HeapEntry *newTable = new HeapEntry[_tableSize]; + for(int i=0; i<_numEntries; i++) { + newTable[i].pri = _table[i].pri; + newTable[i].timer = _table[i].timer; + } + delete[] _table; + _table = newTable; } -void -SGEventMgr::print_stats() const +SGTimer* SGTimerQueue::findByName(const std::string& name) const { - SG_LOG( SG_EVENT, SG_INFO, "" ); - SG_LOG( SG_EVENT, SG_INFO, "Event Stats" ); - SG_LOG( SG_EVENT, SG_INFO, "-----------" ); - - event_container_type::const_iterator first = event_table.begin(); - event_container_type::const_iterator last = event_table.end(); - for (; first != last; ++first) - { - first->print_stats(); + for (int i=0; i < _numEntries; ++i) { + if (_table[i].timer->name == name) { + return _table[i].timer; } - - SG_LOG( SG_EVENT, SG_INFO, "" ); + } + + return NULL; }