changeset: 651243:ff57728124c6 tag: tip parent: 651233:dd0fdd1daa69 user: stransky date: Tue Jan 31 15:53:38 2023 +0100 files: widget/gtk/GfxInfo.cpp description: Bug 1813500 [Linux] Don't hang Firefox when glxtest process hangs r?emilio,rmader Differential Revision: https://phabricator.services.mozilla.com/D168385 diff --git a/widget/gtk/GfxInfo.cpp b/widget/gtk/GfxInfo.cpp --- a/widget/gtk/GfxInfo.cpp +++ b/widget/gtk/GfxInfo.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,9 @@ #include "WidgetUtilsGtk.h" #include "MediaCodecsSupport.h" +// How long we wait for data from glxtest process in milliseconds. +#define GLXTEST_TIMEOUT 4000 + #define EXIT_STATUS_BUFFER_TOO_SMALL 2 #ifdef DEBUG bool fire_glxtest_process(); @@ -99,12 +103,28 @@ void GfxInfo::GetData() { // information in a separate process to protect against bad drivers. // if glxtest_pipe == -1, that means that we already read the information - if (glxtest_pipe == -1) return; + if (glxtest_pipe == -1) { + return; + } + + const TimeStamp deadline = + TimeStamp::Now() + TimeDuration::FromMilliseconds(GLXTEST_TIMEOUT); enum { buf_size = 2048 }; char buf[buf_size]; - ssize_t bytesread = read(glxtest_pipe, &buf, - buf_size - 1); // -1 because we'll append a zero + ssize_t bytesread = 0; + + struct pollfd pfd {}; + pfd.fd = glxtest_pipe; + pfd.events = POLLIN; + auto ret = poll(&pfd, 1, GLXTEST_TIMEOUT); + if (ret <= 0) { + gfxCriticalNote << "glxtest: failed to read data from glxtest, we may " + "fallback to software rendering\n"; + } else { + // -1 because we'll append a zero + bytesread = read(glxtest_pipe, &buf, buf_size - 1); + } close(glxtest_pipe); glxtest_pipe = -1; @@ -129,9 +149,9 @@ void GfxInfo::GetData() { int waitpid_errno = 0; while (wait_for_glxtest_process) { wait_for_glxtest_process = false; - if (waitpid(glxtest_pid, &glxtest_status, 0) == -1) { + if (waitpid(glxtest_pid, &glxtest_status, WNOHANG) == -1) { waitpid_errno = errno; - if (waitpid_errno == EINTR) { + if (waitpid_errno == EAGAIN || waitpid_errno == EINTR) { wait_for_glxtest_process = true; } else { // Bug 718629 @@ -142,6 +162,15 @@ void GfxInfo::GetData() { waiting_for_glxtest_process_failed = (waitpid_errno != ECHILD); } } + if (wait_for_glxtest_process) { + if (TimeStamp::Now() > deadline) { + gfxCriticalNote << "glxtest: glxtest process hangs\n"; + waiting_for_glxtest_process_failed = true; + break; + } + // Wait 100ms to another waitpid() check. + usleep(100000); + } } int exit_code = EXIT_FAILURE;