Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent deadlock when calling SetWindowPos from another thread #14306

Merged
merged 1 commit into from Aug 20, 2018

Conversation

popy2k14
Copy link
Contributor

flag SWP_ASYNCWINDOWPOS, see https://msdn.microsoft.com/en-us/library/windows/desktop/ms633545%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

Description

When SetWindowPos is called from another thread with the main gui HWND, kodi freezes!
This was the case on ExternalPlayer.cpp, see ticket: https://trac.kodi.tv/ticket/17988
My PR adds the SWP_ASYNCWINDOWPOS flag on all SetWindowPos.
So the risk of ever running into the same problem, when calling ->Show() is low.

Motivation and Context

Kodi freezes when external player is active and STOP is pressed on keyboard or received, json, remote...

How Has This Been Tested?

On my dev machine, the issue is reproduce able like described in the ticket.
After the PR, issue is gone for me.

Types of change

  • [X ] Bug fix (non-breaking change which fixes an issue)
  • Clean up (non-breaking change which removes non-working, unmaintained functionality)
  • [X ] Improvement (non-breaking change which improves existing functionality)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that will cause existing functionality to change)
  • Cosmetic change (non-breaking change that doesn't touch code)
  • None of the above (please explain below)

Checklist:

  • [X ] My code follows the Code Guidelines of this project
  • My change requires a change to the documentation, either Doxygen or wiki
  • I have updated the documentation accordingly
  • [X ] I have read the Contributing document
  • I have added tests to cover my change
  • All new and existing tests passed

@Rechi Rechi requested a review from afedchin August 16, 2018 18:17
Copy link
Member

@afedchin afedchin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please drop changes that I commented, because Kodi expects old behavior in these places. I think it will not cause an issue, but I don't want to risk at this stage of development v18.

@@ -401,7 +401,7 @@ void CWinSystemWin32::AdjustWindow(bool forceResize)
rc.top,
rc.right - rc.left,
rc.bottom - rc.top,
SWP_SHOWWINDOW | SWP_DRAWFRAME
SWP_SHOWWINDOW | SWP_DRAWFRAME | SWP_ASYNCWINDOWPOS

This comment was marked as spam.

@@ -586,7 +586,7 @@ bool CWinSystemWin32::DPIChanged(WORD dpi, RECT windowRect) const
resizeRect.top,
resizeRect.right - resizeRect.left,
resizeRect.bottom - resizeRect.top,
SWP_NOZORDER | SWP_NOACTIVATE);
SWP_NOZORDER | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);

This comment was marked as spam.

@@ -1122,7 +1122,7 @@ void CWinSystemWin32::NotifyAppFocusChange(bool bGaining)
ReleaseBackBuffer();

if (bGaining)
SetWindowPos(m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);
SetWindowPos(m_hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_ASYNCWINDOWPOS);

This comment was marked as spam.

@@ -1132,7 +1132,7 @@ void CWinSystemWin32::NotifyAppFocusChange(bool bGaining)
SetDeviceFullScreen(bGaining, res);

if (!bGaining)
SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);
SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_ASYNCWINDOWPOS);

This comment was marked as spam.

@afedchin
Copy link
Member

after some thoughts I concluded that you fixed consequence but not a root reason. CExternalPlayer shouldn't change window not from main thread. So in my opinion acceptable solution is sending a message/event to the main thread to change window. @FernetMenta what do you think?

@FernetMenta
Copy link
Contributor

Right, SetWindowPos is Windows API function and must only be called by windowing component.

So in my opinion acceptable solution is sending a message/event to the main thread to change window

I am not sure if this is Windows only or something generic.

@popy2k14
Copy link
Contributor Author

You are right but if anybody uses SetWindowPos from another thread again!?
This could happen also when this issue is solved with an event to the main thread.

@FernetMenta
Copy link
Contributor

You are right but if anybody uses SetWindowPos from another thread again!?

