mirror of
https://gitlab.freedesktop.org/xorg/lib/libx11.git
synced 2026-05-06 13:58:03 +02:00
Allow X*IfEvent() to reenter libX11
The documentation for this family of functions very clearly says not to call into xlib in your predicate function, but historically single threaded apps could get away with it just fine, and now that we've forced thread-safety on the world such apps will now deadlock instead. That's not an acceptable regression even if the app is technically broken. This has been reported with XFCE and FVWM, and Motif's cut-and-paste code has the same bug by inspection, so this does need to be addressed. This change nerfs LockDisplay/UnlockDisplay while inside the critical bit of an IfEvent function. This is still safe in the sense that the display remains locked and no other thread should be able to change it from under us, but the loop that scans the event queue might not be robust against it being modified as a side effect of protocol emitted by the predicate callback. But that's not new, non-XInitThreads'd xlib would have the same caveat. Closes: xorg/lib/libx11#157
This commit is contained in:
parent
0d1d65bdd9
commit
7977557541
6 changed files with 39 additions and 0 deletions
|
|
@ -207,6 +207,7 @@ struct _XDisplay
|
|||
|
||||
XIOErrorExitHandler exit_handler;
|
||||
void *exit_handler_data;
|
||||
Bool in_ifevent;
|
||||
};
|
||||
|
||||
#define XAllocIDs(dpy,ids,n) (*(dpy)->idlist_alloc)(dpy,ids,n)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ Bool XCheckIfEvent (
|
|||
int n; /* time through count */
|
||||
|
||||
LockDisplay(dpy);
|
||||
dpy->in_ifevent = True;
|
||||
prev = NULL;
|
||||
for (n = 3; --n >= 0;) {
|
||||
for (qelt = prev ? prev->next : dpy->head;
|
||||
|
|
@ -60,6 +61,7 @@ Bool XCheckIfEvent (
|
|||
*event = qelt->event;
|
||||
_XDeq(dpy, prev, qelt);
|
||||
_XStoreEventCookie(dpy, event);
|
||||
dpy->in_ifevent = False;
|
||||
UnlockDisplay(dpy);
|
||||
return True;
|
||||
}
|
||||
|
|
@ -78,6 +80,7 @@ Bool XCheckIfEvent (
|
|||
/* another thread has snatched this event */
|
||||
prev = NULL;
|
||||
}
|
||||
dpy->in_ifevent = False;
|
||||
UnlockDisplay(dpy);
|
||||
return False;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ XIfEvent (
|
|||
unsigned long qe_serial = 0;
|
||||
|
||||
LockDisplay(dpy);
|
||||
dpy->in_ifevent = True;
|
||||
prev = NULL;
|
||||
while (1) {
|
||||
for (qelt = prev ? prev->next : dpy->head;
|
||||
|
|
@ -59,6 +60,7 @@ XIfEvent (
|
|||
*event = qelt->event;
|
||||
_XDeq(dpy, prev, qelt);
|
||||
_XStoreEventCookie(dpy, event);
|
||||
dpy->in_ifevent = False;
|
||||
UnlockDisplay(dpy);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ XOpenDisplay (
|
|||
dpy->xcmisc_opcode = 0;
|
||||
dpy->xkb_info = NULL;
|
||||
dpy->exit_handler_data = NULL;
|
||||
dpy->in_ifevent = False;
|
||||
|
||||
/*
|
||||
* Setup other information in this display structure.
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ XPeekIfEvent (
|
|||
unsigned long qe_serial = 0;
|
||||
|
||||
LockDisplay(dpy);
|
||||
dpy->in_ifevent = True;
|
||||
prev = NULL;
|
||||
while (1) {
|
||||
for (qelt = prev ? prev->next : dpy->head;
|
||||
|
|
@ -63,6 +64,7 @@ XPeekIfEvent (
|
|||
_XStoreEventCookie(dpy, ©);
|
||||
*event = copy;
|
||||
}
|
||||
dpy->in_ifevent = False;
|
||||
UnlockDisplay(dpy);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -452,6 +452,32 @@ static void _XDisplayLockWait(
|
|||
}
|
||||
}
|
||||
|
||||
static void _XLockDisplay(
|
||||
Display *dpy
|
||||
XTHREADS_FILE_LINE_ARGS
|
||||
);
|
||||
|
||||
static void _XIfEventLockDisplay(
|
||||
Display *dpy
|
||||
XTHREADS_FILE_LINE_ARGS
|
||||
)
|
||||
{
|
||||
/* assert(dpy->in_ifevent); */
|
||||
}
|
||||
|
||||
static void _XIfEventUnlockDisplay(
|
||||
Display *dpy
|
||||
XTHREADS_FILE_LINE_ARGS
|
||||
)
|
||||
{
|
||||
if (dpy->in_ifevent)
|
||||
return;
|
||||
|
||||
dpy->lock_fns->lock_display = _XLockDisplay;
|
||||
dpy->lock_fns->unlock_display = _XUnlockDisplay;
|
||||
UnlockDisplay(dpy);
|
||||
}
|
||||
|
||||
static void _XLockDisplay(
|
||||
Display *dpy
|
||||
XTHREADS_FILE_LINE_ARGS
|
||||
|
|
@ -478,6 +504,10 @@ static void _XLockDisplay(
|
|||
#endif
|
||||
_XIDHandler(dpy);
|
||||
_XSeqSyncFunction(dpy);
|
||||
if (dpy->in_ifevent) {
|
||||
dpy->lock_fns->lock_display = _XIfEventLockDisplay;
|
||||
dpy->lock_fns->unlock_display = _XIfEventUnlockDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue