• Main Page
  • Classes
  • Files
  • File List

CEventQueue.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2012 Bolton Software Ltd.
00004  * Copyright (C) 2004 Chris Schoeneman
00005  * 
00006  * This package is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * found in the file COPYING that should have accompanied this file.
00009  * 
00010  * This package is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include "CEventQueue.h"
00020 #include "CLog.h"
00021 #include "CSimpleEventQueueBuffer.h"
00022 #include "CStopwatch.h"
00023 #include "IEventJob.h"
00024 #include "CArch.h"
00025 
00026 // interrupt handler.  this just adds a quit event to the queue.
00027 static
00028 void
00029 interrupt(CArch::ESignal, void*)
00030 {
00031     EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
00032 }
00033 
00034 
00035 //
00036 // CEventQueue
00037 //
00038 
00039 CEventQueue::CEventQueue() :
00040     m_nextType(CEvent::kLast)
00041 {
00042     setInstance(this);
00043     m_mutex = ARCH->newMutex();
00044     ARCH->setSignalHandler(CArch::kINTERRUPT, &interrupt, NULL);
00045     ARCH->setSignalHandler(CArch::kTERMINATE, &interrupt, NULL);
00046     m_buffer = new CSimpleEventQueueBuffer;
00047 }
00048 
00049 CEventQueue::~CEventQueue()
00050 {
00051     delete m_buffer;
00052     ARCH->setSignalHandler(CArch::kINTERRUPT, NULL, NULL);
00053     ARCH->setSignalHandler(CArch::kTERMINATE, NULL, NULL);
00054     ARCH->closeMutex(m_mutex);
00055     setInstance(NULL);
00056 }
00057 
00058 void
00059 CEventQueue::loop()
00060 {
00061     CEvent event;
00062     getEvent(event);
00063     while (event.getType() != CEvent::kQuit) {
00064         dispatchEvent(event);
00065         CEvent::deleteData(event);
00066         getEvent(event);
00067     }
00068 }
00069 
00070 CEvent::Type
00071 CEventQueue::registerType(const char* name)
00072 {
00073     CArchMutexLock lock(m_mutex);
00074     m_typeMap.insert(std::make_pair(m_nextType, name));
00075     m_nameMap.insert(std::make_pair(name, m_nextType));
00076     LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
00077     return m_nextType++;
00078 }
00079 
00080 CEvent::Type
00081 CEventQueue::registerTypeOnce(CEvent::Type& type, const char* name)
00082 {
00083     CArchMutexLock lock(m_mutex);
00084     if (type == CEvent::kUnknown) {
00085         m_typeMap.insert(std::make_pair(m_nextType, name));
00086         m_nameMap.insert(std::make_pair(name, m_nextType));
00087         LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
00088         type = m_nextType++;
00089     }
00090     return type;
00091 }
00092 
00093 const char*
00094 CEventQueue::getTypeName(CEvent::Type type)
00095 {
00096     switch (type) {
00097     case CEvent::kUnknown:
00098         return "nil";
00099 
00100     case CEvent::kQuit:
00101         return "quit";
00102 
00103     case CEvent::kSystem:
00104         return "system";
00105 
00106     case CEvent::kTimer:
00107         return "timer";
00108 
00109     default:
00110         CTypeMap::const_iterator i = m_typeMap.find(type);
00111         if (i == m_typeMap.end()) {
00112             return "<unknown>";
00113         }
00114         else {
00115             return i->second;
00116         }
00117     }
00118 }
00119 
00120 void
00121 CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
00122 {
00123     CArchMutexLock lock(m_mutex);
00124 
00125     LOG((CLOG_DEBUG "adopting new buffer"));
00126 
00127     if (m_events.size() != 0) {
00128         // this can come as a nasty surprise to programmers expecting
00129         // their events to be raised, only to have them deleted.
00130         LOG((CLOG_DEBUG "discarding %d event(s)", m_events.size()));
00131     }
00132 
00133     // discard old buffer and old events
00134     delete m_buffer;
00135     for (CEventTable::iterator i = m_events.begin(); i != m_events.end(); ++i) {
00136         CEvent::deleteData(i->second);
00137     }
00138     m_events.clear();
00139     m_oldEventIDs.clear();
00140 
00141     // use new buffer
00142     m_buffer = buffer;
00143     if (m_buffer == NULL) {
00144         m_buffer = new CSimpleEventQueueBuffer;
00145     }
00146 }
00147 
00148 bool
00149 CEventQueue::getEvent(CEvent& event, double timeout)
00150 {
00151     CStopwatch timer(true);
00152 retry:
00153     // if no events are waiting then handle timers and then wait
00154     while (m_buffer->isEmpty()) {
00155         // handle timers first
00156         if (hasTimerExpired(event)) {
00157             return true;
00158         }
00159 
00160         // get time remaining in timeout
00161         double timeLeft = timeout - timer.getTime();
00162         if (timeout >= 0.0 && timeLeft <= 0.0) {
00163             return false;
00164         }
00165 
00166         // get time until next timer expires.  if there is a timer
00167         // and it'll expire before the client's timeout then use
00168         // that duration for our timeout instead.
00169         double timerTimeout = getNextTimerTimeout();
00170         if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) {
00171             timeLeft = timerTimeout;
00172         }
00173 
00174         // wait for an event
00175         m_buffer->waitForEvent(timeLeft);
00176     }
00177 
00178     // get the event
00179     UInt32 dataID;
00180     IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID);
00181     switch (type) {
00182     case IEventQueueBuffer::kNone:
00183         if (timeout < 0.0 || timeout <= timer.getTime()) {
00184             // don't want to fail if client isn't expecting that
00185             // so if getEvent() fails with an infinite timeout
00186             // then just try getting another event.
00187             goto retry;
00188         }
00189         return false;
00190 
00191     case IEventQueueBuffer::kSystem:
00192         return true;
00193 
00194     case IEventQueueBuffer::kUser:
00195         {
00196             CArchMutexLock lock(m_mutex);
00197             event = removeEvent(dataID);
00198             return true;
00199         }
00200 
00201     default:
00202         assert(0 && "invalid event type");
00203         return false;
00204     }
00205 }
00206 
00207 bool
00208 CEventQueue::dispatchEvent(const CEvent& event)
00209 {
00210     void* target   = event.getTarget();
00211     IEventJob* job = getHandler(event.getType(), target);
00212     if (job == NULL) {
00213         job = getHandler(CEvent::kUnknown, target);
00214     }
00215     if (job != NULL) {
00216         job->run(event);
00217         return true;
00218     }
00219     return false;
00220 }
00221 
00222 void
00223 CEventQueue::addEvent(const CEvent& event)
00224 {
00225     // discard bogus event types
00226     switch (event.getType()) {
00227     case CEvent::kUnknown:
00228     case CEvent::kSystem:
00229     case CEvent::kTimer:
00230         return;
00231 
00232     default:
00233         break;
00234     }
00235     
00236     if ((event.getFlags() & CEvent::kDeliverImmediately) != 0) {
00237         dispatchEvent(event);
00238         CEvent::deleteData(event);
00239     }
00240     else {
00241         CArchMutexLock lock(m_mutex);
00242         
00243         // store the event's data locally
00244         UInt32 eventID = saveEvent(event);
00245         
00246         // add it
00247         if (!m_buffer->addEvent(eventID)) {
00248             // failed to send event
00249             removeEvent(eventID);
00250             CEvent::deleteData(event);
00251         }
00252     }
00253 }
00254 
00255 CEventQueueTimer*
00256 CEventQueue::newTimer(double duration, void* target)
00257 {
00258     assert(duration > 0.0);
00259 
00260     CEventQueueTimer* timer = m_buffer->newTimer(duration, false);
00261     if (target == NULL) {
00262         target = timer;
00263     }
00264     CArchMutexLock lock(m_mutex);
00265     m_timers.insert(timer);
00266     // initial duration is requested duration plus whatever's on
00267     // the clock currently because the latter will be subtracted
00268     // the next time we check for timers.
00269     m_timerQueue.push(CTimer(timer, duration,
00270                             duration + m_time.getTime(), target, false));
00271     return timer;
00272 }
00273 
00274 CEventQueueTimer*
00275 CEventQueue::newOneShotTimer(double duration, void* target)
00276 {
00277     assert(duration > 0.0);
00278 
00279     CEventQueueTimer* timer = m_buffer->newTimer(duration, true);
00280     if (target == NULL) {
00281         target = timer;
00282     }
00283     CArchMutexLock lock(m_mutex);
00284     m_timers.insert(timer);
00285     // initial duration is requested duration plus whatever's on
00286     // the clock currently because the latter will be subtracted
00287     // the next time we check for timers.
00288     m_timerQueue.push(CTimer(timer, duration,
00289                             duration + m_time.getTime(), target, true));
00290     return timer;
00291 }
00292 
00293 void
00294 CEventQueue::deleteTimer(CEventQueueTimer* timer)
00295 {
00296     CArchMutexLock lock(m_mutex);
00297     for (CTimerQueue::iterator index = m_timerQueue.begin();
00298                             index != m_timerQueue.end(); ++index) {
00299         if (index->getTimer() == timer) {
00300             m_timerQueue.erase(index);
00301             break;
00302         }
00303     }
00304     CTimers::iterator index = m_timers.find(timer);
00305     if (index != m_timers.end()) {
00306         m_timers.erase(index);
00307     }
00308     m_buffer->deleteTimer(timer);
00309 }
00310 
00311 void
00312 CEventQueue::adoptHandler(CEvent::Type type, void* target, IEventJob* handler)
00313 {
00314     CArchMutexLock lock(m_mutex);
00315     IEventJob*& job = m_handlers[target][type];
00316     delete job;
00317     job = handler;
00318 }
00319 
00320 void
00321 CEventQueue::removeHandler(CEvent::Type type, void* target)
00322 {
00323     IEventJob* handler = NULL;
00324     {
00325         CArchMutexLock lock(m_mutex);
00326         CHandlerTable::iterator index = m_handlers.find(target);
00327         if (index != m_handlers.end()) {
00328             CTypeHandlerTable& typeHandlers = index->second;
00329             CTypeHandlerTable::iterator index2 = typeHandlers.find(type);
00330             if (index2 != typeHandlers.end()) {
00331                 handler = index2->second;
00332                 typeHandlers.erase(index2);
00333             }
00334         }
00335     }
00336     delete handler;
00337 }
00338 
00339 void
00340 CEventQueue::removeHandlers(void* target)
00341 {
00342     std::vector<IEventJob*> handlers;
00343     {
00344         CArchMutexLock lock(m_mutex);
00345         CHandlerTable::iterator index = m_handlers.find(target);
00346         if (index != m_handlers.end()) {
00347             // copy to handlers array and clear table for target
00348             CTypeHandlerTable& typeHandlers = index->second;
00349             for (CTypeHandlerTable::iterator index2 = typeHandlers.begin();
00350                             index2 != typeHandlers.end(); ++index2) {
00351                 handlers.push_back(index2->second);
00352             }
00353             typeHandlers.clear();
00354         }
00355     }
00356 
00357     // delete handlers
00358     for (std::vector<IEventJob*>::iterator index = handlers.begin();
00359                             index != handlers.end(); ++index) {
00360         delete *index;
00361     }
00362 }
00363 
00364 bool
00365 CEventQueue::isEmpty() const
00366 {
00367     return (m_buffer->isEmpty() && getNextTimerTimeout() != 0.0);
00368 }
00369 
00370 IEventJob*
00371 CEventQueue::getHandler(CEvent::Type type, void* target) const
00372 {
00373     CArchMutexLock lock(m_mutex);
00374     CHandlerTable::const_iterator index = m_handlers.find(target);
00375     if (index != m_handlers.end()) {
00376         const CTypeHandlerTable& typeHandlers = index->second;
00377         CTypeHandlerTable::const_iterator index2 = typeHandlers.find(type);
00378         if (index2 != typeHandlers.end()) {
00379             return index2->second;
00380         }
00381     }
00382     return NULL;
00383 }
00384 
00385 UInt32
00386 CEventQueue::saveEvent(const CEvent& event)
00387 {
00388     // choose id
00389     UInt32 id;
00390     if (!m_oldEventIDs.empty()) {
00391         // reuse an id
00392         id = m_oldEventIDs.back();
00393         m_oldEventIDs.pop_back();
00394     }
00395     else {
00396         // make a new id
00397         id = static_cast<UInt32>(m_events.size());
00398     }
00399 
00400     // save data
00401     m_events[id] = event;
00402     return id;
00403 }
00404 
00405 CEvent
00406 CEventQueue::removeEvent(UInt32 eventID)
00407 {
00408     // look up id
00409     CEventTable::iterator index = m_events.find(eventID);
00410     if (index == m_events.end()) {
00411         return CEvent();
00412     }
00413 
00414     // get data
00415     CEvent event = index->second;
00416     m_events.erase(index);
00417 
00418     // save old id for reuse
00419     m_oldEventIDs.push_back(eventID);
00420 
00421     return event;
00422 }
00423 
00424 bool
00425 CEventQueue::hasTimerExpired(CEvent& event)
00426 {
00427     // return true if there's a timer in the timer priority queue that
00428     // has expired.  if returning true then fill in event appropriately
00429     // and reset and reinsert the timer.
00430     if (m_timerQueue.empty()) {
00431         return false;
00432     }
00433 
00434     // get time elapsed since last check
00435     const double time = m_time.getTime();
00436     m_time.reset();
00437 
00438     // countdown elapsed time
00439     for (CTimerQueue::iterator index = m_timerQueue.begin();
00440                             index != m_timerQueue.end(); ++index) {
00441         (*index) -= time;
00442     }
00443 
00444     // done if no timers are expired
00445     if (m_timerQueue.top() > 0.0) {
00446         return false;
00447     }
00448 
00449     // remove timer from queue
00450     CTimer timer = m_timerQueue.top();
00451     m_timerQueue.pop();
00452 
00453     // prepare event and reset the timer's clock
00454     timer.fillEvent(m_timerEvent);
00455     event = CEvent(CEvent::kTimer, timer.getTarget(), &m_timerEvent);
00456     timer.reset();
00457 
00458     // reinsert timer into queue if it's not a one-shot
00459     if (!timer.isOneShot()) {
00460         m_timerQueue.push(timer);
00461     }
00462 
00463     return true;
00464 }
00465 
00466 double
00467 CEventQueue::getNextTimerTimeout() const
00468 {
00469     // return -1 if no timers, 0 if the top timer has expired, otherwise
00470     // the time until the top timer in the timer priority queue will
00471     // expire.
00472     if (m_timerQueue.empty()) {
00473         return -1.0;
00474     }
00475     if (m_timerQueue.top() <= 0.0) {
00476         return 0.0;
00477     }
00478     return m_timerQueue.top();
00479 }
00480 
00481 CEvent::Type
00482 CEventQueue::getRegisteredType(const CString& name) const
00483 {
00484     CNameMap::const_iterator found = m_nameMap.find(name);
00485     if (found != m_nameMap.end())
00486         return found->second;
00487 
00488     return CEvent::kUnknown;
00489 }
00490 
00491 
00492 //
00493 // CEventQueue::CTimer
00494 //
00495 
00496 CEventQueue::CTimer::CTimer(CEventQueueTimer* timer, double timeout,
00497                 double initialTime, void* target, bool oneShot) :
00498     m_timer(timer),
00499     m_timeout(timeout),
00500     m_target(target),
00501     m_oneShot(oneShot),
00502     m_time(initialTime)
00503 {
00504     assert(m_timeout > 0.0);
00505 }
00506 
00507 CEventQueue::CTimer::~CTimer()
00508 {
00509     // do nothing
00510 }
00511 
00512 void
00513 CEventQueue::CTimer::reset()
00514 {
00515     m_time = m_timeout;
00516 }
00517 
00518 CEventQueue::CTimer&
00519 CEventQueue::CTimer::operator-=(double dt)
00520 {
00521     m_time -= dt;
00522     return *this;
00523 }
00524 
00525 CEventQueue::CTimer::operator double() const
00526 {
00527     return m_time;
00528 }
00529 
00530 bool
00531 CEventQueue::CTimer::isOneShot() const
00532 {
00533     return m_oneShot;
00534 }
00535 
00536 CEventQueueTimer*
00537 CEventQueue::CTimer::getTimer() const
00538 {
00539     return m_timer;
00540 }
00541 
00542 void*
00543 CEventQueue::CTimer::getTarget() const
00544 {
00545     return m_target;
00546 }
00547 
00548 void
00549 CEventQueue::CTimer::fillEvent(CTimerEvent& event) const
00550 {
00551     event.m_timer = m_timer;
00552     event.m_count = 0;
00553     if (m_time <= 0.0) {
00554         event.m_count = static_cast<UInt32>((m_timeout - m_time) / m_timeout);
00555     }
00556 }
00557 
00558 bool
00559 CEventQueue::CTimer::operator<(const CTimer& t) const
00560 {
00561     return m_time < t.m_time;
00562 }

Generated on Fri May 24 2013 00:00:03 for Synergy by  doxygen 1.7.1