Fixed bug that could allow multiple threads to simultaneously access
the X11 display connection. The only problematic method was CXWindowsEventQueueBuffer::addEvent given that the other event queue methods are only called from the main thread.
This commit is contained in:
parent
7e36454b01
commit
88c6769ebe
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
|
||||
#include "CXWindowsEventQueueBuffer.h"
|
||||
#include "CLock.h"
|
||||
#include "CThread.h"
|
||||
#include "CEvent.h"
|
||||
#include "IEventQueue.h"
|
||||
|
@ -47,7 +48,8 @@ class CEventQueueTimer { };
|
|||
CXWindowsEventQueueBuffer::CXWindowsEventQueueBuffer(
|
||||
Display* display, Window window) :
|
||||
m_display(display),
|
||||
m_window(window)
|
||||
m_window(window),
|
||||
m_waiting(false)
|
||||
{
|
||||
assert(m_display != NULL);
|
||||
assert(m_window != None);
|
||||
|
@ -63,6 +65,17 @@ CXWindowsEventQueueBuffer::~CXWindowsEventQueueBuffer()
|
|||
void
|
||||
CXWindowsEventQueueBuffer::waitForEvent(double dtimeout)
|
||||
{
|
||||
CThread::testCancel();
|
||||
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
// we're now waiting for events
|
||||
m_waiting = true;
|
||||
|
||||
// push out pending events
|
||||
flush();
|
||||
}
|
||||
|
||||
// use poll() to wait for a message from the X server or for timeout.
|
||||
// this is a good deal more efficient than polling and sleeping.
|
||||
#if HAVE_POLL
|
||||
|
@ -93,7 +106,6 @@ CXWindowsEventQueueBuffer::waitForEvent(double dtimeout)
|
|||
// wait for message from X server or for timeout. also check
|
||||
// if the thread has been cancelled. poll() should return -1
|
||||
// with EINTR when the thread is cancelled.
|
||||
CThread::testCancel();
|
||||
#if HAVE_POLL
|
||||
poll(pfds, 1, timeout);
|
||||
#else
|
||||
|
@ -103,12 +115,24 @@ CXWindowsEventQueueBuffer::waitForEvent(double dtimeout)
|
|||
SELECT_TYPE_ARG234 NULL,
|
||||
SELECT_TYPE_ARG5 timeoutPtr);
|
||||
#endif
|
||||
|
||||
{
|
||||
// we're no longer waiting for events
|
||||
CLock lock(&m_mutex);
|
||||
m_waiting = true;
|
||||
}
|
||||
|
||||
CThread::testCancel();
|
||||
}
|
||||
|
||||
IEventQueueBuffer::Type
|
||||
CXWindowsEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// push out pending events
|
||||
flush();
|
||||
|
||||
// get next event
|
||||
XNextEvent(m_display, &m_event);
|
||||
|
||||
|
@ -128,25 +152,33 @@ CXWindowsEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
|||
bool
|
||||
CXWindowsEventQueueBuffer::addEvent(UInt32 dataID)
|
||||
{
|
||||
// send ourself a message
|
||||
// prepare a message
|
||||
XEvent xevent;
|
||||
xevent.xclient.type = ClientMessage;
|
||||
xevent.xclient.window = m_window;
|
||||
xevent.xclient.message_type = m_userEvent;
|
||||
xevent.xclient.format = 32;
|
||||
xevent.xclient.data.l[0] = static_cast<long>(dataID);
|
||||
if (XSendEvent(m_display, m_window, False, 0, &xevent) == 0) {
|
||||
return false;
|
||||
|
||||
// save the message
|
||||
CLock lock(&m_mutex);
|
||||
m_postedEvents.push_back(xevent);
|
||||
|
||||
// if we're currently waiting for an event then send saved events to
|
||||
// the X server now. if we're not waiting then some other thread
|
||||
// might be using the display connection so we can't safely use it
|
||||
// too.
|
||||
if (m_waiting) {
|
||||
flush();
|
||||
}
|
||||
|
||||
// force waitForEvent() to return
|
||||
XFlush(m_display);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CXWindowsEventQueueBuffer::isEmpty() const
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
return (XPending(m_display) == 0);
|
||||
}
|
||||
|
||||
|
@ -161,3 +193,16 @@ CXWindowsEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
|
|||
{
|
||||
delete timer;
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsEventQueueBuffer::flush()
|
||||
{
|
||||
// note -- m_mutex must be locked on entry
|
||||
|
||||
// flush the posted event list to the X server
|
||||
for (size_t i = 0; i < m_postedEvents.size(); ++i) {
|
||||
XSendEvent(m_display, m_window, False, 0, &m_postedEvents[i]);
|
||||
}
|
||||
XFlush(m_display);
|
||||
m_postedEvents.clear();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#define CXWINDOWSEVENTQUEUEBUFFER_H
|
||||
|
||||
#include "IEventQueueBuffer.h"
|
||||
#include "CMutex.h"
|
||||
#include "stdvector.h"
|
||||
#if defined(X_DISPLAY_MISSING)
|
||||
# error X11 is required to build synergy
|
||||
#else
|
||||
|
@ -38,10 +40,18 @@ public:
|
|||
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||
|
||||
private:
|
||||
void flush();
|
||||
|
||||
private:
|
||||
typedef std::vector<XEvent> CEventList;
|
||||
|
||||
CMutex m_mutex;
|
||||
Display* m_display;
|
||||
Window m_window;
|
||||
Atom m_userEvent;
|
||||
XEvent m_event;
|
||||
CEventList m_postedEvents;
|
||||
bool m_waiting;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue