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 "mt/Mutex.h"
#include "mt/Lock.h"
#include "arch/Arch.h"
#include "base/Log.h"
#include "base/SimpleEventQueueBuffer.h"
#include "base/Stopwatch.h"
#include "base/IEventJob.h"
#include "base/EventTypes.h"
#include "base/Log.h"
#include "base/XBase.h"
EVENT_TYPE_ACCESSOR(CClient)
EVENT_TYPE_ACCESSOR(IStream)
@ -78,7 +81,9 @@ CEventQueue::CEventQueue() :
m_typesForCServerApp(NULL),
m_typesForIKeyState(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();
ARCH->setSignalHandler(CArch::kINTERRUPT, &interrupt, this);
@ -89,6 +94,9 @@ CEventQueue::CEventQueue() :
CEventQueue::~CEventQueue()
{
delete m_buffer;
delete m_readyCondVar;
delete m_readyMutex;
ARCH->setSignalHandler(CArch::kINTERRUPT, NULL, NULL);
ARCH->setSignalHandler(CArch::kTERMINATE, NULL, NULL);
ARCH->closeMutex(m_mutex);
@ -98,6 +106,16 @@ void
CEventQueue::loop()
{
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;
getEvent(event);
@ -268,18 +286,27 @@ CEventQueue::addEvent(const CEvent& event)
dispatchEvent(event);
CEvent::deleteData(event);
}
else if (!(*m_readyCondVar)) {
m_pending.push(event);
}
else {
CArchMutexLock lock(m_mutex);
addEventToBuffer(event);
}
}
// store the event's data locally
UInt32 eventID = saveEvent(event);
void
CEventQueue::addEventToBuffer(const CEvent& event)
{
CArchMutexLock lock(m_mutex);
// add it
if (!m_buffer->addEvent(eventID)) {
// failed to send event
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;
}
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
//

View File

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

View File

@ -176,6 +176,13 @@ public:
registerTypeOnce(CEvent::Type& type,
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
//@{

View File

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

View File

@ -18,6 +18,7 @@
#include "platform/OSXScreen.h"
#include "base/EventQueue.h"
#include "client/Client.h"
#include "platform/OSXClipboard.h"
#include "platform/OSXEventQueueBuffer.h"
@ -163,6 +164,10 @@ COSXScreen::COSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCur
// create thread for monitoring system power state.
*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"));
m_pmWatchThread = new CThread(new TMethodJob<COSXScreen>
(this, &COSXScreen::watchSystemPowerThread));
@ -255,6 +260,11 @@ COSXScreen::~COSXScreen()
delete m_keyState;
delete m_screensaver;
#if defined(MAC_OS_X_VERSION_10_7)
delete m_carbonLoopMutex;
delete m_carbonLoopReady;
#endif
}
void*
@ -1695,8 +1705,14 @@ COSXScreen::watchSystemPowerThread(void*)
LOG((CLOG_DEBUG "started watchSystemPowerThread"));
// HACK: sleep, this seem to stop synergy from freezing.
ARCH->sleep(1);
m_events->waitForReady();
#if defined(MAC_OS_X_VERSION_10_7)
if (*m_carbonLoopReady == false) {
*m_carbonLoopReady = true;
m_carbonLoopReady->broadcast();
}
#endif
// start the run loop
LOG((CLOG_DEBUG "starting carbon loop"));
@ -2100,6 +2116,21 @@ COSXScreen::getDraggingFilename()
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"
void

View File

@ -47,6 +47,7 @@ class CThread;
class COSXKeyState;
class COSXScreenSaver;
class IEventQueue;
class CMutex;
//! Implementation of IPlatformScreen for OS X
class COSXScreen : public CPlatformScreen {
@ -98,6 +99,7 @@ public:
virtual CString& getDraggingFilename();
const CString& getDropTarget() const { return m_dropTarget; }
void waitForCarbonLoop() const;
protected:
// IPlatformScreen overrides
@ -344,4 +346,9 @@ private:
CThread* m_getDropTargetThread;
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,
NULL));
// HACK: sleep, allow queue to start.
ARCH->sleep(1);
// wait until carbon loop is ready
COSXScreen* screen = dynamic_cast<COSXScreen*>(
s_clientScreen->getPlatformScreen());
screen->waitForCarbonLoop();
runCocoaApp();
#else

View File

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

View File

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

View File

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