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 "CXWindowsEventQueueBuffer.h"
|
||||||
|
#include "CLock.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "CEvent.h"
|
#include "CEvent.h"
|
||||||
#include "IEventQueue.h"
|
#include "IEventQueue.h"
|
||||||
|
@ -47,7 +48,8 @@ class CEventQueueTimer { };
|
||||||
CXWindowsEventQueueBuffer::CXWindowsEventQueueBuffer(
|
CXWindowsEventQueueBuffer::CXWindowsEventQueueBuffer(
|
||||||
Display* display, Window window) :
|
Display* display, Window window) :
|
||||||
m_display(display),
|
m_display(display),
|
||||||
m_window(window)
|
m_window(window),
|
||||||
|
m_waiting(false)
|
||||||
{
|
{
|
||||||
assert(m_display != NULL);
|
assert(m_display != NULL);
|
||||||
assert(m_window != None);
|
assert(m_window != None);
|
||||||
|
@ -63,6 +65,17 @@ CXWindowsEventQueueBuffer::~CXWindowsEventQueueBuffer()
|
||||||
void
|
void
|
||||||
CXWindowsEventQueueBuffer::waitForEvent(double dtimeout)
|
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.
|
// 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.
|
// this is a good deal more efficient than polling and sleeping.
|
||||||
#if HAVE_POLL
|
#if HAVE_POLL
|
||||||
|
@ -93,7 +106,6 @@ CXWindowsEventQueueBuffer::waitForEvent(double dtimeout)
|
||||||
// wait for message from X server or for timeout. also check
|
// wait for message from X server or for timeout. also check
|
||||||
// if the thread has been cancelled. poll() should return -1
|
// if the thread has been cancelled. poll() should return -1
|
||||||
// with EINTR when the thread is cancelled.
|
// with EINTR when the thread is cancelled.
|
||||||
CThread::testCancel();
|
|
||||||
#if HAVE_POLL
|
#if HAVE_POLL
|
||||||
poll(pfds, 1, timeout);
|
poll(pfds, 1, timeout);
|
||||||
#else
|
#else
|
||||||
|
@ -103,12 +115,24 @@ CXWindowsEventQueueBuffer::waitForEvent(double dtimeout)
|
||||||
SELECT_TYPE_ARG234 NULL,
|
SELECT_TYPE_ARG234 NULL,
|
||||||
SELECT_TYPE_ARG5 timeoutPtr);
|
SELECT_TYPE_ARG5 timeoutPtr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
// we're no longer waiting for events
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
m_waiting = true;
|
||||||
|
}
|
||||||
|
|
||||||
CThread::testCancel();
|
CThread::testCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
IEventQueueBuffer::Type
|
IEventQueueBuffer::Type
|
||||||
CXWindowsEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
CXWindowsEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
||||||
{
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
|
// push out pending events
|
||||||
|
flush();
|
||||||
|
|
||||||
// get next event
|
// get next event
|
||||||
XNextEvent(m_display, &m_event);
|
XNextEvent(m_display, &m_event);
|
||||||
|
|
||||||
|
@ -128,25 +152,33 @@ CXWindowsEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
||||||
bool
|
bool
|
||||||
CXWindowsEventQueueBuffer::addEvent(UInt32 dataID)
|
CXWindowsEventQueueBuffer::addEvent(UInt32 dataID)
|
||||||
{
|
{
|
||||||
// send ourself a message
|
// prepare a message
|
||||||
XEvent xevent;
|
XEvent xevent;
|
||||||
xevent.xclient.type = ClientMessage;
|
xevent.xclient.type = ClientMessage;
|
||||||
xevent.xclient.window = m_window;
|
xevent.xclient.window = m_window;
|
||||||
xevent.xclient.message_type = m_userEvent;
|
xevent.xclient.message_type = m_userEvent;
|
||||||
xevent.xclient.format = 32;
|
xevent.xclient.format = 32;
|
||||||
xevent.xclient.data.l[0] = static_cast<long>(dataID);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CXWindowsEventQueueBuffer::isEmpty() const
|
CXWindowsEventQueueBuffer::isEmpty() const
|
||||||
{
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
return (XPending(m_display) == 0);
|
return (XPending(m_display) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,3 +193,16 @@ CXWindowsEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
|
||||||
{
|
{
|
||||||
delete timer;
|
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
|
#define CXWINDOWSEVENTQUEUEBUFFER_H
|
||||||
|
|
||||||
#include "IEventQueueBuffer.h"
|
#include "IEventQueueBuffer.h"
|
||||||
|
#include "CMutex.h"
|
||||||
|
#include "stdvector.h"
|
||||||
#if defined(X_DISPLAY_MISSING)
|
#if defined(X_DISPLAY_MISSING)
|
||||||
# error X11 is required to build synergy
|
# error X11 is required to build synergy
|
||||||
#else
|
#else
|
||||||
|
@ -38,10 +40,18 @@ public:
|
||||||
virtual void deleteTimer(CEventQueueTimer*) const;
|
virtual void deleteTimer(CEventQueueTimer*) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::vector<XEvent> CEventList;
|
||||||
|
|
||||||
|
CMutex m_mutex;
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
Window m_window;
|
Window m_window;
|
||||||
Atom m_userEvent;
|
Atom m_userEvent;
|
||||||
XEvent m_event;
|
XEvent m_event;
|
||||||
|
CEventList m_postedEvents;
|
||||||
|
bool m_waiting;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue