From: <man...@us...> - 2013-04-08 16:34:18
|
Revision: 1777 http://sourceforge.net/p/modplug/code/1777 Author: manxorist Date: 2013-04-08 16:34:04 +0000 (Mon, 08 Apr 2013) Log Message: ----------- [Ref] Do less work in NotifyThread. Move searching for the newest notification to the main thread and let the notify thread only forward a rate-limited trigger. This also fixes an obscure race condition when clicking stop and clearing the notification buffer while a notification was pending. Modified Paths: -------------- trunk/OpenMPT/mptrack/InputHandler.h trunk/OpenMPT/mptrack/MainFrm.cpp trunk/OpenMPT/mptrack/Mainfrm.h Modified: trunk/OpenMPT/mptrack/InputHandler.h =================================================================== --- trunk/OpenMPT/mptrack/InputHandler.h 2013-04-08 10:38:15 UTC (rev 1776) +++ trunk/OpenMPT/mptrack/InputHandler.h 2013-04-08 16:34:04 UTC (rev 1777) @@ -14,7 +14,7 @@ enum { WM_MOD_UPDATEPOSITION = (WM_USER+1973), - WM_MOD_UPDATEPOSITIONTHREADED, + WM_MOD_NOTIFICATION, WM_MOD_INVALIDATEPATTERNS, WM_MOD_ACTIVATEVIEW, WM_MOD_CHANGEVIEWCLASS, Modified: trunk/OpenMPT/mptrack/MainFrm.cpp =================================================================== --- trunk/OpenMPT/mptrack/MainFrm.cpp 2013-04-08 10:38:15 UTC (rev 1776) +++ trunk/OpenMPT/mptrack/MainFrm.cpp 2013-04-08 16:34:04 UTC (rev 1777) @@ -85,8 +85,8 @@ ON_UPDATE_COMMAND_UI(ID_INDICATOR_XINFO,OnUpdateXInfo) //rewbs.xinfo ON_UPDATE_COMMAND_UI(ID_INDICATOR_CPU, OnUpdateCPU) ON_UPDATE_COMMAND_UI(IDD_TREEVIEW, OnUpdateControlBarMenu) + ON_MESSAGE(WM_MOD_NOTIFICATION, OnNotification) ON_MESSAGE(WM_MOD_UPDATEPOSITION, OnUpdatePosition) - ON_MESSAGE(WM_MOD_UPDATEPOSITIONTHREADED, OnUpdatePositionThreaded) ON_MESSAGE(WM_MOD_INVALIDATEPATTERNS, OnInvalidatePatterns) ON_MESSAGE(WM_MOD_SPECIALKEY, OnSpecialKey) ON_MESSAGE(WM_MOD_KEYCOMMAND, OnCustomKeyMsg) //rewbs.customKeys @@ -670,83 +670,35 @@ DWORD CMainFrame::NotifyThread() //------------------------------ { - // initialize thread message queue MSG msg; - PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); -#ifdef NDEBUG - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL ); // we shall not stall the audio thread while holding m_NotificationBufferMutex -#endif + PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); // initialize thread message queue bool terminate = false; bool cansend = true; while(!terminate) { - switch(MsgWaitForMultipleObjects(1, &m_hNotifyWakeUp, FALSE, 1000, QS_ALLEVENTS)) + HANDLE waitHandles[2]; + waitHandles[0] = m_PendingNotificationSempahore; + waitHandles[1] = m_hNotifyWakeUp; + switch(MsgWaitForMultipleObjects(2, waitHandles, FALSE, 1000, QS_ALLEVENTS)) { + case WAIT_OBJECT_0 + 0: + // last notification has been handled by gui thread + cansend = true; + break; case WAIT_OBJECT_0 + 1: - { - while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + if(cansend) { - if(msg.message == WM_QUIT) terminate = true; + if(PostMessage(WM_MOD_NOTIFICATION, 0, 0)) + { + // message sent, do not send any more until it has been handled + cansend = false; + } } - } break; - case WAIT_OBJECT_0: + case WAIT_OBJECT_0 + 2: + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - const Notification * pnotify = nullptr; - { - int64 currenttotalsamples = 0; - bool currenttotalsamplesValid = false; - { - CriticalSection cs; - if(gpSoundDevice && gpSoundDevice->HasGetStreamPosition()) - { - currenttotalsamples = gpSoundDevice->GetStreamPositionSamples(); - currenttotalsamplesValid = true; - } - } - // advance to the newest notification, drop the obsolete ones - Util::lock_guard<Util::mutex> lock(m_NotificationBufferMutex); - if(!currenttotalsamplesValid) - { - currenttotalsamples = m_TotalSamplesRendered; - currenttotalsamplesValid = true; - } - const Notification * p = m_NotifyBuffer.peek_p(); - if(p && currenttotalsamples >= p->timestampSamples) - { - pnotify = p; - while(m_NotifyBuffer.peek_next_p() && currenttotalsamples >= m_NotifyBuffer.peek_next_p()->timestampSamples) - { - m_NotifyBuffer.pop(); - p = m_NotifyBuffer.peek_p(); - pnotify = p; - } - } - } - if(pnotify) - { - if(!cansend) - { - // poll the semaphore instead of waiting directly after sending the message to avoid deadlocks on termination of openmpt or when stopping audio rendering - if(WaitForSingleObject(m_PendingNotificationSempahore, 0) == WAIT_OBJECT_0) - { - // last notification has been handled by gui thread, so we can pop the notify buffer - cansend = true; - } - } - if(cansend) - { - m_PendingNotification = *pnotify; // copy notification so that we can free the buffer - { - Util::lock_guard<Util::mutex> lock(m_NotificationBufferMutex); - m_NotifyBuffer.pop(); - } - if(PostMessage(WM_MOD_UPDATEPOSITIONTHREADED, 0, 0)) - { - cansend = false; - } - } - } + if(msg.message == WM_QUIT) terminate = true; } break; } @@ -755,6 +707,60 @@ } +LRESULT CMainFrame::OnNotification(WPARAM, LPARAM) +//------------------------------------------------ +{ + Notification PendingNotification; + bool found = false; + int64 currenttotalsamples = 0; + bool currenttotalsamplesValid = false; + { + CriticalSection cs; + if(gpSoundDevice && gpSoundDevice->HasGetStreamPosition()) + { + currenttotalsamples = gpSoundDevice->GetStreamPositionSamples(); + currenttotalsamplesValid = true; + } + } + { + // advance to the newest notification, drop the obsolete ones + Util::lock_guard<Util::mutex> lock(m_NotificationBufferMutex); + if(!currenttotalsamplesValid) + { + currenttotalsamples = m_TotalSamplesRendered; + currenttotalsamplesValid = true; + } + const Notification * pnotify = nullptr; + const Notification * p = m_NotifyBuffer.peek_p(); + if(p && currenttotalsamples >= p->timestampSamples) + { + pnotify = p; + while(m_NotifyBuffer.peek_next_p() && currenttotalsamples >= m_NotifyBuffer.peek_next_p()->timestampSamples) + { + m_NotifyBuffer.pop(); + p = m_NotifyBuffer.peek_p(); + pnotify = p; + } + } + if(pnotify) + { + PendingNotification = *pnotify; // copy notification so that we can free the buffer + found = true; + { + Util::lock_guard<Util::mutex> lock(m_NotificationBufferMutex); + m_NotifyBuffer.pop(); + } + } + } + if(found) + { + OnUpdatePosition(0, (LPARAM)&PendingNotification); + } + ReleaseSemaphore(m_PendingNotificationSempahore, 1, NULL); + return 0; +} + + void CMainFrame::SetAudioThreadActive(bool active) //------------------------------------------------ { @@ -2283,17 +2289,6 @@ } -LRESULT CMainFrame::OnUpdatePositionThreaded(WPARAM, LPARAM) -//---------------------------------------------------------- -{ - Notification * pnotify = &m_PendingNotification; - LRESULT retval = OnUpdatePosition(0, (LPARAM)pnotify); - // for all notifications which were delivered via the notification thread, release the semaphore - ReleaseSemaphore(m_PendingNotificationSempahore, 1, NULL); - return retval; -} - - LRESULT CMainFrame::OnUpdatePosition(WPARAM, LPARAM lParam) //--------------------------------------------------------- { Modified: trunk/OpenMPT/mptrack/Mainfrm.h =================================================================== --- trunk/OpenMPT/mptrack/Mainfrm.h 2013-04-08 10:38:15 UTC (rev 1776) +++ trunk/OpenMPT/mptrack/Mainfrm.h 2013-04-08 16:34:04 UTC (rev 1777) @@ -323,7 +323,6 @@ int64 m_TotalSamplesRendered; Util::fixed_size_queue<Notification,MAX_UPDATE_HISTORY> m_NotifyBuffer; HANDLE m_PendingNotificationSempahore; // protects the one notification that is in flight from the notification thread to the gui thread from being freed while the gui thread still uses it - Notification m_PendingNotification; // Instrument preview in tree view CSoundFile m_WaveFile; @@ -530,8 +529,8 @@ afx_msg void OnPanic(); afx_msg void OnReportBug(); //rewbs.customKeys afx_msg BOOL OnInternetLink(UINT nID); + afx_msg LRESULT OnNotification(WPARAM, LPARAM lParam); afx_msg LRESULT OnUpdatePosition(WPARAM, LPARAM lParam); - afx_msg LRESULT OnUpdatePositionThreaded(WPARAM, LPARAM lParam); afx_msg void OnExampleSong(UINT nId); afx_msg void OnOpenTemplateModule(UINT nId); afx_msg LRESULT OnInvalidatePatterns(WPARAM, LPARAM); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |