X11: Fix joystick events causing busy waiting

On Linux, the inotify descriptor was included in the set used for
select, but could not break the outer loop, leading to busy waiting
until timeout or the correct X11 event arrived.

This commit adds a new function for waiting just on X11 events.

Fixes #1872
This commit is contained in:
Camilla Löwy 2022-02-18 15:19:16 +01:00 committed by Camilla Löwy
parent 92b5c67b50
commit 1e987cb92e
2 changed files with 37 additions and 23 deletions

View File

@ -270,6 +270,7 @@ information on what to include when reporting a bug.
- [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences - [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences
- [X11] Bugfix: Waiting for events would fail if file descriptor was too large - [X11] Bugfix: Waiting for events would fail if file descriptor was too large
(#2024) (#2024)
- [X11] Bugfix: Joystick events could lead to busy-waiting (#1872)
- [Wayland] Added dynamic loading of all Wayland libraries - [Wayland] Added dynamic loading of all Wayland libraries
- [Wayland] Added support for key names via xkbcommon - [Wayland] Added support for key names via xkbcommon
- [Wayland] Removed support for `wl_shell` (#1443) - [Wayland] Removed support for `wl_shell` (#1443)

View File

@ -56,26 +56,12 @@
#define _GLFW_XDND_VERSION 5 #define _GLFW_XDND_VERSION 5
// Wait for data to arrive on any of the specified file descriptors
// Wait for event data to arrive on any relevant file descriptor
// This avoids blocking other threads via the per-display Xlib lock that also
// covers GLX functions
// //
static GLFWbool waitForEvent(double* timeout) static GLFWbool waitForData(struct pollfd* fds, nfds_t count, double* timeout)
{ {
for (;;) for (;;)
{ {
nfds_t count = 1;
struct pollfd fds[2] =
{
{ ConnectionNumber(_glfw.x11.display), POLLIN }
};
#if defined(__linux__)
if (_glfw.joysticksInitialized)
fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN };
#endif
if (timeout) if (timeout)
{ {
const int milliseconds = (int) (*timeout * 1e3); const int milliseconds = (int) (*timeout * 1e3);
@ -105,6 +91,33 @@ static GLFWbool waitForEvent(double* timeout)
} }
} }
// Wait for event data to arrive on the X11 display socket
// This avoids blocking other threads via the per-display Xlib lock that also
// covers GLX functions
//
static GLFWbool waitForX11Event(double* timeout)
{
struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN };
return waitForData(&fd, 1, timeout);
}
// Wait for event data to arrive on any event file descriptor
// This avoids blocking other threads via the per-display Xlib lock that also
// covers GLX functions
//
static GLFWbool waitForAnyEvent(double* timeout)
{
nfds_t count = 1;
struct pollfd fds[2] = { { ConnectionNumber(_glfw.x11.display), POLLIN } };
#if defined(__linux__)
if (_glfw.joysticksInitialized)
fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN };
#endif
return waitForData(fds, count, timeout);
}
// Waits until a VisibilityNotify event arrives for the specified window or the // Waits until a VisibilityNotify event arrives for the specified window or the
// timeout period elapses (ICCCM section 4.2.2) // timeout period elapses (ICCCM section 4.2.2)
// //
@ -118,7 +131,7 @@ static GLFWbool waitForVisibilityNotify(_GLFWwindow* window)
VisibilityNotify, VisibilityNotify,
&dummy)) &dummy))
{ {
if (!waitForEvent(&timeout)) if (!waitForX11Event(&timeout))
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -960,7 +973,7 @@ static const char* getSelectionString(Atom selection)
SelectionNotify, SelectionNotify,
&notification)) &notification))
{ {
waitForEvent(NULL); waitForX11Event(NULL);
} }
if (notification.xselection.property == None) if (notification.xselection.property == None)
@ -996,7 +1009,7 @@ static const char* getSelectionString(Atom selection)
isSelPropNewValueNotify, isSelPropNewValueNotify,
(XPointer) &notification)) (XPointer) &notification))
{ {
waitForEvent(NULL); waitForX11Event(NULL);
} }
XFree(data); XFree(data);
@ -1898,7 +1911,7 @@ void _glfwPushSelectionToManagerX11(void)
} }
} }
waitForEvent(NULL); waitForX11Event(NULL);
} }
} }
@ -2240,7 +2253,7 @@ void _glfwGetWindowFrameSizeX11(_GLFWwindow* window,
isFrameExtentsEvent, isFrameExtentsEvent,
(XPointer) window)) (XPointer) window))
{ {
if (!waitForEvent(&timeout)) if (!waitForX11Event(&timeout))
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
@ -2782,7 +2795,7 @@ void _glfwPollEventsX11(void)
void _glfwWaitEventsX11(void) void _glfwWaitEventsX11(void)
{ {
while (!XPending(_glfw.x11.display)) while (!XPending(_glfw.x11.display))
waitForEvent(NULL); waitForAnyEvent(NULL);
_glfwPollEventsX11(); _glfwPollEventsX11();
} }
@ -2791,7 +2804,7 @@ void _glfwWaitEventsTimeoutX11(double timeout)
{ {
while (!XPending(_glfw.x11.display)) while (!XPending(_glfw.x11.display))
{ {
if (!waitForEvent(&timeout)) if (!waitForAnyEvent(&timeout))
break; break;
} }