From 2c86dab53a7bf70fa3669d545911ec87d48076f7 Mon Sep 17 00:00:00 2001 From: Stephane Lussier Date: Thu, 18 Feb 1999 17:34:09 +0000 Subject: [PATCH] - New implementation of SendMessage, ReceiveMessage, ReplyMessage functions to support thread-safeness, and nested SendMessage. - Addition of ReplyMessage32. --- include/queue.h | 69 +++++--- relay32/user32.spec | 2 +- windows/message.c | 195 ++++++++++++++--------- windows/queue.c | 378 +++++++++++++++++++++++++++++++------------- windows/user.c | 1 - 5 files changed, 439 insertions(+), 206 deletions(-) diff --git a/include/queue.h b/include/queue.h index 8a9836baba..3ad74a9d08 100644 --- a/include/queue.h +++ b/include/queue.h @@ -22,11 +22,43 @@ typedef struct tagQMSG struct tagQMSG *prevMsg; } QMSG; -typedef struct + +typedef struct tagSMSG { - LRESULT lResult; - BOOL16 bPending; -} QSMCTRL; + struct tagSMSG *nextProcessing; /* next SMSG in the processing list */ + struct tagSMSG *nextPending; /* next SMSG in the pending list */ + struct tagSMSG *nextWaiting; /* next SMSG in the waiting list */ + + HQUEUE16 hSrcQueue; /* sending Queue, (NULL if it didn't wait) */ + HQUEUE16 hDstQueue; /* destination Queue */ + + HWND32 hWnd; /* destinantion window */ + UINT32 msg; /* message sent */ + WPARAM32 wParam; /* wParam of the sent message */ + LPARAM lParam; /* lParam of the sent message */ + + LRESULT lResult; /* result of SendMessage */ + WORD flags; /* see below SMSG_XXXX */ +} SMSG; + + +/* SMSG -> flags values */ +/* set when lResult contains a good value */ +#define SMSG_HAVE_RESULT 0x0001 +/* protection for multiple call to ReplyMessage16() */ +#define SMSG_ALREADY_REPLIED 0x0002 +/* use with EARLY_REPLY for forcing the receiver to clean SMSG */ +#define SMSG_RECEIVER_CLEANS 0x0010 +/* used with EARLY_REPLY to indicate to sender, receiver is done with SMSG */ +#define SMSG_RECEIVED 0x0020 +/* set in ReceiveMessage() to indicate it's not an early reply */ +#define SMSG_SENDING_REPLY 0x0040 +/* set when ReplyMessage16() is called by the application */ +#define SMSG_EARLY_REPLY 0x0080 +/* set when sender is Win32 thread */ +#define SMSG_WIN32 0x1000 +/* set when sender is a unnicode thread */ +#define SMSG_UNICODE 0x2000 /* Per-queue data for the message queue * Note that we currently only store the current values for @@ -55,8 +87,6 @@ typedef struct tagMESSAGEQUEUE DWORD magic; /* magic number should be QUEUE_MAGIC */ DWORD lockCount; /* reference counter */ - - WORD flags; /* Queue flags */ WORD wWinVersion; /* Expected Windows version */ WORD msgCount; /* Number of waiting messages */ @@ -76,19 +106,9 @@ typedef struct tagMESSAGEQUEUE DWORD GetMessagePosVal; /* Value for GetMessagePos */ DWORD GetMessageExtraInfoVal; /* Value for GetMessageExtraInfo */ - HQUEUE16 InSendMessageHandle; /* Queue of task that sent a message */ - HTASK16 hSendingTask; /* Handle of task that sent a message */ - HTASK16 hPrevSendingTask; /* Handle of previous sender */ - - HWND32 hWnd32; /* Send message arguments */ - UINT32 msg32; - WPARAM32 wParam32; - LPARAM lParam; - DWORD SendMessageReturn; /* Return value for SendMessage */ - - QSMCTRL* smResultInit; /* SendMesage result pointers */ - QSMCTRL* smResultCurrent; - QSMCTRL* smResult; + SMSG* smWaiting; /* SendMessage waiting for reply */ + SMSG* smProcessing; /* SendMessage currently being processed */ + SMSG* smPending; /* SendMessage waiting to be received */ HANDLE16 hCurHook; /* Current hook */ HANDLE16 hooks[WH_NB_HOOKS]; /* Task hooks list */ @@ -100,11 +120,11 @@ typedef struct tagMESSAGEQUEUE /* Extra (undocumented) queue wake bits - see "Undoc. Windows" */ #define QS_SMRESULT 0x8000 /* Queue has a SendMessage() result */ -#define QS_SMPARAMSFREE 0x4000 /* SendMessage() parameters are available */ -/* Queue flags */ -#define QUEUE_SM_WIN32 0x0002 /* Currently sent message is Win32 */ -#define QUEUE_SM_UNICODE 0x0004 /* Currently sent message is Unicode */ +/* Types of SMSG stack */ +#define SM_PROCESSING_LIST 1 /* list of SM currently being processed */ +#define SM_PENDING_LIST 2 /* list of SM wating to be received */ +#define SM_WAITING_LIST 3 /* list of SM waiting for reply */ #define QUEUE_MAGIC 0xD46E80AF @@ -144,7 +164,8 @@ extern BOOL32 QUEUE_AddMsg( HQUEUE16 hQueue, MSG32 * msg, DWORD extraInfo ); extern QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND32 hwnd, int first, int last ); extern void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg ); -extern void QUEUE_FlushMessages(HQUEUE16); +extern SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg ); +extern BOOL32 QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg ); extern void hardware_event( WORD message, WORD wParam, LONG lParam, int xPos, int yPos, DWORD time, DWORD extraInfo ); diff --git a/relay32/user32.spec b/relay32/user32.spec index 942f100a08..e404195ccf 100644 --- a/relay32/user32.spec +++ b/relay32/user32.spec @@ -445,7 +445,7 @@ init MAIN_UserInit 441 stdcall RemoveMenu(long long long) RemoveMenu32 442 stdcall RemovePropA(long str) RemoveProp32A 443 stdcall RemovePropW(long wstr) RemoveProp32W -444 stub ReplyMessage +444 stdcall ReplyMessage(long) ReplyMessage32 445 stub ResetDisplay 446 stdcall ReuseDDElParam(long long long long long) ReuseDDElParam 447 stdcall ScreenToClient(long ptr) ScreenToClient32 diff --git a/windows/message.c b/windows/message.c index 1723efd995..b0f4ab933b 100644 --- a/windows/message.c +++ b/windows/message.c @@ -43,7 +43,7 @@ extern HQUEUE16 hCursorQueue; /* queue.c */ DWORD MSG_WineStartTicks; /* Ticks at Wine startup */ static UINT32 doubleClickSpeed = 452; -static INT32 debugSMRL = 0; /* intertask SendMessage() recursion level */ + /*********************************************************************** * MSG_CheckFilter @@ -621,16 +621,20 @@ UINT32 WINAPI GetDoubleClickTime32(void) * * Implementation of an inter-task SendMessage. */ -static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg, +static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam, WORD flags ) { - INT32 prevSMRL = debugSMRL; - QSMCTRL qCtrl = { 0, 1}; MESSAGEQUEUE *queue, *destQ; + SMSG *smsg; + LRESULT lResult = 0; if (IsTaskLocked() || !IsWindow32(hwnd)) return 0; + /* create a SMSG structure to hold SendMessage() parameters */ + if (! (smsg = (SMSG *) HeapAlloc( SystemHeap, 0, sizeof(SMSG) )) ) + return 0; + if (!(queue = (MESSAGEQUEUE*)QUEUE_Lock( GetFastQueue() ))) return 0; if (!(destQ = (MESSAGEQUEUE*)QUEUE_Lock( hDestQueue ))) @@ -639,66 +643,84 @@ static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg, return 0; } - debugSMRL+=4; - TRACE(sendmsg,"%*sSM: %s [%04x] (%04x -> %04x)\n", - prevSMRL, "", SPY_GetMsgName(msg), msg, queue->self, hDestQueue ); - - if( !(queue->wakeBits & QS_SMPARAMSFREE) ) - { - TRACE(sendmsg,"\tIntertask SendMessage: sleeping since unreplied SendMessage pending\n"); - QUEUE_WaitBits( QS_SMPARAMSFREE ); - } - - /* resume sending */ - queue->hWnd32 = hwnd; - queue->msg32 = msg; - queue->wParam32 = wParam; - queue->lParam = lParam; - queue->hPrevSendingTask = destQ->hSendingTask; - destQ->hSendingTask = GetFastQueue(); + TRACE(sendmsg,"SM: %s [%04x] (%04x -> %04x)\n", + SPY_GetMsgName(msg), msg, queue->self, hDestQueue ); - QUEUE_ClearWakeBit( queue, QS_SMPARAMSFREE ); - queue->flags = (queue->flags & ~(QUEUE_SM_WIN32|QUEUE_SM_UNICODE)) | flags; - - TRACE(sendmsg,"%*ssm: smResultInit = %08x\n", prevSMRL, "", (unsigned)&qCtrl); + /* fill up SMSG structure */ + smsg->hWnd = hwnd; + smsg->msg = msg; + smsg->wParam = wParam; + smsg->lParam = lParam; + + smsg->lResult = 0; + smsg->hSrcQueue = GetFastQueue(); + smsg->hDstQueue = hDestQueue; + smsg->flags = flags; - queue->smResultInit = &qCtrl; + /* add smsg struct in the processing SM list of the source queue */ + QUEUE_AddSMSG(queue, SM_PROCESSING_LIST, smsg); - QUEUE_SetWakeBit( destQ, QS_SENDMESSAGE ); + /* add smsg struct in the pending list of the destination queue */ + if (QUEUE_AddSMSG(destQ, SM_PENDING_LIST, smsg) == FALSE) + return 0; /* perform task switch and wait for the result */ - - while( qCtrl.bPending ) + while( (smsg->flags & SMSG_HAVE_RESULT) == 0 ) { - if (!(queue->wakeBits & QS_SMRESULT)) - { - if (THREAD_IsWin16( THREAD_Current() )) + /* force destination task to run next, if 16 bit threads */ + if (THREAD_IsWin16(THREAD_Current()) && THREAD_IsWin16(destQ->thdb) ) DirectedYield( destQ->thdb->teb.htask16 ); - QUEUE_WaitBits( QS_SMRESULT ); - TRACE(sendmsg,"\tsm: have result!\n"); - } - /* got something */ - TRACE(sendmsg,"%*ssm: smResult = %08x\n", prevSMRL, "", (unsigned)queue->smResult ); + QUEUE_WaitBits( QS_SMRESULT ); - if (queue->smResult) { /* FIXME, smResult should always be set */ - queue->smResult->lResult = queue->SendMessageReturn; - queue->smResult->bPending = FALSE; + if (! (smsg->flags & SMSG_HAVE_RESULT) ) + { + /* not supposed to happen */ + ERR(sendmsg, "SMSG_HAVE_RESULT not set smsg->flags=%x\n", smsg->flags); } + else + { + lResult = smsg->lResult; + TRACE(sendmsg,"smResult = %08x\n", (unsigned)lResult ); + } + QUEUE_ClearWakeBit( queue, QS_SMRESULT ); + } + + /* remove the smsg from the processingg list of the source queue */ + QUEUE_RemoveSMSG( queue, SM_PROCESSING_LIST, smsg ); - if( queue->smResult != &qCtrl ) - ERR(sendmsg, "%*ssm: weird scenes inside the goldmine!\n", prevSMRL, ""); + /* Note: the destination thread is in charge of removing the smsg from + the pending list */ + + /* sender thread is in charge of releasing smsg if it's not an + early reply */ + if ( !(smsg->flags & SMSG_EARLY_REPLY) ) + { + HeapFree(SystemHeap, 0, smsg); } - queue->smResultInit = NULL; + else + { + /* In the case of an early reply, sender thread will released the + smsg structure if the receiver thread is done (SMSG_RECEIVED set). + If the receiver thread isn't done, SMSG_RECEIVER_CLEANS_UP flag + is set, and it will be the receiver responsability to released + smsg */ + EnterCriticalSection( &queue->cSection ); - TRACE(sendmsg,"%*sSM: [%04x] returning %08lx\n", prevSMRL, "", msg, qCtrl.lResult); - debugSMRL-=4; + if (smsg->flags & SMSG_RECEIVED) + HeapFree(SystemHeap, 0, smsg); + else + smsg->flags |= SMSG_RECEIVER_CLEANS; + + LeaveCriticalSection( &queue->cSection ); + } QUEUE_Unlock( queue ); QUEUE_Unlock( destQ ); - return qCtrl.lResult; + TRACE(sendmsg,"done!\n"); + return lResult; } @@ -707,52 +729,81 @@ static LRESULT MSG_SendMessage( HQUEUE16 hDestQueue, HWND16 hwnd, UINT16 msg, */ void WINAPI ReplyMessage16( LRESULT result ) { - MESSAGEQUEUE *senderQ; - MESSAGEQUEUE *queue; + ReplyMessage32( result ); +} - if (!(queue = (MESSAGEQUEUE*)QUEUE_Lock( GetFastQueue() ))) return; +/*********************************************************************** + * ReplyMessage (USER.115) + */ +BOOL32 WINAPI ReplyMessage32( LRESULT result ) +{ + MESSAGEQUEUE *senderQ = 0; + MESSAGEQUEUE *queue = 0; + SMSG *smsg; + BOOL32 ret = FALSE; - TRACE(msg,"ReplyMessage, queue %04x\n", queue->self); + if (!(queue = (MESSAGEQUEUE*)QUEUE_Lock( GetFastQueue() ))) return FALSE; - while( (senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->InSendMessageHandle))) + TRACE(sendmsg,"ReplyMessage, queue %04x\n", queue->self); + + while ((smsg = queue->smWaiting) != 0) { - TRACE(msg,"\trpm: replying to %08x (%04x -> %04x)\n", - queue->msg32, queue->self, senderQ->self); + /* if message has already been reply, continue the loop of receving + message */ + if ( smsg->flags & SMSG_ALREADY_REPLIED ) + goto ReplyMessageDone; + + senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue ); + if ( !senderQ ) + goto ReplyMessageDone; + /* if send message pending, processed it */ if( queue->wakeBits & QS_SENDMESSAGE ) { + /* Note: QUEUE_ReceiveMessage() and ReplyMessage call each other */ QUEUE_ReceiveMessage( queue ); QUEUE_Unlock( senderQ ); continue; /* ReceiveMessage() already called us */ } + break; /* message to reply is in smsg */ + } - if(!(senderQ->wakeBits & QS_SMRESULT) ) break; - if (THREAD_IsWin16(THREAD_Current())) OldYield(); + if ( !smsg ) + goto ReplyMessageDone; - QUEUE_Unlock( senderQ ); - } - if( !senderQ ) - { - TRACE(msg,"\trpm: done\n"); - QUEUE_Unlock( queue ); - return; - } + smsg->lResult = result; + smsg->flags |= SMSG_ALREADY_REPLIED | SMSG_HAVE_RESULT; + + /* check if it's an early reply (called by the application) or + a regular reply (called by ReceiveMessage) */ + if ( !(smsg->flags & SMSG_SENDING_REPLY) ) + smsg->flags |= SMSG_EARLY_REPLY; - senderQ->SendMessageReturn = result; - TRACE(msg,"\trpm: smResult = %08x, result = %08lx\n", - (unsigned)queue->smResultCurrent, result ); + TRACE( sendmsg,"\trpm: smResult = %08lx\n", (long) result ); - senderQ->smResult = queue->smResultCurrent; - queue->InSendMessageHandle = 0; + /* remove smsg from the waiting list, if it's not an early reply */ + /* it is important to leave it in the waiting list if it's an early + reply, to be protected aginst multiple call to ReplyMessage() */ + if ( !(smsg->flags & SMSG_EARLY_REPLY) ) + QUEUE_RemoveSMSG( queue, SM_WAITING_LIST, smsg ); + /* tell the sending task that its reply is ready */ QUEUE_SetWakeBit( senderQ, QS_SMRESULT ); + + /* switch directly to sending task (16 bit thread only) */ if (THREAD_IsWin16( THREAD_Current() )) DirectedYield( senderQ->thdb->teb.htask16 ); + ret = TRUE; + +ReplyMessageDone: + if ( senderQ ) QUEUE_Unlock( senderQ ); + if ( queue ) QUEUE_Unlock( queue ); -} + return ret; +} /*********************************************************************** * MSG_PeekMessage @@ -1454,7 +1505,7 @@ LRESULT WINAPI SendMessage32A( HWND32 hwnd, UINT32 msg, WPARAM32 wParam, if (wndPtr->hmemTaskQ != GetFastQueue()) ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam, - QUEUE_SM_WIN32 ); + SMSG_WIN32 ); else ret = CallWindowProc32A( (WNDPROC32)wndPtr->winproc, hwnd, msg, wParam, lParam ); @@ -1525,7 +1576,7 @@ LRESULT WINAPI SendMessage32W( if (wndPtr->hmemTaskQ != GetFastQueue()) ret = MSG_SendMessage( wndPtr->hmemTaskQ, hwnd, msg, wParam, lParam, - QUEUE_SM_WIN32 | QUEUE_SM_UNICODE ); + SMSG_WIN32 | SMSG_UNICODE ); else ret = CallWindowProc32W( (WNDPROC32)wndPtr->winproc, hwnd, msg, wParam, lParam ); @@ -2115,7 +2166,7 @@ BOOL32 WINAPI InSendMessage32(void) if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue() ))) return 0; - ret = (BOOL32)queue->InSendMessageHandle; + ret = (BOOL32)queue->smProcessing; QUEUE_Unlock( queue ); return ret; diff --git a/windows/queue.c b/windows/queue.c index 0a33aa0481..d3f30f3449 100644 --- a/windows/queue.c +++ b/windows/queue.c @@ -19,6 +19,7 @@ #include "process.h" #include #include "debug.h" +#include "spy.h" #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */ @@ -359,23 +360,21 @@ void QUEUE_DumpQueue( HQUEUE16 hQueue ) DUMP( "next: %12.4x Intertask SendMessage:\n" "thread: %10p ----------------------\n" - "hWnd: %12.8x\n" - "firstMsg: %8p msg: %11.8x\n" - "lastMsg: %8p wParam: %10.8x\n" - "msgCount: %8.4x lParam: %10.8x\n" - "lockCount: %7.4x lRet: %12.8x\n" - "wWinVer: %9.4x ISMH: %10.4x\n" - "paints: %10.4x hSendTask: %5.4x\n" - "timers: %10.4x hPrevSend: %5.4x\n" + "firstMsg: %8p smWaiting: %10p\n" + "lastMsg: %8p smPending: %10p\n" + "msgCount: %8.4x smProcessing: %10p\n" + "lockCount: %7.4x\n" + "wWinVer: %9.4x\n" + "paints: %10.4x\n" + "timers: %10.4x\n" "wakeBits: %8.4x\n" "wakeMask: %8.4x\n" "hCurHook: %8.4x\n", - pq->next, pq->thdb, pq->hWnd32, pq->firstMsg, pq->msg32, - pq->lastMsg, pq->wParam32, pq->msgCount, (unsigned)pq->lParam, - (unsigned)pq->lockCount, (unsigned)pq->SendMessageReturn, - pq->wWinVersion, pq->InSendMessageHandle, - pq->wPaintCount, pq->hSendingTask, pq->wTimerCount, - pq->hPrevSendingTask, pq->wakeBits, pq->wakeMask, pq->hCurHook); + pq->next, pq->thdb, pq->firstMsg, pq->smWaiting, pq->lastMsg, + pq->smPending, pq->msgCount, pq->smProcessing, + (unsigned)pq->lockCount, pq->wWinVersion, + pq->wPaintCount, pq->wTimerCount, + pq->wakeBits, pq->wakeMask, pq->hCurHook); QUEUE_Unlock( pq ); } @@ -449,7 +448,7 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData ) return 0; msgQueue->self = hQueue; - msgQueue->wakeBits = msgQueue->changeBits = QS_SMPARAMSFREE; + msgQueue->wakeBits = msgQueue->changeBits = 0; msgQueue->wWinVersion = pTask ? pTask->version : 0; InitializeCriticalSection( &msgQueue->cSection ); @@ -481,6 +480,44 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData ) } +/*********************************************************************** + * QUEUE_FlushMessage + * + * Try to reply to all pending sent messages on exit. + */ +void QUEUE_FlushMessages( MESSAGEQUEUE *queue ) +{ + SMSG *smsg; + MESSAGEQUEUE *senderQ = 0; + + if( queue ) + { + EnterCriticalSection( &queue->cSection ); + + /* empty the list of pending SendMessage waiting to be received */ + while (queue->smPending) + { + smsg = QUEUE_RemoveSMSG( queue, SM_PENDING_LIST, 0); + + senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue ); + if ( !senderQ ) + continue; + + /* return 0, to unblock other thread */ + smsg->lResult = 0; + smsg->flags |= SMSG_HAVE_RESULT; + QUEUE_SetWakeBit( senderQ, QS_SMRESULT); + + QUEUE_Unlock( senderQ ); + } + + QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE ); + + LeaveCriticalSection( &queue->cSection ); + } +} + + /*********************************************************************** * QUEUE_DeleteMsgQueue * @@ -492,7 +529,6 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData ) BOOL32 QUEUE_DeleteMsgQueue( HQUEUE16 hQueue ) { MESSAGEQUEUE * msgQueue = (MESSAGEQUEUE*)QUEUE_Lock(hQueue); - HQUEUE16 senderQ; HQUEUE16 *pPrev; TRACE(msg,"(): Deleting message queue %04x\n", hQueue); @@ -509,16 +545,7 @@ BOOL32 QUEUE_DeleteMsgQueue( HQUEUE16 hQueue ) if( hActiveQueue == hQueue ) hActiveQueue = 0; /* flush sent messages */ - senderQ = msgQueue->hSendingTask; - while( senderQ ) - { - MESSAGEQUEUE* sq = (MESSAGEQUEUE*)QUEUE_Lock(senderQ); - if( !sq ) break; - sq->SendMessageReturn = 0L; - QUEUE_SetWakeBit( sq, QS_SMRESULT ); - senderQ = sq->hPrevSendingTask; - QUEUE_Unlock(sq); - } + QUEUE_FlushMessages( msgQueue ); SYSTEM_LOCK(); @@ -687,130 +714,265 @@ void QUEUE_WaitBits( WORD bits ) /*********************************************************************** - * QUEUE_ReceiveMessage + * QUEUE_AddSMSG * - * This routine is called when a sent message is waiting for the queue. + * This routine is called when a SMSG need to be added to one of the three + * SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST) */ -void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue ) +BOOL32 QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg ) { - MESSAGEQUEUE *senderQ = NULL; - HQUEUE16 prevSender = 0; - QSMCTRL* prevCtrlPtr = NULL; - LRESULT result = 0; - - TRACE(msg, "ReceiveMessage, queue %04x\n", queue->self ); - if (!(queue->wakeBits & QS_SENDMESSAGE) || - !(senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask))) - { TRACE(msg,"\trcm: nothing to do\n"); return; } - - if( !senderQ->hPrevSendingTask ) - QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE ); /* no more sent messages */ + TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list, + smsg, SPY_GetMsgName(smsg->msg)); + + switch (list) + { + case SM_PROCESSING_LIST: + /* don't need to be thread safe, only accessed by the + thread associated with the sender queue */ + smsg->nextProcessing = queue->smProcessing; + queue->smProcessing = smsg; + break; + + case SM_WAITING_LIST: + /* don't need to be thread safe, only accessed by the + thread associated with the receiver queue */ + smsg->nextWaiting = queue->smWaiting; + queue->smWaiting = smsg; + break; + + case SM_PENDING_LIST: + /* make it thread safe, could be accessed by the sender and + receiver thread */ + + EnterCriticalSection( &queue->cSection ); + smsg->nextPending = queue->smPending; + queue->smPending = smsg; + QUEUE_SetWakeBit( queue, QS_SENDMESSAGE ); + LeaveCriticalSection( &queue->cSection ); + break; - /* Save current state on stack */ - prevSender = queue->InSendMessageHandle; - prevCtrlPtr = queue->smResultCurrent; + default: + WARN(sendmsg, "Invalid list: %d", list); + break; + } - /* Remove sending queue from the list */ - queue->InSendMessageHandle = queue->hSendingTask; - queue->smResultCurrent = senderQ->smResultInit; - queue->hSendingTask = senderQ->hPrevSendingTask; + return TRUE; +} - TRACE(msg, "\trcm: smResultCurrent = %08x, prevCtrl = %08x\n", - (unsigned)queue->smResultCurrent, (unsigned)prevCtrlPtr ); - QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE ); - TRACE(msg, "\trcm: calling wndproc - %08x %08x %08x %08x\n", - senderQ->hWnd32, senderQ->msg32, - senderQ->wParam32, (unsigned)senderQ->lParam ); +/*********************************************************************** + * QUEUE_RemoveSMSG + * + * This routine is called when a SMSG need to be remove from one of the three + * SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST) + * If smsg == 0, remove the first smsg from the specified list + */ +SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg ) +{ - if (IsWindow32( senderQ->hWnd32 )) + switch (list) { - WND *wndPtr = WIN_FindWndPtr( senderQ->hWnd32 ); - DWORD extraInfo = queue->GetMessageExtraInfoVal; - queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal; - - if (senderQ->flags & QUEUE_SM_WIN32) + case SM_PROCESSING_LIST: + /* don't need to be thread safe, only accessed by the + thread associated with the sender queue */ + + /* if smsg is equal to null, it means the first in the list */ + if (!smsg) + smsg = queue->smProcessing; + + TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list, + smsg, SPY_GetMsgName(smsg->msg)); + /* In fact SM_PROCESSING_LIST is a stack, and smsg + should be always at the top of the list */ + if ( (smsg != queue->smProcessing) || !queue->smProcessing ) { - TRACE(msg, "\trcm: msg is Win32\n" ); - if (senderQ->flags & QUEUE_SM_UNICODE) - result = CallWindowProc32W( wndPtr->winproc, - senderQ->hWnd32, senderQ->msg32, - senderQ->wParam32, senderQ->lParam ); + ERR( sendmsg, "smsg not at the top of Processing list, smsg=0x%p queue=0x%p", smsg, queue); + return 0; + } else - result = CallWindowProc32A( wndPtr->winproc, - senderQ->hWnd32, senderQ->msg32, - senderQ->wParam32, senderQ->lParam ); + { + queue->smProcessing = smsg->nextProcessing; + smsg->nextProcessing = 0; } - else /* Win16 message */ - result = CallWindowProc16( (WNDPROC16)wndPtr->winproc, - (HWND16) senderQ->hWnd32, - (UINT16) senderQ->msg32, - LOWORD (senderQ->wParam32), - senderQ->lParam ); + return smsg; - queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */ - TRACE(msg,"\trcm: result = %08x\n", (unsigned)result ); + case SM_WAITING_LIST: + /* don't need to be thread safe, only accessed by the + thread associated with the receiver queue */ + + /* if smsg is equal to null, it means the first in the list */ + if (!smsg) + smsg = queue->smWaiting; + + TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list, + smsg, SPY_GetMsgName(smsg->msg)); + /* In fact SM_WAITING_LIST is a stack, and smsg + should be always at the top of the list */ + if ( (smsg != queue->smWaiting) || !queue->smWaiting ) + { + ERR( sendmsg, "smsg not at the top of Waiting list, smsg=0x%p queue=0x%p", smsg, queue); + return 0; + } + else + { + queue->smWaiting = smsg->nextWaiting; + smsg->nextWaiting = 0; } - else WARN(msg, "\trcm: bad hWnd\n"); + return smsg; - QUEUE_Unlock( senderQ ); + case SM_PENDING_LIST: + /* make it thread safe, could be accessed by the sender and + receiver thread */ + EnterCriticalSection( &queue->cSection ); - /* Return the result to the sender task */ - ReplyMessage16( result ); + if (!smsg || !queue->smPending) + smsg = queue->smPending; + else + { + ERR( sendmsg, "should always remove the top one in Pending list, smsg=0x%p queue=0x%p", smsg, queue); + return 0; + } + + TRACE(sendmsg,"queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list, + smsg, SPY_GetMsgName(smsg->msg)); - queue->InSendMessageHandle = prevSender; - queue->smResultCurrent = prevCtrlPtr; + queue->smPending = smsg->nextPending; + smsg->nextPending = 0; - TRACE(msg,"done!\n"); + /* if no more SMSG in Pending list, clear QS_SENDMESSAGE flag */ + if (!queue->smPending) + QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE ); + + LeaveCriticalSection( &queue->cSection ); + return smsg; + + default: + WARN(sendmsg, "Invalid list: %d", list); + break; + } + + return 0; } + /*********************************************************************** - * QUEUE_FlushMessage + * QUEUE_ReceiveMessage * - * Try to reply to all pending sent messages on exit. + * This routine is called when a sent message is waiting for the queue. */ -void QUEUE_FlushMessages( HQUEUE16 hQueue ) +void QUEUE_ReceiveMessage( MESSAGEQUEUE *queue ) { - MESSAGEQUEUE *queue = (MESSAGEQUEUE*)QUEUE_Lock( hQueue ); + LRESULT result = 0; + SMSG *smsg; + MESSAGEQUEUE *senderQ; + + TRACE(sendmsg, "queue %04x\n", queue->self ); + + if ( !(queue->wakeBits & QS_SENDMESSAGE) && queue->smPending ) + { + TRACE(sendmsg,"\trcm: nothing to do\n"); + return; + } + + /* remove smsg on the top of the pending list and put it in the processing list */ + smsg = QUEUE_RemoveSMSG(queue, SM_PENDING_LIST, 0); + QUEUE_AddSMSG(queue, SM_WAITING_LIST, smsg); - if( queue ) + TRACE(sendmsg,"RM: %s [%04x] (%04x -> %04x)\n", + SPY_GetMsgName(smsg->msg), smsg->msg, smsg->hSrcQueue, smsg->hDstQueue ); + + if (IsWindow32( smsg->hWnd )) + { + WND *wndPtr = WIN_FindWndPtr( smsg->hWnd ); + DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */ + + /* use sender queue extra info value while calling the window proc */ + senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue ); + if (senderQ) { - MESSAGEQUEUE *senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask ); - QSMCTRL* CtrlPtr = queue->smResultCurrent; + queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal; + QUEUE_Unlock( senderQ ); + } - TRACE(msg,"Flushing queue %04x:\n", hQueue ); + /* call the right version of CallWindowProcXX */ + if (smsg->flags & SMSG_WIN32) + { + TRACE(sendmsg, "\trcm: msg is Win32\n" ); + if (smsg->flags & SMSG_UNICODE) + result = CallWindowProc32W( wndPtr->winproc, + smsg->hWnd, smsg->msg, + smsg->wParam, smsg->lParam ); + else + result = CallWindowProc32A( wndPtr->winproc, + smsg->hWnd, smsg->msg, + smsg->wParam, smsg->lParam ); + } + else /* Win16 message */ + result = CallWindowProc16( (WNDPROC16)wndPtr->winproc, + (HWND16) smsg->hWnd, + (UINT16) smsg->msg, + LOWORD (smsg->wParam), + smsg->lParam ); - while( senderQ ) + queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */ + TRACE(sendmsg,"result = %08x\n", (unsigned)result ); + } + else WARN(sendmsg, "\trcm: bad hWnd\n"); + + /* sometimes when we got early reply, the receiver is in charge of + freeing up memory associated with smsg */ + /* when there is an early reply the sender will not release smsg + before SMSG_RECEIVED is set */ + if ( smsg->flags & SMSG_EARLY_REPLY ) { - if( !CtrlPtr ) - CtrlPtr = senderQ->smResultInit; + /* remove smsg from the waiting list */ + QUEUE_RemoveSMSG( queue, SM_WAITING_LIST, smsg ); - TRACE(msg,"\tfrom queue %04x, smResult %08x\n", queue->hSendingTask, (unsigned)CtrlPtr ); + /* make thread safe when accessing SMSG_SENT_REPLY and + SMSG_RECEIVER_CLEANS_UP. Those fleags are used by both thread, + the sender and receiver, to find out which thread should released + smsg structure. The critical section of the sender queue is used. */ - if( !(queue->hSendingTask = senderQ->hPrevSendingTask) ) - QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE ); + senderQ = (MESSAGEQUEUE*)QUEUE_Lock( smsg->hSrcQueue ); - QUEUE_SetWakeBit( senderQ, QS_SMPARAMSFREE ); + /* synchronize with the sender */ + if (senderQ) + EnterCriticalSection( &senderQ->cSection ); - queue->smResultCurrent = CtrlPtr; - while( senderQ->wakeBits & QS_SMRESULT ) OldYield(); + /* tell the sender we're all done with smsg structure */ + smsg->flags |= SMSG_RECEIVED; - senderQ->SendMessageReturn = 0; - senderQ->smResult = queue->smResultCurrent; - QUEUE_SetWakeBit( senderQ, QS_SMRESULT); + /* sender will set SMSG_RECEIVER_CLEANS_UP if it wants the + receiver to clean up smsg, it could only happens when there is + an early reply */ + if ( smsg->flags & SMSG_RECEIVER_CLEANS ) + { + TRACE( sendmsg,"Receiver cleans up!\n" ); + HeapFree( SystemHeap, 0, smsg ); + } + /* release lock */ + if (senderQ) + { + LeaveCriticalSection( &senderQ->cSection ); QUEUE_Unlock( senderQ ); - - senderQ = (MESSAGEQUEUE*)QUEUE_Lock( queue->hSendingTask ); - CtrlPtr = NULL; + } } - queue->InSendMessageHandle = 0; + else + { + /* no early reply, so do it now */ - QUEUE_Unlock( queue ); + /* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not + an early reply */ + smsg->flags |= SMSG_SENDING_REPLY; + ReplyMessage32( result ); } + TRACE( sendmsg,"done! \n" ); } + + /*********************************************************************** * QUEUE_AddMsg * diff --git a/windows/user.c b/windows/user.c index 5513dca079..2e3571202c 100644 --- a/windows/user.c +++ b/windows/user.c @@ -173,7 +173,6 @@ void USER_QueueCleanup( HQUEUE16 hQueue ) TIMER_RemoveQueueTimers( hQueue ); - QUEUE_FlushMessages( hQueue ); HOOK_FreeQueueHooks( hQueue ); QUEUE_SetExitingQueue( hQueue ); -- 2.32.0.93.g670b81a890