won't happen if g_hWnd gets eliminated.

@afedchin
Copy link
Member

You are right but if anybody uses SetWindowPos from another thread again!?

nobody except windowing shouldn't use SetWindowPos. Using SetWindowPos from ExternalPlayer is bad. Fernet is right g_hWnd must be eliminated.

This could happen also when this issue is solved with an event to the main thread.

application events are processed from main thread only.

@popy2k14
Copy link
Contributor Author

@afedchin @FernetMenta when ill do the changes to the PR and leave the async flag in exernal player (which is a quick fix), do you merge it?

We than can create an ticket for removing the g_hWnd variable.

What do you think?

@FernetMenta
Copy link
Contributor

I never do such quick hacks but I leave the decision to @afedchin

@popy2k14
Copy link
Contributor Author

I'll removed the flag from other code playces and just leave it there which belongs to ExternalPlayer.
@afedchin Please, whats your decision? Would be nice if you merge this because some of use using ExternalPlayer currently :-)

We can make a ticket which describes the issue and thats the best way is to eleminate the g_hWnd variable.

Thanks

@fritsch
Copy link
Member

fritsch commented Aug 18, 2018 via email

@popy2k14
Copy link
Contributor Author

Yeah. but eliminating the variable will not be that easy.
I'ts used in several other components where windows api is needing an hwnd.
Here are the references where they are used:

\xbmc\xbmc\cores\AudioEngine\Sinks\AESinkDirectSound.cpp(163): HWND tmp_hWnd = g_hWnd == nullptr ? GetDesktopWindow() : g_hWnd;
\xbmc\xbmc\cores\ExternalPlayer\ExternalPlayer.cpp(349): SetForegroundWindow(g_hWnd);
\xbmc\xbmc\network\mdns\ZeroconfBrowserMDNS.cpp(27):extern HWND g_hWnd;
\xbmc\xbmc\network\mdns\ZeroconfMDNS.cpp(204): WSAAsyncSelect( (SOCKET) DNSServiceRefSockFD( m_service ), g_hWnd, BONJOUR_EVENT, 0 );
\xbmc\xbmc\platform\win32\WIN32Util.cpp(254): ShowWindow(g_hWnd,SW_MINIMIZE);
\xbmc\xbmc\platform\win32\WindowHelper.cpp(49): SetForegroundWindow(g_hWnd);
\xbmc\xbmc\powermanagement\PowerManager.cpp(202): SetForegroundWindow(g_hWnd);
\xbmc\xbmc\windowing\windows\WinEventsWin32.cpp(263): g_hWnd = nullptr;

As an example in the ZeroconfBrowserMDNS.cpp the WSAAsyncSelect needs an hwnd where the event gets passed after select is ok, so there the correct hwnd is needed for this to work.
Did'nt look a the other files, but i assume the same.
So elliminating the global hwnd is not the right way.

@afedchin
Copy link
Member

Please, whats your decision? Would be nice if you merge this because some of use using ExternalPlayer currently :-)

If current fix resolves the issue, I can aprove it.

So elliminating the global hwnd is not the right way.

It's right way, you just doesn't see how to resolve it.

@popy2k14
Copy link
Contributor Author

The current fix resolves the main issue, please aprove it.
Should ill create a ticket regarding the global hwnd?

@afedchin
Copy link
Member

Should ill create a ticket regarding the global hwnd?

no need. I've added this to my todo list

@afedchin afedchin merged commit 50d4a65 into xbmc:master Aug 20, 2018
@afedchin
Copy link
Member

thanks. merged

@popy2k14
Copy link
Contributor Author

Thanks!

@Rechi Rechi added Type: Fix non-breaking change which fixes an issue Platform: Windows v18 Leia labels Aug 20, 2018
@MartijnKaijser MartijnKaijser added this to the Leia 18.0-beta1 milestone Aug 26, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Platform: Windows Type: Fix non-breaking change which fixes an issue v18 Leia
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants