XQuartz: Use a mutex to ensure we only have one thread calling mieqEnqueue at a time.

(cherry picked from commit 7b087c965bce9f440ab5233d6383aa4a7de969b8)
This commit is contained in:
Jeremy Huddleston 2008-04-17 15:23:00 -07:00
parent 55f80d7545
commit 2a1ba20af9
4 changed files with 148 additions and 102 deletions

View File

@ -54,6 +54,9 @@ in this Software without prior written authorization from The Open Group.
#include <sys/types.h> #include <sys/types.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <unistd.h> #include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <IOKit/hidsystem/IOLLEvent.h> #include <IOKit/hidsystem/IOLLEvent.h>
/* Fake button press/release for scroll wheel move. */ /* Fake button press/release for scroll wheel move. */
@ -77,6 +80,25 @@ static int old_flags = 0; // last known modifier state
xEvent *darwinEvents = NULL; xEvent *darwinEvents = NULL;
pthread_mutex_t mieqEnqueue_mutex;
static inline void mieqEnqueue_lock(void) {
int err;
if((err = pthread_mutex_lock(&mieqEnqueue_mutex))) {
ErrorF("%s:%s:%d: Failed to lock mieqEnqueue_mutex: %d\n",
__FILE__, __FUNCTION__, __LINE__, err);
spewCallStack();
}
}
static inline void mieqEnqueue_unlock(void) {
int err;
if((err = pthread_mutex_unlock(&mieqEnqueue_mutex))) {
ErrorF("%s:%s:%d: Failed to unlock mieqEnqueue_mutex: %d\n",
__FILE__, __FUNCTION__, __LINE__, err);
spewCallStack();
}
}
/* /*
* DarwinPressModifierMask * DarwinPressModifierMask
* Press or release the given modifier key, specified by its mask. * Press or release the given modifier key, specified by its mask.
@ -197,107 +219,119 @@ static void DarwinSimulateMouseClick(
mieqSetHandler. */ mieqSetHandler. */
void DarwinEventHandler(int screenNum, xEventPtr xe, DeviceIntPtr dev, int nevents) { void DarwinEventHandler(int screenNum, xEventPtr xe, DeviceIntPtr dev, int nevents) {
int i; int i;
DEBUG_LOG("DarwinEventHandler(%d, %p, %p, %d)\n", screenNum, xe, dev, nevents); TA_SERVER();
for (i=0; i<nevents; i++) {
switch(xe[i].u.u.type) {
case kXquartzControllerNotify:
DEBUG_LOG("kXquartzControllerNotify\n");
AppleWMSendEvent(AppleWMControllerNotify,
AppleWMControllerNotifyMask,
xe[i].u.clientMessage.u.l.longs0,
xe[i].u.clientMessage.u.l.longs1);
break;
case kXquartzPasteboardNotify: DEBUG_LOG("DarwinEventHandler(%d, %p, %p, %d)\n", screenNum, xe, dev, nevents);
DEBUG_LOG("kXquartzPasteboardNotify\n"); for (i=0; i<nevents; i++) {
AppleWMSendEvent(AppleWMPasteboardNotify, switch(xe[i].u.u.type) {
AppleWMPasteboardNotifyMask, case kXquartzControllerNotify:
xe[i].u.clientMessage.u.l.longs0, DEBUG_LOG("kXquartzControllerNotify\n");
xe[i].u.clientMessage.u.l.longs1); AppleWMSendEvent(AppleWMControllerNotify,
break; AppleWMControllerNotifyMask,
xe[i].u.clientMessage.u.l.longs0,
xe[i].u.clientMessage.u.l.longs1);
break;
case kXquartzActivate: case kXquartzPasteboardNotify:
DEBUG_LOG("kXquartzActivate\n"); DEBUG_LOG("kXquartzPasteboardNotify\n");
QuartzShow(xe[i].u.keyButtonPointer.rootX, AppleWMSendEvent(AppleWMPasteboardNotify,
xe[i].u.keyButtonPointer.rootY); AppleWMPasteboardNotifyMask,
AppleWMSendEvent(AppleWMActivationNotify, xe[i].u.clientMessage.u.l.longs0,
AppleWMActivationNotifyMask, xe[i].u.clientMessage.u.l.longs1);
AppleWMIsActive, 0); break;
break;
case kXquartzDeactivate: case kXquartzActivate:
DEBUG_LOG("kXquartzDeactivate\n"); DEBUG_LOG("kXquartzActivate\n");
DarwinReleaseModifiers(); QuartzShow(xe[i].u.keyButtonPointer.rootX,
AppleWMSendEvent(AppleWMActivationNotify, xe[i].u.keyButtonPointer.rootY);
AppleWMActivationNotifyMask, AppleWMSendEvent(AppleWMActivationNotify,
AppleWMIsInactive, 0); AppleWMActivationNotifyMask,
QuartzHide(); AppleWMIsActive, 0);
break; break;
case kXquartzWindowState: case kXquartzDeactivate:
DEBUG_LOG("kXquartzWindowState\n"); DEBUG_LOG("kXquartzDeactivate\n");
RootlessNativeWindowStateChanged(xprGetXWindow(xe[i].u.clientMessage.u.l.longs0), DarwinReleaseModifiers();
xe[i].u.clientMessage.u.l.longs1); AppleWMSendEvent(AppleWMActivationNotify,
break; AppleWMActivationNotifyMask,
AppleWMIsInactive, 0);
QuartzHide();
break;
case kXquartzWindowMoved: case kXquartzWindowState:
DEBUG_LOG("kXquartzWindowMoved\n"); DEBUG_LOG("kXquartzWindowState\n");
RootlessNativeWindowMoved ((WindowPtr)xe[i].u.clientMessage.u.l.longs0); RootlessNativeWindowStateChanged(xprGetXWindow(xe[i].u.clientMessage.u.l.longs0),
break; xe[i].u.clientMessage.u.l.longs1);
break;
case kXquartzToggleFullscreen: case kXquartzWindowMoved:
DEBUG_LOG("kXquartzToggleFullscreen\n"); DEBUG_LOG("kXquartzWindowMoved\n");
RootlessNativeWindowMoved ((WindowPtr)xe[i].u.clientMessage.u.l.longs0);
break;
case kXquartzToggleFullscreen:
DEBUG_LOG("kXquartzToggleFullscreen\n");
#ifdef DARWIN_DDX_MISSING #ifdef DARWIN_DDX_MISSING
if (quartzEnableRootless) QuartzSetFullscreen(!quartzHasRoot); if (quartzEnableRootless)
else if (quartzHasRoot) QuartzHide(); QuartzSetFullscreen(!quartzHasRoot);
else QuartzShow(); else if (quartzHasRoot)
QuartzHide();
else
QuartzShow();
#else #else
// ErrorF("kXquartzToggleFullscreen not implemented\n"); // ErrorF("kXquartzToggleFullscreen not implemented\n");
#endif #endif
break; break;
case kXquartzSetRootless: case kXquartzSetRootless:
DEBUG_LOG("kXquartzSetRootless\n"); DEBUG_LOG("kXquartzSetRootless\n");
#ifdef DARWIN_DDX_MISSING #ifdef DARWIN_DDX_MISSING
QuartzSetRootless(xe[i].u.clientMessage.u.l.longs0); QuartzSetRootless(xe[i].u.clientMessage.u.l.longs0);
if (!quartzEnableRootless && !quartzHasRoot) QuartzHide(); if (!quartzEnableRootless && !quartzHasRoot)
QuartzHide();
#else #else
// ErrorF("kXquartzSetRootless not implemented\n"); // ErrorF("kXquartzSetRootless not implemented\n");
#endif #endif
break; break;
case kXquartzSetRootClip: case kXquartzSetRootClip:
QuartzSetRootClip((BOOL)xe[i].u.clientMessage.u.l.longs0); QuartzSetRootClip((BOOL)xe[i].u.clientMessage.u.l.longs0);
break; break;
case kXquartzQuit: case kXquartzQuit:
GiveUp(0); GiveUp(0);
break; break;
case kXquartzBringAllToFront: case kXquartzBringAllToFront:
DEBUG_LOG("kXquartzBringAllToFront\n"); DEBUG_LOG("kXquartzBringAllToFront\n");
RootlessOrderAllWindows(); RootlessOrderAllWindows();
break; break;
case kXquartzSpaceChanged: case kXquartzSpaceChanged:
DEBUG_LOG("kXquartzSpaceChanged\n"); DEBUG_LOG("kXquartzSpaceChanged\n");
QuartzSpaceChanged(xe[i].u.clientMessage.u.l.longs0); QuartzSpaceChanged(xe[i].u.clientMessage.u.l.longs0);
break;
break; default:
default: ErrorF("Unknown application defined event type %d.\n", xe[i].u.u.type);
ErrorF("Unknown application defined event type %d.\n", xe[i].u.u.type);
} }
} }
} }
Bool DarwinEQInit(DevicePtr pKbd, DevicePtr pPtr) { Bool DarwinEQInit(DevicePtr pKbd, DevicePtr pPtr) {
int err;
if (!darwinEvents) if (!darwinEvents)
darwinEvents = (xEvent *)xcalloc(sizeof(xEvent), GetMaximumEventsNum()); darwinEvents = (xEvent *)xcalloc(sizeof(xEvent), GetMaximumEventsNum());
if (!darwinEvents) if (!darwinEvents)
FatalError("Couldn't allocate event buffer\n"); FatalError("Couldn't allocate event buffer\n");
if((err = pthread_mutex_init(&mieqEnqueue_mutex, NULL))) {
FatalError("Couldn't allocate miEnqueue mutex: %d.\n", err);
}
mieqInit(); mieqInit();
mieqSetHandler(kXquartzReloadKeymap, DarwinKeyboardReloadHandler); mieqSetHandler(kXquartzReloadKeymap, DarwinKeyboardReloadHandler);
mieqSetHandler(kXquartzActivate, DarwinEventHandler); mieqSetHandler(kXquartzActivate, DarwinEventHandler);
@ -305,7 +339,7 @@ Bool DarwinEQInit(DevicePtr pKbd, DevicePtr pPtr) {
mieqSetHandler(kXquartzSetRootClip, DarwinEventHandler); mieqSetHandler(kXquartzSetRootClip, DarwinEventHandler);
mieqSetHandler(kXquartzQuit, DarwinEventHandler); mieqSetHandler(kXquartzQuit, DarwinEventHandler);
mieqSetHandler(kXquartzReadPasteboard, QuartzReadPasteboard); mieqSetHandler(kXquartzReadPasteboard, QuartzReadPasteboard);
mieqSetHandler(kXquartzWritePasteboard, QuartzWritePasteboard); mieqSetHandler(kXquartzWritePasteboard, QuartzWritePasteboard);
mieqSetHandler(kXquartzToggleFullscreen, DarwinEventHandler); mieqSetHandler(kXquartzToggleFullscreen, DarwinEventHandler);
mieqSetHandler(kXquartzSetRootless, DarwinEventHandler); mieqSetHandler(kXquartzSetRootless, DarwinEventHandler);
mieqSetHandler(kXquartzSpaceChanged, DarwinEventHandler); mieqSetHandler(kXquartzSpaceChanged, DarwinEventHandler);
@ -326,6 +360,8 @@ void ProcessInputEvents(void) {
xEvent xe; xEvent xe;
int x = sizeof(xe); int x = sizeof(xe);
TA_SERVER();
mieqProcessInputEvents(); mieqProcessInputEvents();
// Empty the signaling pipe // Empty the signaling pipe
@ -336,7 +372,7 @@ void ProcessInputEvents(void) {
/* Sends a null byte down darwinEventWriteFD, which will cause the /* Sends a null byte down darwinEventWriteFD, which will cause the
Dispatch() event loop to check out event queue */ Dispatch() event loop to check out event queue */
void DarwinPokeEQ(void) { static void DarwinPokeEQ(void) {
char nullbyte=0; char nullbyte=0;
input_check_flag++; input_check_flag++;
// <daniels> oh, i ... er ... christ. // <daniels> oh, i ... er ... christ.
@ -398,15 +434,18 @@ void DarwinSendPointerEvents(int ev_type, int ev_button, int pointer_x, int poin
return; return;
} }
num_events = GetPointerEvents(darwinEvents, darwinPointer, ev_type, ev_button, mieqEnqueue_lock(); {
POINTER_ABSOLUTE, 0, 5, valuators); num_events = GetPointerEvents(darwinEvents, darwinPointer, ev_type, ev_button,
POINTER_ABSOLUTE, 0, 5, valuators);
for(i=0; i<num_events; i++) mieqEnqueue (darwinPointer,&darwinEvents[i]);
DarwinPokeEQ();
for(i=0; i<num_events; i++) mieqEnqueue (darwinPointer,&darwinEvents[i]); } mieqEnqueue_unlock();
DarwinPokeEQ();
} }
void DarwinSendKeyboardEvents(int ev_type, int keycode) { void DarwinSendKeyboardEvents(int ev_type, int keycode) {
int i, num_events; int i, num_events;
if(!darwinEvents) { if(!darwinEvents) {
ErrorF("DarwinSendKeyboardEvents called before darwinEvents was initialized\n"); ErrorF("DarwinSendKeyboardEvents called before darwinEvents was initialized\n");
return; return;
@ -425,9 +464,11 @@ void DarwinSendKeyboardEvents(int ev_type, int keycode) {
} }
} }
num_events = GetKeyboardEvents(darwinEvents, darwinKeyboard, ev_type, keycode + MIN_KEYCODE); mieqEnqueue_lock(); {
for(i=0; i<num_events; i++) mieqEnqueue(darwinKeyboard,&darwinEvents[i]); num_events = GetKeyboardEvents(darwinEvents, darwinKeyboard, ev_type, keycode + MIN_KEYCODE);
DarwinPokeEQ(); for(i=0; i<num_events; i++) mieqEnqueue(darwinKeyboard,&darwinEvents[i]);
DarwinPokeEQ();
} mieqEnqueue_unlock();
} }
void DarwinSendProximityEvents(int ev_type, int pointer_x, int pointer_y, void DarwinSendProximityEvents(int ev_type, int pointer_x, int pointer_y,
@ -443,11 +484,12 @@ void DarwinSendProximityEvents(int ev_type, int pointer_x, int pointer_y,
return; return;
} }
num_events = GetProximityEvents(darwinEvents, darwinPointer, ev_type, mieqEnqueue_lock(); {
0, 5, valuators); num_events = GetProximityEvents(darwinEvents, darwinPointer, ev_type,
0, 5, valuators);
for(i=0; i<num_events; i++) mieqEnqueue (darwinPointer,&darwinEvents[i]); for(i=0; i<num_events; i++) mieqEnqueue (darwinPointer,&darwinEvents[i]);
DarwinPokeEQ(); DarwinPokeEQ();
} mieqEnqueue_unlock();
} }
@ -512,5 +554,7 @@ void DarwinSendDDXEvent(int type, int argc, ...) {
va_end (args); va_end (args);
} }
mieqEnqueue_lock();
mieqEnqueue(darwinPointer, &xe); mieqEnqueue(darwinPointer, &xe);
mieqEnqueue_unlock();
} }

