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

(cherry picked from commit 1e987cb92e)
This commit is contained in:
Camilla Löwy 2022-02-18 15:19:16 +01:00
parent b4aa5f626f
commit 811e6bb01c
2 changed files with 37 additions and 23 deletions

View File

@ -127,6 +127,7 @@ information on what to include when reporting a bug.
- [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences
- [X11] Bugfix: Waiting for events would fail if file descriptor was too large
(#2024)
- [X11] Bugfix: Joystick events could lead to busy-waiting (#1872)
- [Wayland] Added support for key names via xkbcommon
- [Wayland] Bugfix: Key repeat could lead to a race condition (#1710)
- [Wayland] Bugfix: Activating a window would emit two input focus events

View File

@ -56,26 +56,12 @@
#define _GLFW_XDND_VERSION 5
// 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
// Wait for data to arrive on any of the specified file descriptors
//
static GLFWbool waitForEvent(double* timeout)
static GLFWbool waitForData(struct pollfd* fds, nfds_t count, double* timeout)
{
for (;;)
{
nfds_t count = 1;
struct pollfd fds[2] =
{
{ ConnectionNumber(_glfw.x11.display), POLLIN }
};
#if defined(__linux__)
if (_glfw.linjs.inotify > 0)
fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN };
#endif
if (timeout)
{
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.linjs.inotify > 0)
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
// timeout period elapses (ICCCM section 4.2.2)
//
@ -118,7 +131,7 @@ static GLFWbool waitForVisibilityNotify(_GLFWwindow* window)
VisibilityNotify,
&dummy))
{
if (!waitForEvent(&timeout))
if (!waitForX11Event(&timeout))
return GLFW_FALSE;
}
@ -973,7 +986,7 @@ static const char* getSelectionString(Atom selection)
SelectionNotify,
&notification))
{
waitForEvent(NULL);
waitForX11Event(NULL);
}
if (notification.xselection.property == None)
@ -1009,7 +1022,7 @@ static const char* getSelectionString(Atom selection)
isSelPropNewValueNotify,
(XPointer) &notification))
{
waitForEvent(NULL);
waitForX11Event(NULL);
}
XFree(data);
@ -1940,7 +1953,7 @@ void _glfwPushSelectionToManagerX11(void)
}
}
waitForEvent(NULL);
waitForX11Event(NULL);
}
}
@ -2258,7 +2271,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
isFrameExtentsEvent,
(XPointer) window))
{
if (!waitForEvent(&timeout))
if (!waitForX11Event(&timeout))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
@ -2785,7 +2798,7 @@ void _glfwPlatformPollEvents(void)
void _glfwPlatformWaitEvents(void)
{
while (!XPending(_glfw.x11.display))
waitForEvent(NULL);
waitForAnyEvent(NULL);
_glfwPlatformPollEvents();
}
@ -2794,7 +2807,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout)
{
while (!XPending(_glfw.x11.display))
{
if (!waitForEvent(&timeout))
if (!waitForAnyEvent(&timeout))
break;
}