CEventQueue.cpp

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

Generated on Fri Nov 6 00:18:44 2009 for synergy-plus by  doxygen 1.4.7