View File

@ -32,7 +32,6 @@ Bool DarwinEQInit(DevicePtr pKbd, DevicePtr pPtr);
void DarwinEQEnqueue(const xEventPtr e); void DarwinEQEnqueue(const xEventPtr e);
void DarwinEQPointerPost(DeviceIntPtr pDev, xEventPtr e); void DarwinEQPointerPost(DeviceIntPtr pDev, xEventPtr e);
void DarwinEQSwitchScreen(ScreenPtr pScreen, Bool fromDIX); void DarwinEQSwitchScreen(ScreenPtr pScreen, Bool fromDIX);
void DarwinPokeEQ(void);
void DarwinSendPointerEvents(int ev_type, int ev_button, int pointer_x, int pointer_y, void DarwinSendPointerEvents(int ev_type, int ev_button, int pointer_x, int pointer_y,
float pressure, float tilt_x, float tilt_y); float pressure, float tilt_x, float tilt_y);
void DarwinSendProximityEvents(int ev_type, int pointer_x, int pointer_y, void DarwinSendProximityEvents(int ev_type, int pointer_x, int pointer_y,

View File

@ -36,7 +36,7 @@
pthread_t SERVER_THREAD; pthread_t SERVER_THREAD;
pthread_t APPKIT_THREAD; pthread_t APPKIT_THREAD;
static inline void spewCallStack(void) { void spewCallStack(void) {
void* callstack[128]; void* callstack[128];
int i, frames = backtrace(callstack, 128); int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames); char** strs = backtrace_symbols(callstack, frames);

View File

@ -36,6 +36,9 @@ extern pthread_t APPKIT_THREAD;
#define threadSafetyID(tid) (pthread_equal((tid), SERVER_THREAD) ? "X Server Thread" : "Appkit Thread") #define threadSafetyID(tid) (pthread_equal((tid), SERVER_THREAD) ? "X Server Thread" : "Appkit Thread")
/* Dump the call stack */
void spewCallStack(void);
/* Print message to ErrorF if we're in the wrong thread */ /* Print message to ErrorF if we're in the wrong thread */
void _threadAssert(pthread_t tid, const char *file, const char *fun, int line); void _threadAssert(pthread_t tid, const char *file, const char *fun, int line);