fixed: events were added before event queue was ready, caused debug build assert failure.

removed sleep hack in favour of cond var wait.
This commit is contained in:
jerry 2014-04-17 10:56:25 +00:00
parent 0d087d4edc
commit 45c1cde698
10 changed files with 126 additions and 25 deletions

View File

@ -18,12 +18,15 @@
#include "base/EventQueue.h" #include "base/EventQueue.h"
#include "mt/Mutex.h"
#include "mt/Lock.h"
#include "arch/Arch.h" #include "arch/Arch.h"
#include "base/Log.h"
#include "base/SimpleEventQueueBuffer.h" #include "base/SimpleEventQueueBuffer.h"
#include "base/Stopwatch.h" #include "base/Stopwatch.h"
#include "base/IEventJob.h" #include "base/IEventJob.h"
#include "base/EventTypes.h" #include "base/EventTypes.h"
#include "base/Log.h"
#include "base/XBase.h"
EVENT_TYPE_ACCESSOR(CClient) EVENT_TYPE_ACCESSOR(CClient)
EVENT_TYPE_ACCESSOR(IStream) EVENT_TYPE_ACCESSOR(IStream)
@ -78,7 +81,9 @@ CEventQueue::CEventQueue() :
m_typesForCServerApp(NULL), m_typesForCServerApp(NULL),
m_typesForIKeyState(NULL), m_typesForIKeyState(NULL),
m_typesForIPrimaryScreen(NULL), m_typesForIPrimaryScreen(NULL),
m_typesForIScreen(NULL) m_typesForIScreen(NULL),
m_readyMutex(new CMutex),
m_readyCondVar(new CCondVar<bool>(m_readyMutex, false))
{ {
m_mutex = ARCH->newMutex(); m_mutex = ARCH->newMutex();
ARCH->setSignalHandler(CArch::kINTERRUPT, &interrupt, this); ARCH->setSignalHandler(CArch::kINTERRUPT, &interrupt, this);
@ -89,6 +94,9 @@ CEventQueue::CEventQueue() :
CEventQueue::~CEventQueue() CEventQueue::~CEventQueue()
{ {
delete m_buffer; delete m_buffer;
delete m_readyCondVar;
delete m_readyMutex;
ARCH->setSignalHandler(CArch::kINTERRUPT, NULL, NULL); ARCH->setSignalHandler(CArch::kINTERRUPT, NULL, NULL);
ARCH->setSignalHandler(CArch::kTERMINATE, NULL, NULL); ARCH->setSignalHandler(CArch::kTERMINATE, NULL, NULL);
ARCH->closeMutex(m_mutex); ARCH->closeMutex(m_mutex);
@ -98,6 +106,16 @@ void
CEventQueue::loop() CEventQueue::loop()
{ {
m_buffer->init(); m_buffer->init();
*m_readyCondVar = true;
m_readyCondVar->broadcast();
LOG((CLOG_DEBUG "event queue is ready"));
while (!m_pending.empty()) {
LOG((CLOG_DEBUG "add pending events to buffer"));
CEvent& event = m_pending.front();
addEventToBuffer(event);
m_pending.pop();
}
CEvent event; CEvent event;
getEvent(event); getEvent(event);
@ -268,18 +286,27 @@ CEventQueue::addEvent(const CEvent& event)
dispatchEvent(event); dispatchEvent(event);
CEvent::deleteData(event); CEvent::deleteData(event);
} }
else if (!(*m_readyCondVar)) {
m_pending.push(event);
}
else { else {
CArchMutexLock lock(m_mutex); addEventToBuffer(event);
}
// store the event's data locally }
UInt32 eventID = saveEvent(event);
void
// add it CEventQueue::addEventToBuffer(const CEvent& event)
if (!m_buffer->addEvent(eventID)) { {
// failed to send event CArchMutexLock lock(m_mutex);
removeEvent(eventID);
CEvent::deleteData(event); // store the event's data locally
} UInt32 eventID = saveEvent(event);
// add it
if (!m_buffer->addEvent(eventID)) {
// failed to send event
removeEvent(eventID);
CEvent::deleteData(event);
} }
} }
@ -526,6 +553,21 @@ CEventQueue::getSystemTarget()
return &m_systemTarget; return &m_systemTarget;
} }
void
CEventQueue::waitForReady() const
{
double timeout = ARCH->time() + 5;
m_readyCondVar->lock();
while (!m_readyCondVar->wait()) {
if(ARCH->time() > timeout) {
throw std::runtime_error("event queue is not ready within 5 sec");
}
}
m_readyCondVar->unlock();
}
// //
// CEventQueue::CTimer // CEventQueue::CTimer
// //

View File

@ -18,14 +18,19 @@
#pragma once #pragma once
#include "mt/CondVar.h"
#include "arch/IArchMultithread.h"
#include "base/IEventQueue.h" #include "base/IEventQueue.h"
#include "base/Event.h" #include "base/Event.h"
#include "base/PriorityQueue.h" #include "base/PriorityQueue.h"
#include "base/Stopwatch.h" #include "base/Stopwatch.h"
#include "arch/IArchMultithread.h"
#include "common/stdmap.h" #include "common/stdmap.h"
#include "common/stdset.h" #include "common/stdset.h"
#include <queue>
class CMutex;
//! Event queue //! Event queue
/*! /*!
An event queue that implements the platform independent parts and An event queue that implements the platform independent parts and
@ -59,13 +64,15 @@ public:
virtual CEvent::Type virtual CEvent::Type
getRegisteredType(const CString& name) const; getRegisteredType(const CString& name) const;
void* getSystemTarget(); void* getSystemTarget();
virtual void waitForReady() const;
private: private:
UInt32 saveEvent(const CEvent& event); UInt32 saveEvent(const CEvent& event);
CEvent removeEvent(UInt32 eventID); CEvent removeEvent(UInt32 eventID);
bool hasTimerExpired(CEvent& event); bool hasTimerExpired(CEvent& event);
double getNextTimerTimeout() const; double getNextTimerTimeout() const;
void addEventToBuffer(const CEvent& event);
private: private:
class CTimer { class CTimer {
public: public:
@ -170,6 +177,9 @@ private:
IKeyStateEvents* m_typesForIKeyState; IKeyStateEvents* m_typesForIKeyState;
IPrimaryScreenEvents* m_typesForIPrimaryScreen; IPrimaryScreenEvents* m_typesForIPrimaryScreen;
IScreenEvents* m_typesForIScreen; IScreenEvents* m_typesForIScreen;
CMutex* m_readyMutex;
CCondVar<bool>* m_readyCondVar;
std::queue<const CEvent> m_pending;
}; };
#define EVENT_TYPE_ACCESSOR(type_) \ #define EVENT_TYPE_ACCESSOR(type_) \

View File

@ -176,6 +176,13 @@ public:
registerTypeOnce(CEvent::Type& type, registerTypeOnce(CEvent::Type& type,
const char* name) = 0; const char* name) = 0;
//! Wait for event queue to become ready
/*!
Blocks on the current thread until the event queue is ready for events to
be added.
*/
virtual void waitForReady() const = 0;
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{

View File

@ -28,9 +28,6 @@ COSXDragView* g_dragView = NULL;
void void
runCocoaApp() runCocoaApp()
{ {
// HACK: sleep, carbon loop should start first.
usleep(1000000);
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
[NSApplication sharedApplication]; [NSApplication sharedApplication];

View File

@ -18,6 +18,7 @@
#include "platform/OSXScreen.h" #include "platform/OSXScreen.h"
#include "base/EventQueue.h"
#include "client/Client.h" #include "client/Client.h"
#include "platform/OSXClipboard.h" #include "platform/OSXClipboard.h"
#include "platform/OSXEventQueueBuffer.h" #include "platform/OSXEventQueueBuffer.h"
@ -163,6 +164,10 @@ COSXScreen::COSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCur
// create thread for monitoring system power state. // create thread for monitoring system power state.
*m_pmThreadReady = false; *m_pmThreadReady = false;
#if defined(MAC_OS_X_VERSION_10_7)
m_carbonLoopMutex = new CMutex();
m_carbonLoopReady = new CCondVar<bool>(m_carbonLoopMutex, false);
#endif
LOG((CLOG_DEBUG "starting watchSystemPowerThread")); LOG((CLOG_DEBUG "starting watchSystemPowerThread"));
m_pmWatchThread = new CThread(new TMethodJob<COSXScreen> m_pmWatchThread = new CThread(new TMethodJob<COSXScreen>
(this, &COSXScreen::watchSystemPowerThread)); (this, &COSXScreen::watchSystemPowerThread));
@ -255,6 +260,11 @@ COSXScreen::~COSXScreen()
delete m_keyState; delete m_keyState;
delete m_screensaver; delete m_screensaver;
#if defined(MAC_OS_X_VERSION_10_7)
delete m_carbonLoopMutex;
delete m_carbonLoopReady;
#endif
} }
void* void*
@ -1694,10 +1704,16 @@ COSXScreen::watchSystemPowerThread(void*)
} }
LOG((CLOG_DEBUG "started watchSystemPowerThread")); LOG((CLOG_DEBUG "started watchSystemPowerThread"));
m_events->waitForReady();
// HACK: sleep, this seem to stop synergy from freezing. #if defined(MAC_OS_X_VERSION_10_7)
ARCH->sleep(1); if (*m_carbonLoopReady == false) {
*m_carbonLoopReady = true;
m_carbonLoopReady->broadcast();
}
#endif
// start the run loop // start the run loop
LOG((CLOG_DEBUG "starting carbon loop")); LOG((CLOG_DEBUG "starting carbon loop"));
CFRunLoopRun(); CFRunLoopRun();
@ -2100,6 +2116,21 @@ COSXScreen::getDraggingFilename()
return m_draggingFilename; return m_draggingFilename;
} }
void
COSXScreen::waitForCarbonLoop() const
{
double timeout = ARCH->time() + 5;
m_carbonLoopReady->lock();
while (!m_carbonLoopReady->wait()) {
if(ARCH->time() > timeout) {
throw std::runtime_error("carbon loop is not ready within 5 sec");
}
}
m_carbonLoopReady->unlock();
}
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
void void

View File

@ -47,6 +47,7 @@ class CThread;
class COSXKeyState; class COSXKeyState;
class COSXScreenSaver; class COSXScreenSaver;
class IEventQueue; class IEventQueue;
class CMutex;
//! Implementation of IPlatformScreen for OS X //! Implementation of IPlatformScreen for OS X
class COSXScreen : public CPlatformScreen { class COSXScreen : public CPlatformScreen {
@ -98,6 +99,7 @@ public:
virtual CString& getDraggingFilename(); virtual CString& getDraggingFilename();
const CString& getDropTarget() const { return m_dropTarget; } const CString& getDropTarget() const { return m_dropTarget; }
void waitForCarbonLoop() const;
protected: protected:
// IPlatformScreen overrides // IPlatformScreen overrides
@ -344,4 +346,9 @@ private:
CThread* m_getDropTargetThread; CThread* m_getDropTargetThread;
CString m_dropTarget; CString m_dropTarget;
#if defined(MAC_OS_X_VERSION_10_7)
CMutex* m_carbonLoopMutex;
CCondVar<bool>* m_carbonLoopReady;
#endif
}; };

View File

@ -548,8 +548,10 @@ CClientApp::mainLoop()
this, &CClientApp::runEventsLoop, this, &CClientApp::runEventsLoop,
NULL)); NULL));
// HACK: sleep, allow queue to start. // wait until carbon loop is ready
ARCH->sleep(1); COSXScreen* screen = dynamic_cast<COSXScreen*>(
s_clientScreen->getPlatformScreen());
screen->waitForCarbonLoop();
runCocoaApp(); runCocoaApp();
#else #else

View File

@ -296,6 +296,8 @@ public:
virtual void getShape(SInt32& x, SInt32& y, virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const; SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const; virtual void getCursorPos(SInt32& x, SInt32& y) const;
IPlatformScreen* getPlatformScreen() { return m_screen; }
protected: protected:
void enablePrimary(); void enablePrimary();

View File

@ -798,8 +798,10 @@ CServerApp::mainLoop()
this, &CServerApp::runEventsLoop, this, &CServerApp::runEventsLoop,
NULL)); NULL));
// HACK: sleep, allow queue to start. // wait until carbon loop is ready
ARCH->sleep(1); COSXScreen* screen = dynamic_cast<COSXScreen*>(
s_serverScreen->getPlatformScreen());
screen->waitForCarbonLoop();
runCocoaApp(); runCocoaApp();
#else #else

View File

@ -61,4 +61,5 @@ public:
MOCK_METHOD0(forIKeyState, IKeyStateEvents&()); MOCK_METHOD0(forIKeyState, IKeyStateEvents&());
MOCK_METHOD0(forIPrimaryScreen, IPrimaryScreenEvents&()); MOCK_METHOD0(forIPrimaryScreen, IPrimaryScreenEvents&());
MOCK_METHOD0(forIScreen, IScreenEvents&()); MOCK_METHOD0(forIScreen, IScreenEvents&());
MOCK_CONST_METHOD0(waitForReady, void());
}; };