Kaydet (Commit) ea2be4ef authored tarafından Michael Stahl's avatar Michael Stahl

vcl: document the non-obvious WinSalInstance's WaitMutex members

Change-Id: I004f082c9e4a17aeb7a8bd778bf45dff93e47ee8
üst 482c52e9
...@@ -27,11 +27,21 @@ class SalYieldMutex; ...@@ -27,11 +27,21 @@ class SalYieldMutex;
class WinSalInstance : public SalInstance class WinSalInstance : public SalInstance
{ {
public: public:
HINSTANCE mhInst; // Instance Handle /// Instance Handle
HWND mhComWnd; // window, for communication (between threads and the main thread) HINSTANCE mhInst;
SalYieldMutex* mpSalYieldMutex; // Sal-Yield-Mutex /// invisible Window so non-main threads can SendMessage() the main thread
osl::Mutex* mpSalWaitMutex; // Sal-Wait-Mutex HWND mhComWnd;
sal_uInt16 mnYieldWaitCount; // Wait-Count /// The Yield mutex ensures that only one thread calls into VCL
SalYieldMutex* mpSalYieldMutex;
/// The Wait mutex ensures increment of mnYieldWaitCount and acquisition
/// or release of mpSalYieldMutex is atomic
osl::Mutex* mpSalWaitMutex;
/// count main thread's pending ImplSalYieldMutexAcquireWithWait() calls
/// (it's not clear to me if this will be > 1 in practice; it would be
/// possible if main thread's handling of SAL_MSG_* sent by other threads
/// via SendMessage() ends up calling ImplSalYieldMutexAcquireWithWait())
sal_uInt16 mnYieldWaitCount;
public: public:
WinSalInstance(); WinSalInstance();
virtual ~WinSalInstance(); virtual ~WinSalInstance();
......
...@@ -159,6 +159,8 @@ void SalYieldMutex::release() ...@@ -159,6 +159,8 @@ void SalYieldMutex::release()
// Java clients doesn't come in the right order // Java clients doesn't come in the right order
GdiFlush(); GdiFlush();
// lock here to ensure that the test of mnYieldWaitCount and
// m_mutex.release() is atomic
mpInstData->mpSalWaitMutex->acquire(); mpInstData->mpSalWaitMutex->acquire();
if ( mpInstData->mnYieldWaitCount ) if ( mpInstData->mnYieldWaitCount )
PostMessageW( mpInstData->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 ); PostMessageW( mpInstData->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
...@@ -203,16 +205,19 @@ sal_uLong SalYieldMutex::GetAcquireCount( sal_uLong nThreadId ) ...@@ -203,16 +205,19 @@ sal_uLong SalYieldMutex::GetAcquireCount( sal_uLong nThreadId )
return 0; return 0;
} }
/// note: while VCL is fully up and running (other threads started and
/// before shutdown), the main thread must acquire SolarMutex only via
/// this function to avoid deadlock
void ImplSalYieldMutexAcquireWithWait() void ImplSalYieldMutexAcquireWithWait()
{ {
WinSalInstance* pInst = GetSalData()->mpFirstInstance; WinSalInstance* pInst = GetSalData()->mpFirstInstance;
if ( !pInst ) if ( !pInst )
return; return;
// If we are the main thread, then we must wait with wait, because // If this is the main thread, then we must wait with GetMessage(),
// in if we don't reschedule, then we create deadlocks if a Windows // because if we don't reschedule, then we create deadlocks if a Window's
// Function is called from another thread. If we aren't the main thread, // create/destroy is called via SendMessage() from another thread.
// than we call acquire directly. // If this is not the main thread, call acquire directly.
DWORD nThreadId = GetCurrentThreadId(); DWORD nThreadId = GetCurrentThreadId();
SalData* pSalData = GetSalData(); SalData* pSalData = GetSalData();
if ( pSalData->mnAppThreadId == nThreadId ) if ( pSalData->mnAppThreadId == nThreadId )
...@@ -233,13 +238,26 @@ void ImplSalYieldMutexAcquireWithWait() ...@@ -233,13 +238,26 @@ void ImplSalYieldMutexAcquireWithWait()
} }
else else
{ {
// other threads must not observe mnYieldWaitCount == 0
// while main thread is blocked in GetMessage()
pInst->mnYieldWaitCount++; pInst->mnYieldWaitCount++;
pInst->mpSalWaitMutex->release(); pInst->mpSalWaitMutex->release();
MSG aTmpMsg; MSG aTmpMsg;
// this call exists because it dispatches SendMessage() msg!
GetMessageW( &aTmpMsg, pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, SAL_MSG_RELEASEWAITYIELD ); GetMessageW( &aTmpMsg, pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, SAL_MSG_RELEASEWAITYIELD );
// it is possible that another thread acquires and releases
// mpSalYieldMutex after the GetMessage call returns,
// observes mnYieldWaitCount != 0 and sends an extra
// SAL_MSG_RELEASEWAITYIELD - but that appears unproblematic
// as it will just cause the next Yield to do an extra
// iteration of the while loop here
pInst->mnYieldWaitCount--; pInst->mnYieldWaitCount--;
if ( pInst->mnYieldWaitCount ) if ( pInst->mnYieldWaitCount )
{
// repeat the message so that the next instance of this
// function further up the call stack is unblocked too
PostMessageW( pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 ); PostMessageW( pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
}
} }
} }
} }
...@@ -701,6 +719,8 @@ LRESULT CALLBACK SalComWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lPar ...@@ -701,6 +719,8 @@ LRESULT CALLBACK SalComWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lPar
case SAL_MSG_RELEASEWAITYIELD: case SAL_MSG_RELEASEWAITYIELD:
{ {
WinSalInstance* pInst = GetSalData()->mpFirstInstance; WinSalInstance* pInst = GetSalData()->mpFirstInstance;
// this test does not need mpSalWaitMutex locked because
// it can only happen on the main thread
if ( pInst && pInst->mnYieldWaitCount ) if ( pInst && pInst->mnYieldWaitCount )
PostMessageW( hWnd, SAL_MSG_RELEASEWAITYIELD, wParam, lParam ); PostMessageW( hWnd, SAL_MSG_RELEASEWAITYIELD, wParam, lParam );
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment