Alexandre Julliard wrote:
> Ulrich Weigand <[EMAIL PROTECTED]> writes:
>
> > But in this case, I think Ove is basically right: you have only one
> > race between QUEUE_SetWakeBit and QUEUE_WaitBits.
>
> Well, yes of course, the race is between testing and setting the bits,
> but the race not only happens if the compiler optimizes out the second
> test, it can happen for a number of reasons (like reordering of the
> assignments, two threads setting bits at the same time, etc.)
Well, volatile prevents reordering of assignments. But nevertheless
I agree, volatile helps only if you have atomic operations in the
first place ... (On Intel, load/store to an aligned dword is atomic,
so the only problem is the |=. Of course, on other architectures,
not even that is necessarily guaranteed.)
> > What do you think about this patch, for example? (Untested ...)
>
> That seems reasonable yes.
Well, that quick patch contained a potential deadlock due to lock
order inversion :-( Furthermore, it really only makes sense if
*all* accesses to wakeBits/changeBits/wakeMask are protected ...
The following patch is a more complete implementation of this idea;
it is also somewhat tested (at least the Borland Thread Sorting Demo,
my old stress test case for inter-thread messages, still runs ;-).
Ove, could you try whether this solves your deadlock?
Bye,
Ulrich
ChangeLog:
* include/queue.h windows/queue.c windows/message.c
Protect queue->wakeBits/changeBits/wakeBits by critical section.
diff -ur wine-cvs/include/queue.h wine-uw/include/queue.h
--- wine-cvs/include/queue.h Wed Jan 3 22:51:30 2001
+++ wine-uw/include/queue.h Wed Jan 3 23:10:28 2001
@@ -159,7 +159,8 @@
extern MESSAGEQUEUE *QUEUE_GetSysQueue(void);
extern void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit );
extern void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit );
-extern void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue );
+extern WORD QUEUE_TestWakeBit( MESSAGEQUEUE *queue, WORD bit );
+extern BOOL QUEUE_ReceiveMessage( MESSAGEQUEUE *queue );
extern int QUEUE_WaitBits( WORD bits, DWORD timeout );
extern void QUEUE_IncPaintCount( HQUEUE16 hQueue );
extern void QUEUE_DecPaintCount( HQUEUE16 hQueue );
diff -ur wine-cvs/windows/message.c wine-uw/windows/message.c
--- wine-cvs/windows/message.c Wed Jan 3 22:51:35 2001
+++ wine-uw/windows/message.c Wed Jan 3 23:12:58 2001
@@ -1123,7 +1123,7 @@
static BOOL MSG_PeekMessage( int type, LPMSG msg, HWND hwnd,
DWORD first, DWORD last, WORD flags, BOOL peek )
{
- int mask;
+ int changeBits, mask;
MESSAGEQUEUE *msgQueue;
HQUEUE16 hQueue;
POINT16 pt16;
@@ -1159,12 +1159,15 @@
WIN_RestoreWndsLock(iWndsLocks);
return FALSE;
}
+
+ EnterCriticalSection( &msgQueue->cSection );
msgQueue->changeBits = 0;
+ LeaveCriticalSection( &msgQueue->cSection );
/* First handle a message put by SendMessage() */
- while (msgQueue->wakeBits & QS_SENDMESSAGE)
- QUEUE_ReceiveMessage( msgQueue );
+ while ( QUEUE_ReceiveMessage( msgQueue ) )
+ ;
/* Now handle a WM_QUIT message */
@@ -1183,7 +1186,7 @@
/* Now find a normal message */
retry:
- if (((msgQueue->wakeBits & mask) & QS_POSTMESSAGE) &&
+ if ((QUEUE_TestWakeBit(msgQueue, mask & QS_POSTMESSAGE)) &&
((qmsg = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != 0))
{
/* Try to convert message to requested type */
@@ -1206,7 +1209,10 @@
break;
}
- msgQueue->changeBits |= MSG_JournalPlayBackMsg();
+ changeBits = MSG_JournalPlayBackMsg();
+ EnterCriticalSection( &msgQueue->cSection );
+ msgQueue->changeBits |= changeBits;
+ LeaveCriticalSection( &msgQueue->cSection );
/* Now find a hardware event */
@@ -1222,12 +1228,12 @@
/* Check again for SendMessage */
- while (msgQueue->wakeBits & QS_SENDMESSAGE)
- QUEUE_ReceiveMessage( msgQueue );
+ while ( QUEUE_ReceiveMessage( msgQueue ) )
+ ;
/* Now find a WM_PAINT message */
- if ((msgQueue->wakeBits & mask) & QS_PAINT)
+ if (QUEUE_TestWakeBit(msgQueue, mask & QS_PAINT))
{
WND* wndPtr;
msg->hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
@@ -1263,10 +1269,11 @@
if (!(flags & PM_NOYIELD))
{
UserYield16();
- while (msgQueue->wakeBits & QS_SENDMESSAGE)
- QUEUE_ReceiveMessage( msgQueue );
+ while ( QUEUE_ReceiveMessage( msgQueue ) )
+ ;
}
- if ((msgQueue->wakeBits & mask) & QS_TIMER)
+
+ if (QUEUE_TestWakeBit(msgQueue, mask & QS_TIMER))
{
if (TIMER_GetTimerMsg(msg, hwnd, hQueue, flags & PM_REMOVE)) break;
}
@@ -1279,7 +1286,7 @@
WIN_RestoreWndsLock(iWndsLocks);
return FALSE;
}
- msgQueue->wakeMask = mask;
+
QUEUE_WaitBits( mask, INFINITE );
QUEUE_Unlock( msgQueue );
}
@@ -1986,8 +1993,10 @@
return WAIT_FAILED;
}
+ EnterCriticalSection( &msgQueue->cSection );
msgQueue->changeBits = 0;
msgQueue->wakeMask = dwWakeMask;
+ LeaveCriticalSection( &msgQueue->cSection );
if (THREAD_IsWin16(NtCurrentTeb()))
{
@@ -2025,11 +2034,14 @@
/*
* If a message matching the wait mask has arrived, return.
*/
+ EnterCriticalSection( &msgQueue->cSection );
if (msgQueue->changeBits & dwWakeMask)
{
+ LeaveCriticalSection( &msgQueue->cSection );
ret = nCount;
break;
}
+ LeaveCriticalSection( &msgQueue->cSection );
/*
* And continue doing this until we hit the timeout.
diff -ur wine-cvs/windows/queue.c wine-uw/windows/queue.c
--- wine-cvs/windows/queue.c Wed Jan 3 22:51:35 2001
+++ wine-uw/windows/queue.c Wed Jan 3 23:10:19 2001
@@ -620,19 +620,32 @@
*
* See "Windows Internals", p.449
*/
-void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
+static BOOL QUEUE_TrySetWakeBit( MESSAGEQUEUE *queue, WORD bit, BOOL always )
{
- TRACE_(msg)("queue = %04x (wm=%04x), bit = %04x\n",
- queue->self, queue->wakeMask, bit );
+ BOOL wake = FALSE;
+
+ EnterCriticalSection( &queue->cSection );
+
+ TRACE_(msg)("queue = %04x (wm=%04x), bit = %04x, always = %d\n",
+ queue->self, queue->wakeMask, bit, always );
- if (bit & QS_MOUSE) pMouseQueue = queue;
- if (bit & QS_KEY) pKbdQueue = queue;
- queue->changeBits |= bit;
- queue->wakeBits |= bit;
+ if ((queue->wakeMask & bit) || always)
+ {
+ if (bit & QS_MOUSE) pMouseQueue = queue;
+ if (bit & QS_KEY) pKbdQueue = queue;
+ queue->changeBits |= bit;
+ queue->wakeBits |= bit;
+ }
if (queue->wakeMask & bit)
{
queue->wakeMask = 0;
+ wake = TRUE;
+ }
+ LeaveCriticalSection( &queue->cSection );
+
+ if ( wake )
+ {
/* Wake up thread waiting for message */
if ( THREAD_IsWin16( queue->teb ) )
{
@@ -652,6 +665,12 @@
SERVER_END_REQ;
}
}
+
+ return wake;
+}
+void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit )
+{
+ QUEUE_TrySetWakeBit( queue, bit, TRUE );
}
@@ -660,8 +679,22 @@
*/
void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
{
+ EnterCriticalSection( &queue->cSection );
queue->changeBits &= ~bit;
queue->wakeBits &= ~bit;
+ LeaveCriticalSection( &queue->cSection );
+}
+
+/***********************************************************************
+ * QUEUE_TestWakeBit
+ */
+WORD QUEUE_TestWakeBit( MESSAGEQUEUE *queue, WORD bit )
+{
+ WORD ret;
+ EnterCriticalSection( &queue->cSection );
+ ret = queue->wakeBits & bit;
+ LeaveCriticalSection( &queue->cSection );
+ return ret;
}
@@ -690,29 +723,30 @@
for (;;)
{
+ EnterCriticalSection( &queue->cSection );
+
if (queue->changeBits & bits)
{
/* One of the bits is set; we can return */
queue->wakeMask = 0;
+
+ LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue );
return 1;
}
if (queue->wakeBits & QS_SENDMESSAGE)
{
/* Process the sent message immediately */
-
queue->wakeMask = 0;
+
+ LeaveCriticalSection( &queue->cSection );
QUEUE_ReceiveMessage( queue );
continue; /* nested sm crux */
}
queue->wakeMask = bits | QS_SENDMESSAGE;
- if(queue->changeBits & bits)
- {
- continue;
- }
-
TRACE_(msg)("%04x) wakeMask is %04x, waiting\n", queue->self, queue->wakeMask);
+ LeaveCriticalSection( &queue->cSection );
if ( !THREAD_IsWin16( NtCurrentTeb() ) )
{
@@ -905,21 +939,24 @@
/***********************************************************************
* QUEUE_ReceiveMessage
*
- * This routine is called when a sent message is waiting for the queue.
+ * This routine is called to check whether a sent message is waiting
+ * for the queue. If so, it is received and processed.
*/
-void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
+BOOL QUEUE_ReceiveMessage( MESSAGEQUEUE *queue )
{
LRESULT result = 0;
SMSG *smsg;
MESSAGEQUEUE *senderQ;
- TRACE_(sendmsg)("queue %04x\n", queue->self );
-
+ EnterCriticalSection( &queue->cSection );
if ( !((queue->wakeBits & QS_SENDMESSAGE) && queue->smPending) )
{
- TRACE_(sendmsg)("\trcm: nothing to do\n");
- return;
+ LeaveCriticalSection( &queue->cSection );
+ return FALSE;
}
+ LeaveCriticalSection( &queue->cSection );
+
+ TRACE_(sendmsg)("queue %04x\n", queue->self );
/* remove smsg on the top of the pending list and put it in the processing list */
smsg = QUEUE_RemoveSMSG(queue, SM_PENDING_LIST, 0);
@@ -974,6 +1011,7 @@
ReplyMessage( result );
TRACE_(sendmsg)("done!\n" );
+ return TRUE;
}
@@ -1144,28 +1182,28 @@
}
if (hQueue)
- queue = QUEUE_Lock( hQueue );
-
- if( !queue )
{
- queue = QUEUE_Lock( hFirstQueue );
- while( queue )
- {
- if (queue->wakeMask & wakeBit) break;
-
- QUEUE_Unlock(queue);
- queue = QUEUE_Lock( queue->next );
- }
- if( !queue )
- {
- WARN_(msg)("couldn't find queue\n");
- return;
- }
+ queue = QUEUE_Lock( hQueue );
+ QUEUE_SetWakeBit( queue, wakeBit );
+ QUEUE_Unlock( queue );
+ return;
}
- QUEUE_SetWakeBit( queue, wakeBit );
+ /* Search for someone to wake */
+ queue = QUEUE_Lock( hFirstQueue );
+ while ( queue )
+ {
+ if (QUEUE_TrySetWakeBit( queue, wakeBit, FALSE ))
+ {
+ QUEUE_Unlock( queue );
+ return;
+ }
+
+ QUEUE_Unlock(queue);
+ queue = QUEUE_Lock( queue->next );
+ }
- QUEUE_Unlock( queue );
+ WARN_(msg)("couldn't find queue\n");
}
@@ -1275,7 +1313,9 @@
MESSAGEQUEUE *queue;
if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
+ EnterCriticalSection( &queue->cSection );
queue->wPaintCount++;
+ LeaveCriticalSection( &queue->cSection );
QUEUE_SetWakeBit( queue, QS_PAINT );
QUEUE_Unlock( queue );
}
@@ -1289,8 +1329,10 @@
MESSAGEQUEUE *queue;
if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
+ EnterCriticalSection( &queue->cSection );
queue->wPaintCount--;
if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT;
+ LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue );
}
@@ -1303,7 +1345,9 @@
MESSAGEQUEUE *queue;
if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
+ EnterCriticalSection( &queue->cSection );
queue->wTimerCount++;
+ LeaveCriticalSection( &queue->cSection );
QUEUE_SetWakeBit( queue, QS_TIMER );
QUEUE_Unlock( queue );
}
@@ -1317,8 +1361,10 @@
MESSAGEQUEUE *queue;
if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return;
+ EnterCriticalSection( &queue->cSection );
queue->wTimerCount--;
if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER;
+ LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue );
}
@@ -1469,8 +1515,10 @@
DWORD ret;
if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
+ EnterCriticalSection( &queue->cSection );
ret = MAKELONG( queue->changeBits, queue->wakeBits );
queue->changeBits = 0;
+ LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue );
return ret & MAKELONG( flags, flags );
@@ -1485,8 +1533,10 @@
DWORD ret;
if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0;
+ EnterCriticalSection( &queue->cSection );
ret = MAKELONG( queue->changeBits, queue->wakeBits );
queue->changeBits = 0;
+ LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue );
return ret & MAKELONG( flags, flags );
@@ -1556,7 +1606,9 @@
if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
return FALSE;
+ EnterCriticalSection( &queue->cSection );
ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON);
+ LeaveCriticalSection( &queue->cSection );
QUEUE_Unlock( queue );
return ret;
@@ -1572,8 +1624,8 @@
/* Handle sent messages */
queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() );
- while (queue && (queue->wakeBits & QS_SENDMESSAGE))
- QUEUE_ReceiveMessage( queue );
+ while ( queue && QUEUE_ReceiveMessage( queue ) )
+ ;
QUEUE_Unlock( queue );
@@ -1586,8 +1638,8 @@
/* Handle sent messages again */
queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() );
- while (queue && (queue->wakeBits & QS_SENDMESSAGE))
- QUEUE_ReceiveMessage( queue );
+ while ( queue && QUEUE_ReceiveMessage( queue ) )
+ ;
QUEUE_Unlock( queue );
}
--
Dr. Ulrich Weigand
[EMAIL PROTECTED]