diff --git a/src/waitable.h b/src/waitable.h index f956a2c98..9e25675e9 100644 --- a/src/waitable.h +++ b/src/waitable.h @@ -111,7 +111,7 @@ namespace gamescope class CFunctionWaitable final : public IWaitable { public: - CFunctionWaitable( int nFD, std::function fnPollFunc ) + CFunctionWaitable( int nFD, std::function fnPollFunc = nullptr ) : m_nFD{ nFD } , m_fnPollFunc{ fnPollFunc } { @@ -119,7 +119,8 @@ namespace gamescope void OnPollIn() final { - m_fnPollFunc(); + if ( m_fnPollFunc ) + m_fnPollFunc(); } void Drain() @@ -260,7 +261,7 @@ namespace gamescope epoll_ctl( m_nEpollFD, EPOLL_CTL_DEL, pWaitable->GetFD(), nullptr ); } - void PollEvents( int nTimeOut = -1 ) + int PollEvents( int nTimeOut = -1 ) { epoll_event events[MaxEvents]; @@ -269,15 +270,15 @@ namespace gamescope int nEventCount = epoll_wait( m_nEpollFD, events, MaxEvents, nTimeOut ); if ( !m_bRunning ) - return; + return 0; if ( nEventCount < 0 ) { - if ( errno == EAGAIN ) + if ( errno == EAGAIN || errno == EINTR ) continue; g_WaitableLog.errorf_errno( "Failed to epoll_wait in CAsyncWaiter" ); - return; + return nEventCount; } for ( int i = 0; i < nEventCount; i++ ) @@ -288,7 +289,7 @@ namespace gamescope pWaitable->HandleEvents( event.events ); } - return; + return nEventCount; } } diff --git a/src/wayland_backend.cpp b/src/wayland_backend.cpp index ab3fdf9a6..f5c0ac696 100644 --- a/src/wayland_backend.cpp +++ b/src/wayland_backend.cpp @@ -7,6 +7,7 @@ #include "defer.hpp" #include "convar.h" #include "refresh_rate.h" +#include "waitable.h" #include #include @@ -320,6 +321,7 @@ namespace gamescope { public: CWaylandInputThread(); + ~CWaylandInputThread(); bool Init( CWaylandBackend *pBackend ); @@ -341,6 +343,8 @@ namespace gamescope CWaylandBackend *m_pBackend = nullptr; + CWaiter<4> m_Waiter; + std::thread m_Thread; std::atomic m_bInitted = { false }; @@ -1919,6 +1923,15 @@ namespace gamescope { } + CWaylandInputThread::~CWaylandInputThread() + { + m_bInitted = true; + m_bInitted.notify_all(); + + m_Waiter.Shutdown(); + m_Thread.join(); + } + bool CWaylandInputThread::Init( CWaylandBackend *pBackend ) { m_pBackend = pBackend; @@ -1970,9 +1983,20 @@ namespace gamescope { m_bInitted.wait( false ); + if ( !m_Waiter.IsRunning() ) + return; + int nFD = wl_display_get_fd( m_pBackend->GetDisplay() ); + if ( nFD < 0 ) + { + abort(); + } + + CFunctionWaitable waitable( nFD ); + m_Waiter.AddWaitable( &waitable ); + int nRet = 0; - for ( ;; ) + while ( m_Waiter.IsRunning() ) { if ( ( nRet = wl_display_dispatch_queue_pending( m_pBackend->GetDisplay(), m_pQueue ) ) < 0 ) { @@ -1987,22 +2011,11 @@ namespace gamescope abort(); } - pollfd pollfd = - { - .fd = nFD, - .events = POLLIN, - }; - if ( ( nRet = poll( &pollfd, 1, -1 ) ) <= 0 ) + if ( ( nRet = m_Waiter.PollEvents() ) <= 0 ) { - int nErrno = errno; wl_display_cancel_read( m_pBackend->GetDisplay() ); if ( nRet < 0 ) - { - if ( nErrno == EINTR || nErrno == EAGAIN ) - continue; - abort(); - } assert( nRet == 0 ); continue;