[Win32SS]
authorJames Tabor <james.tabor@reactos.org>
Tue, 3 Nov 2015 15:18:51 +0000 (15:18 +0000)
committerJames Tabor <james.tabor@reactos.org>
Tue, 3 Nov 2015 15:18:51 +0000 (15:18 +0000)
- Simplify and restructure thread send messages, use look aside list, message signals and global message link for sorting trouble messages.
- See CORE-9210 for more information. Related to and fixed CORE-9718 and CORE-9975. Could have fixed CORE-9695.

svn path=/trunk/; revision=69793

reactos/win32ss/user/ntuser/callback.c
reactos/win32ss/user/ntuser/focus.c
reactos/win32ss/user/ntuser/main.c
reactos/win32ss/user/ntuser/message.c
reactos/win32ss/user/ntuser/msgqueue.c
reactos/win32ss/user/ntuser/msgqueue.h
reactos/win32ss/user/ntuser/win32.h

index e1d6024..e233c07 100644 (file)
@@ -51,13 +51,19 @@ IntCbFreeMemory(PVOID Data)
    PINT_CALLBACK_HEADER Mem;
    PTHREADINFO W32Thread;
 
+   W32Thread = PsGetCurrentThreadWin32Thread();
+   ASSERT(W32Thread);
+
+   if (W32Thread->TIF_flags & TIF_INCLEANUP)
+   {
+      ERR("CbFM Thread is already in cleanup\n");
+      return;
+   }
+
    ASSERT(Data);
 
    Mem = ((PINT_CALLBACK_HEADER)Data - 1);
 
-   W32Thread = PsGetCurrentThreadWin32Thread();
-   ASSERT(W32Thread);
-
    /* Remove the memory block from the thread's callback list */
    RemoveEntryList(&Mem->ListEntry);
 
@@ -340,8 +346,9 @@ co_IntCallWindowProc(WNDPROC Proc,
                                &ResultLength);
    if (!NT_SUCCESS(Status))
    {
+      ERR("Error Callback to User space Status %lx\n",Status);
       UserEnterCo();
-      return -1;
+      return 0;
    }
 
    _SEH2_TRY
index aa50dbc..fb17e3f 100644 (file)
@@ -340,7 +340,13 @@ FindRemoveAsyncMsg(PWND Wnd, WPARAM wParam)
          WARN("ASYNC SAW: Found one in the Sent Msg Queue! %p Activate/Deactivate %d\n", Message->Msg.hwnd, !!wParam);
          RemoveEntryList(&Message->ListEntry); // Purge the entry.
          ClearMsgBitsMask(pti, Message->QS_Flags);
-         ExFreePoolWithTag(Message, TAG_USRMSG);
+         InsertTailList(&usmList, &Message->ListEntry);
+         /* Notify the sender. */
+         if (Message->pkCompletionEvent != NULL)
+         {
+            KeSetEvent(Message->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
+         }
+         FreeUserMessage(Message);
       }
    }
 }
@@ -929,7 +935,7 @@ co_UserSetCapture(HWND hWnd)
    {
       if (Window->head.pti->MessageQueue != ThreadQueue)
       {
-         ERR("Window Thread dos not match Current!\n");
+         ERR("Window Thread does not match Current!\n");
          return NULL;
       }
    }
index b429b63..0da71f8 100644 (file)
@@ -488,8 +488,6 @@ InitThreadCallback(PETHREAD Thread)
     InitializeListHead(&ptiCurrent->W32CallbackListHead);
     InitializeListHead(&ptiCurrent->PostedMessagesListHead);
     InitializeListHead(&ptiCurrent->SentMessagesListHead);
-    InitializeListHead(&ptiCurrent->DispatchingMessagesHead);
-    InitializeListHead(&ptiCurrent->LocalDispatchingMessagesHead);
     InitializeListHead(&ptiCurrent->PtiLink);
     for (i = 0; i < NB_HOOKS; i++)
     {
@@ -778,6 +776,12 @@ ExitThreadCallback(PETHREAD Thread)
         }
     }
 
+    if (ptiCurrent->cEnterCount)
+    {
+       KeSetKernelStackSwapEnable(TRUE);
+       ptiCurrent->cEnterCount = 0;
+    }
+
     /* Find the THREADINFO in the PROCESSINFO's list */
     ppti = &ppiCurrent->ptiList;
     while (*ppti != NULL && *ppti != ptiCurrent)
index 2249775..523eb55 100644 (file)
@@ -1278,7 +1278,7 @@ co_IntSendMessage( HWND hWnd,
                    LPARAM lParam )
 {
     ULONG_PTR Result = 0;
-    if(co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
+    if (co_IntSendMessageTimeout(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
     {
         return (LRESULT)Result;
     }
@@ -1399,7 +1399,7 @@ co_IntSendMessageTimeoutSingle( HWND hWnd,
                                                   wParam,
                                                   lParamPacked,
                                                   lParamBufferSize );
-        if(uResult)
+        if (uResult)
         {
             *uResult = Result;
         }
@@ -1697,7 +1697,7 @@ co_IntSendMessageWithCallBack( HWND hWnd,
         RETURN(TRUE);
     }
 
-    if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+    if(!(Message = AllocateUserMessage(FALSE)))
     {
         ERR("MsqSendMessage(): Not enough memory to allocate a message");
         RETURN( FALSE);
@@ -1707,19 +1707,18 @@ co_IntSendMessageWithCallBack( HWND hWnd,
     Message->Msg.message = Msg;
     Message->Msg.wParam = wParam;
     Message->Msg.lParam = lParamPacked;
-    Message->CompletionEvent = NULL;
-    Message->Result = 0;
+    Message->pkCompletionEvent = NULL; // No event needed.
     Message->lResult = 0;
     Message->QS_Flags = 0;
     Message->ptiReceiver = ptiSendTo;
     Message->ptiSender = NULL; // mjmartin, you are right! This is null.
     Message->ptiCallBackSender = Win32Thread;
-    InitializeListHead(&Message->DispatchingListEntry);
     Message->CompletionCallback = CompletionCallback;
     Message->CompletionCallbackContext = CompletionCallbackContext;
     Message->HookMessage = MSQ_NORMAL;
     Message->HasPackedLParam = (lParamBufferSize > 0);
     Message->QS_Flags = QS_SENDMESSAGE;
+    Message->flags = SMF_RECEIVERFREE;
 
     if (Msg & 0x80000000) // Higher priority event message!
        InsertHeadList(&ptiSendTo->SentMessagesListHead, &Message->ListEntry);
@@ -2723,14 +2722,15 @@ NtUserMessageCall( HWND hWnd,
         break;
     case FNID_SENDMESSAGE:
         {
-            Ret = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
+            lResult = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, 0);
+            Ret = TRUE;
 
             if (ResultInfo)
             {
                 _SEH2_TRY
                 {
                     ProbeForWrite((PVOID)ResultInfo, sizeof(ULONG_PTR), 1);
-                    RtlCopyMemory((PVOID)ResultInfo, &Ret, sizeof(ULONG_PTR));
+                    RtlCopyMemory((PVOID)ResultInfo, &lResult, sizeof(ULONG_PTR));
                 }
                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                 {
index fda7e8a..8499cf7 100644 (file)
@@ -14,10 +14,12 @@ DBG_DEFAULT_CHANNEL(UserMsgQ);
 /* GLOBALS *******************************************************************/
 
 static PPAGED_LOOKASIDE_LIST pgMessageLookasideList;
+static PPAGED_LOOKASIDE_LIST pgSendMsgLookasideList;
+INT SendMsgCount = 0;
 PUSER_MESSAGE_QUEUE gpqCursor;
 ULONG_PTR gdwMouseMoveExtraInfo = 0;
 DWORD gdwMouseMoveTimeStamp = 0;
-
+LIST_ENTRY usmList;
 
 /* FUNCTIONS *****************************************************************/
 
@@ -26,6 +28,7 @@ NTSTATUS
 NTAPI
 MsqInitializeImpl(VOID)
 {
+   // Setup Post Messages
    pgMessageLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
    if (!pgMessageLookasideList)
       return STATUS_NO_MEMORY;
@@ -36,6 +39,19 @@ MsqInitializeImpl(VOID)
                                   sizeof(USER_MESSAGE),
                                   TAG_USRMSG,
                                   256);
+   // Setup Send Messages
+   pgSendMsgLookasideList = ExAllocatePoolWithTag(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST), TAG_USRMSG);
+   if (!pgSendMsgLookasideList)
+      return STATUS_NO_MEMORY;
+   ExInitializePagedLookasideList(pgSendMsgLookasideList,
+                                  NULL,
+                                  NULL,
+                                  0,
+                                  sizeof(USER_SENT_MESSAGE),
+                                  TAG_USRMSG,
+                                  16);
+
+   InitializeListHead(&usmList);
 
    return(STATUS_SUCCESS);
 }
@@ -743,6 +759,115 @@ MsqDestroyMessage(PUSER_MESSAGE Message)
    ExFreeToPagedLookasideList(pgMessageLookasideList, Message);
 }
 
+PUSER_SENT_MESSAGE FASTCALL
+AllocateUserMessage(BOOL KEvent)
+{
+   PUSER_SENT_MESSAGE Message;
+
+   if(!(Message = ExAllocateFromPagedLookasideList(pgSendMsgLookasideList)))
+   {
+       ERR("AllocateUserMessage(): Not enough memory to allocate a message");
+       return NULL;
+   }
+   RtlZeroMemory(Message, sizeof(USER_SENT_MESSAGE));
+
+   if (KEvent)
+   {
+      Message->pkCompletionEvent = &Message->CompletionEvent;;
+
+      KeInitializeEvent(Message->pkCompletionEvent, NotificationEvent, FALSE);
+   }
+   SendMsgCount++;
+   //ERR("AUM pti %p msg %p\n",PsGetCurrentThreadWin32Thread(),Message);
+   return Message;
+}
+
+VOID FASTCALL
+FreeUserMessage(PUSER_SENT_MESSAGE Message)
+{
+   Message->pkCompletionEvent = NULL;
+
+   /* Remove it from the list */
+   RemoveEntryList(&Message->ListEntry);
+
+   ExFreeToPagedLookasideList(pgMessageLookasideList, Message);
+   SendMsgCount--;
+}
+
+VOID APIENTRY
+MsqRemoveWindowMessagesFromQueue(PWND Window)
+{
+   PTHREADINFO pti;
+   PUSER_SENT_MESSAGE SentMessage;
+   PUSER_MESSAGE PostedMessage;
+   PLIST_ENTRY CurrentEntry, ListHead;
+
+   ASSERT(Window);
+
+   pti = Window->head.pti;
+
+   /* remove the posted messages for this window */
+   CurrentEntry = pti->PostedMessagesListHead.Flink;
+   ListHead = &pti->PostedMessagesListHead;
+   while (CurrentEntry != ListHead)
+   {
+      PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
+
+      if (PostedMessage->Msg.hwnd == Window->head.h)
+      {
+         if (PostedMessage->Msg.message == WM_QUIT && pti->QuitPosted == 0)
+         {
+            pti->QuitPosted = 1;
+            pti->exitCode = PostedMessage->Msg.wParam;
+         }
+         RemoveEntryList(&PostedMessage->ListEntry);
+         ClearMsgBitsMask(pti, PostedMessage->QS_Flags);
+         MsqDestroyMessage(PostedMessage);
+         CurrentEntry = pti->PostedMessagesListHead.Flink;
+      }
+      else
+      {
+         CurrentEntry = CurrentEntry->Flink;
+      }
+   }
+
+   /* remove the sent messages for this window */
+   CurrentEntry = pti->SentMessagesListHead.Flink;
+   ListHead = &pti->SentMessagesListHead;
+   while (CurrentEntry != ListHead)
+   {
+      SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
+
+      if(SentMessage->Msg.hwnd == Window->head.h)
+      {
+         TRACE("Remove Window Messages From Sent Queue\n");
+
+         ClearMsgBitsMask(pti, SentMessage->QS_Flags);
+
+         /* wake the sender's thread */
+         if (SentMessage->pkCompletionEvent != NULL)
+         {
+            KeSetEvent(SentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
+         }
+
+         if (SentMessage->HasPackedLParam)
+         {
+            if (SentMessage->Msg.lParam)
+               ExFreePool((PVOID)SentMessage->Msg.lParam);
+         }
+
+         /* free the message */
+         FreeUserMessage(SentMessage);
+
+         CurrentEntry = pti->SentMessagesListHead.Flink;
+      }
+      else
+      {
+         CurrentEntry = CurrentEntry->Flink;
+      }
+   }
+}
+
 BOOLEAN FASTCALL
 co_MsqDispatchOneSentMessage(
     _In_ PTHREADINFO pti)
@@ -763,6 +888,9 @@ co_MsqDispatchOneSentMessage(
    Entry = RemoveHeadList(&pti->SentMessagesListHead);
    Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
 
+   // Signal this message is being processed.
+   Message->flags |= SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE;
+
    SaveMsg = pti->pusmCurrent;
    pti->pusmCurrent = Message;
 
@@ -773,15 +901,14 @@ co_MsqDispatchOneSentMessage(
       pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know...
    }
 
-   /* insert it to the list of messages that are currently dispatched by this
-      message queue */
-   InsertTailList(&pti->LocalDispatchingMessagesHead, &Message->ListEntry);
+   /* Now insert it to the global list of messages that can be removed Justin Case there's Trouble */
+   InsertTailList(&usmList, &Message->ListEntry);
 
    ClearMsgBitsMask(pti, Message->QS_Flags);
 
    if (Message->HookMessage == MSQ_ISHOOK)
    {  // Direct Hook Call processor
-      Result = co_CallHook( Message->Msg.message,     // HookId
+      Result = co_CallHook( Message->Msg.message,           // HookId
                            (INT)(INT_PTR)Message->Msg.hwnd, // Code
                             Message->Msg.wParam,
                             Message->Msg.lParam);
@@ -810,7 +937,9 @@ co_MsqDispatchOneSentMessage(
          /* The message has not been processed yet, reinsert it. */
          RemoveEntryList(&Message->ListEntry);
          InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
-         TRACE("Callback Message not processed yet. Requeuing the message\n");
+         // List is occupied need to set the bit.
+         MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
+         ERR("Callback Message not processed yet. Requeuing the message\n"); //// <---- Need to see if this happens.
          Ret = FALSE;
          goto Exit;
       }
@@ -823,10 +952,6 @@ co_MsqDispatchOneSentMessage(
                                   Message->Msg.lParam);
    }
 
-   /* remove the message from the local dispatching list, because it doesn't need
-      to be cleaned up on thread termination anymore */
-   RemoveEntryList(&Message->ListEntry);
-
    /* If the message is a callback, insert it in the callback senders MessageQueue */
    if (Message->CompletionCallback)
    {
@@ -836,6 +961,7 @@ co_MsqDispatchOneSentMessage(
          Message->QS_Flags |= QS_SMRESULT;
 
          /* insert it in the callers message queue */
+         RemoveEntryList(&Message->ListEntry);
          InsertTailList(&Message->ptiCallBackSender->SentMessagesListHead, &Message->ListEntry);
          MsqWakeQueue(Message->ptiCallBackSender, QS_SENDMESSAGE, TRUE);
       }
@@ -843,29 +969,14 @@ co_MsqDispatchOneSentMessage(
       goto Exit;
    }
 
-   /* remove the message from the dispatching list if needed, so lock the sender's message queue */
-   if (Message->ptiSender && !(Message->ptiSender->TIF_flags & TIF_INCLEANUP))
-   {
-      if (!IsListEmpty(&Message->DispatchingListEntry))
-      {
-         /* only remove it from the dispatching list if not already removed by a timeout */
-         RemoveEntryList(&Message->DispatchingListEntry);
-         InitializeListHead(&Message->DispatchingListEntry);
-      }
-   }
-
-   /* still keep the sender's message queue locked, so the sender can't exit the
-      MsqSendMessage() function (if timed out) */
+   // Retrieve the result from callback.
    if (Message->QS_Flags & QS_SMRESULT)
    {
       Result = Message->lResult;
    }
 
    /* Let the sender know the result. */
-   if (Message->Result != NULL)
-   {
-      *Message->Result = Result;
-   }
+   Message->lResult = Result;
 
    if (Message->HasPackedLParam)
    {
@@ -873,14 +984,22 @@ co_MsqDispatchOneSentMessage(
          ExFreePool((PVOID)Message->Msg.lParam);
    }
 
+   // Clear busy signal.
+   Message->flags &= ~SMF_RECEIVERBUSY;
+
    /* Notify the sender. */
-   if (Message->CompletionEvent != NULL)
+   if (Message->pkCompletionEvent != NULL)
    {
-      KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
+      KeSetEvent(Message->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
    }
 
    /* free the message */
-   ExFreePoolWithTag(Message, TAG_USRMSG);
+   if (Message->flags & SMF_RECEIVERFREE)
+   {
+      TRACE("Receiver Freeing Message %p\n",Message);
+      FreeUserMessage(Message);
+   }
+
    Ret = TRUE;
 Exit:
    /* do not hangup on the user if this is reentering */
@@ -890,89 +1009,6 @@ Exit:
    return Ret;
 }
 
-VOID APIENTRY
-MsqRemoveWindowMessagesFromQueue(PWND Window)
-{
-   PTHREADINFO pti;
-   PUSER_SENT_MESSAGE SentMessage;
-   PUSER_MESSAGE PostedMessage;
-   PLIST_ENTRY CurrentEntry, ListHead;
-
-   ASSERT(Window);
-
-   pti = Window->head.pti;
-
-   /* remove the posted messages for this window */
-   CurrentEntry = pti->PostedMessagesListHead.Flink;
-   ListHead = &pti->PostedMessagesListHead;
-   while (CurrentEntry != ListHead)
-   {
-      PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
-                                        ListEntry);
-      if (PostedMessage->Msg.hwnd == Window->head.h)
-      {
-         if (PostedMessage->Msg.message == WM_QUIT && pti->QuitPosted == 0)
-         {
-            pti->QuitPosted = 1;
-            pti->exitCode = PostedMessage->Msg.wParam;
-         }
-         RemoveEntryList(&PostedMessage->ListEntry);
-         ClearMsgBitsMask(pti, PostedMessage->QS_Flags);
-         MsqDestroyMessage(PostedMessage);
-         CurrentEntry = pti->PostedMessagesListHead.Flink;
-      }
-      else
-      {
-         CurrentEntry = CurrentEntry->Flink;
-      }
-   }
-
-   /* remove the sent messages for this window */
-   CurrentEntry = pti->SentMessagesListHead.Flink;
-   ListHead = &pti->SentMessagesListHead;
-   while (CurrentEntry != ListHead)
-   {
-      SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
-
-      if(SentMessage->Msg.hwnd == Window->head.h)
-      {
-         TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
-
-         RemoveEntryList(&SentMessage->ListEntry);
-         ClearMsgBitsMask(pti, SentMessage->QS_Flags);
-
-         /* Only if the message has a sender was the queue referenced */
-         if ((SentMessage->ptiSender) &&
-             (!IsListEmpty(&SentMessage->DispatchingListEntry)))
-         {
-            RemoveEntryList(&SentMessage->DispatchingListEntry);
-            InitializeListHead(&SentMessage->DispatchingListEntry);
-         }
-
-         /* wake the sender's thread */
-         if (SentMessage->CompletionEvent != NULL)
-         {
-            KeSetEvent(SentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
-         }
-
-         if (SentMessage->HasPackedLParam)
-         {
-            if (SentMessage->Msg.lParam)
-               ExFreePool((PVOID)SentMessage->Msg.lParam);
-         }
-
-         /* free the message */
-         ExFreePoolWithTag(SentMessage, TAG_USRMSG);
-
-         CurrentEntry = pti->SentMessagesListHead.Flink;
-      }
-      else
-      {
-         CurrentEntry = CurrentEntry->Flink;
-      }
-   }
-}
-
 BOOL FASTCALL
 co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
                        HWND hwnd,
@@ -988,9 +1024,9 @@ co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
     PTHREADINFO ptiSender;
     PUSER_SENT_MESSAGE Message;
 
-    if(!(Message = ExAllocatePoolWithTag(NonPagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+    if(!(Message = AllocateUserMessage(FALSE)))
     {
-        ERR("MsqSendMessage(): Not enough memory to allocate a message");
+        ERR("MsqSendMessageAsync(): Not enough memory to allocate a message");
         return FALSE;
     }
 
@@ -1000,18 +1036,15 @@ co_MsqSendMessageAsync(PTHREADINFO ptiReceiver,
     Message->Msg.message = Msg;
     Message->Msg.wParam = wParam;
     Message->Msg.lParam = lParam;
-    Message->CompletionEvent = NULL;
-    Message->Result = 0;
-    Message->lResult = 0;
+    Message->pkCompletionEvent = NULL; // No event needed.
     Message->ptiReceiver = ptiReceiver;
-    Message->ptiSender = NULL;
     Message->ptiCallBackSender = ptiSender;
-    InitializeListHead(&Message->DispatchingListEntry);
     Message->CompletionCallback = CompletionCallback;
     Message->CompletionCallbackContext = CompletionCallbackContext;
     Message->HookMessage = HookMessage;
     Message->HasPackedLParam = HasPackedLParam;
     Message->QS_Flags = QS_SENDMESSAGE;
+    Message->flags = SMF_RECEIVERFREE;
 
     InsertTailList(&ptiReceiver->SentMessagesListHead, &Message->ListEntry);
     MsqWakeQueue(ptiReceiver, QS_SENDMESSAGE, TRUE);
@@ -1031,12 +1064,12 @@ co_MsqSendMessage(PTHREADINFO ptirec,
                   ULONG_PTR *uResult)
 {
    PTHREADINFO pti;
-   PUSER_SENT_MESSAGE Message;
-   KEVENT CompletionEvent;
+   PUSER_SENT_MESSAGE SaveMsg, Message;
    NTSTATUS WaitStatus;
    LARGE_INTEGER Timeout;
    PLIST_ENTRY Entry;
    PWND pWnd;
+   BOOLEAN SwapStateEnabled;
    LRESULT Result = 0;   //// Result could be trashed. ////
 
    pti = PsGetCurrentThreadWin32Thread();
@@ -1105,57 +1138,57 @@ co_MsqSendMessage(PTHREADINFO ptirec,
       }
    }
 
-   if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
+   if(!(Message = AllocateUserMessage(TRUE)))
    {
       ERR("MsqSendMessage(): Not enough memory to allocate a message\n");
+      if (uResult) *uResult = -1;
       return STATUS_INSUFFICIENT_RESOURCES;
    }
 
-   KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE);
-
    Timeout.QuadPart = Int32x32To64(-10000,uTimeout); // Pass SMTO test with a TO of 0x80000000.
    TRACE("Timeout val %lld\n",Timeout.QuadPart)
 
-   /* FIXME: Increase reference counter of sender's message queue here */
-
    Message->Msg.hwnd = Wnd;
    Message->Msg.message = Msg;
    Message->Msg.wParam = wParam;
    Message->Msg.lParam = lParam;
-   Message->CompletionEvent = &CompletionEvent;
-   Message->Result = &Result;
-   Message->lResult = 0;
-   Message->QS_Flags = 0;
    Message->ptiReceiver = ptirec;
    Message->ptiSender = pti;
-   Message->ptiCallBackSender = NULL;
-   Message->CompletionCallback = NULL;
-   Message->CompletionCallbackContext = 0;
    Message->HookMessage = HookMessage;
-   Message->HasPackedLParam = FALSE;
+   Message->QS_Flags = QS_SENDMESSAGE;
 
-   /* Add it to the list of pending messages */
-   InsertTailList(&pti->DispatchingMessagesHead, &Message->DispatchingListEntry);
+   SaveMsg = pti->pusmSent;
+   pti->pusmSent = Message;
 
    /* Queue it in the destination's message queue */
    InsertTailList(&ptirec->SentMessagesListHead, &Message->ListEntry);
 
-   Message->QS_Flags = QS_SENDMESSAGE;
    MsqWakeQueue(ptirec, QS_SENDMESSAGE, TRUE);
 
-   /* We can't access the Message anymore since it could have already been deleted! */
+   // First time in, turn off swapping of the stack.
+   if (pti->cEnterCount == 0)
+   {
+      SwapStateEnabled = KeSetKernelStackSwapEnable(FALSE);
+   }
+   pti->cEnterCount++;
 
    if (Block)
    {
       PVOID WaitObjects[2];
 
-      WaitObjects[0] = &CompletionEvent;       // Wait 0
-      WaitObjects[1] = ptirec->pEThread;       // Wait 1
+      WaitObjects[0] = Message->pkCompletionEvent; // Wait 0
+      WaitObjects[1] = ptirec->pEThread;           // Wait 1
 
       UserLeaveCo();
 
-      WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
-                                            UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
+      WaitStatus = KeWaitForMultipleObjects( 2,
+                                             WaitObjects,
+                                             WaitAny,
+                                             UserRequest,
+                                             UserMode,
+                                             FALSE,
+                                            (uTimeout ? &Timeout : NULL),
+                                             NULL );
 
       UserEnterCo();
 
@@ -1168,39 +1201,24 @@ co_MsqSendMessage(PTHREADINFO ptirec,
          {
             if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message)
             {
-               /* We can access Message here, it's secure because the message queue is locked
-                  and the message is still hasn't been dispatched */
-               Message->CompletionEvent = NULL;
-               Message->Result = NULL;
+               Message->pkCompletionEvent = NULL;
                RemoveEntryList(&Message->ListEntry);
-               RemoveEntryList(&Message->DispatchingListEntry);
                ClearMsgBitsMask(ptirec, Message->QS_Flags);
-               ExFreePoolWithTag(Message, TAG_USRMSG);
+               InsertTailList(&usmList, &Message->ListEntry);
                break;
             }
             Entry = Entry->Flink;
          }
 
-         TRACE("MsqSendMessage (blocked) timed out 1 Status %lx\n", WaitStatus);
+         ERR("MsqSendMessage (blocked) timed out 1 Status %lx\n", WaitStatus);
       }
       // Receiving thread passed on and left us hanging with issues still pending.
       else if (WaitStatus == STATUS_WAIT_1)
       {
          ERR("Bk Receiving Thread woken up dead!\n");
-         Entry = pti->DispatchingMessagesHead.Flink;
-         while (Entry != &pti->DispatchingMessagesHead)
-         {
-            if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry) == Message)
-            {
-               Message->CompletionEvent = NULL;
-               Message->Result = NULL;
-               RemoveEntryList(&Message->DispatchingListEntry);
-               InitializeListHead(&Message->DispatchingListEntry);
-               break;
-            }
-            Entry = Entry->Flink;
-         }
+         Message->flags |= SMF_RECEIVERDIED;
       }
+
       while (co_MsqDispatchOneSentMessage(pti))
          ;
    }
@@ -1208,16 +1226,22 @@ co_MsqSendMessage(PTHREADINFO ptirec,
    {
       PVOID WaitObjects[3];
 
-      WaitObjects[0] = &CompletionEvent;       // Wait 0
-      WaitObjects[1] = pti->pEventQueueServer; // Wait 1
-      WaitObjects[2] = ptirec->pEThread;       // Wait 2
+      WaitObjects[0] = Message->pkCompletionEvent; // Wait 0
+      WaitObjects[1] = pti->pEventQueueServer;     // Wait 1
+      WaitObjects[2] = ptirec->pEThread;           // Wait 2
 
       do
       {
          UserLeaveCo();
 
-         WaitStatus = KeWaitForMultipleObjects(3, WaitObjects, WaitAny, UserRequest,
-                                               UserMode, FALSE, (uTimeout ? &Timeout : NULL), NULL);
+         WaitStatus = KeWaitForMultipleObjects( 3,
+                                                WaitObjects,
+                                                WaitAny,
+                                                UserRequest,
+                                                UserMode,
+                                                FALSE,
+                                               (uTimeout ? &Timeout : NULL),
+                                                NULL);
 
          UserEnterCo();
 
@@ -1230,41 +1254,23 @@ co_MsqSendMessage(PTHREADINFO ptirec,
             {
                if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message)
                {
-                  /* We can access Message here, it's secure because the message queue is locked
-                     and the message is still hasn't been dispatched */
-                  Message->CompletionEvent = NULL;
-                  Message->Result = NULL;
+                  Message->pkCompletionEvent = NULL;
                   RemoveEntryList(&Message->ListEntry);
-                  RemoveEntryList(&Message->DispatchingListEntry);
-                  InitializeListHead(&Message->DispatchingListEntry);
                   ClearMsgBitsMask(ptirec, Message->QS_Flags);
-                  ExFreePoolWithTag(Message, TAG_USRMSG);
+                  InsertTailList(&usmList, &Message->ListEntry);
                   break;
                }
                Entry = Entry->Flink;
             }
 
-            TRACE("MsqSendMessage timed out 2 Status %lx\n", WaitStatus);
-
+            ERR("MsqSendMessage timed out 2 Status %lx\n", WaitStatus);
             break;
          }
          // Receiving thread passed on and left us hanging with issues still pending.
          else if (WaitStatus == STATUS_WAIT_2)
          {
             ERR("NB Receiving Thread woken up dead!\n");
-            Entry = pti->DispatchingMessagesHead.Flink;
-            while (Entry != &pti->DispatchingMessagesHead)
-            {
-               if (CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry) == Message)
-               {
-                  Message->CompletionEvent = NULL;
-                  Message->Result = NULL;
-                  RemoveEntryList(&Message->DispatchingListEntry);
-                  InitializeListHead(&Message->DispatchingListEntry);
-                  break;
-               }
-               Entry = Entry->Flink;
-            }
+            Message->flags |= SMF_RECEIVERDIED;
             break;
          }
 
@@ -1275,19 +1281,52 @@ co_MsqSendMessage(PTHREADINFO ptirec,
       } while (WaitStatus == STATUS_WAIT_1);
    }
 
+   // Count is nil, restore swapping of the stack.
+   if (--pti->cEnterCount == 0 )
+   {
+      KeSetKernelStackSwapEnable(SwapStateEnabled);
+   }
+
+   // Handle User APC
    if (WaitStatus == STATUS_USER_APC)
    {
      // The current thread is dying!
      TRACE("User APC\n");
+
+     // The Message will be on the Trouble list until Thread cleanup.
+     Message->flags |= SMF_SENDERDIED;
+
      co_IntDeliverUserAPC();
      ERR("User APC Returned\n"); // Should not see this message.
    }
 
+   // Force this thread to wake up for the next go around.
+   KeSetEvent(pti->pEventQueueServer, IO_NO_INCREMENT, FALSE);
+
+   Result = Message->lResult;
+
+   // Determine whether this message is being processed or not.
+   if ((Message->flags & (SMF_RECEIVERBUSY|SMF_RECEIVEDMESSAGE)) != SMF_RECEIVEDMESSAGE)
+   {
+      Message->flags |= SMF_RECEIVERFREE;
+   }
+
+   if (!(Message->flags & SMF_RECEIVERFREE))
+   {
+      TRACE("Sender Freeing Message %p ptirec %p bit %d list empty %d\n",Message,ptirec,!!(ptirec->pcti->fsChangeBits & QS_SENDMESSAGE),IsListEmpty(&ptirec->SentMessagesListHead));
+      // Make it to this point, the message was received.
+      FreeUserMessage(Message);
+   }
+
+   pti->pusmSent = SaveMsg;
+
+   TRACE("MSM Allocation Count %d Status %lx Result %d\n",SendMsgCount,WaitStatus,Result);
+
    if (WaitStatus != STATUS_TIMEOUT)
    {
       if (uResult)
       {
-         *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : -1);
+         *uResult = (STATUS_WAIT_0 == WaitStatus ? Result : 0);
       }
    }
 
@@ -2104,6 +2143,23 @@ MsqCleanupThreadMsgs(PTHREADINFO pti)
    PUSER_MESSAGE CurrentMessage;
    PUSER_SENT_MESSAGE CurrentSentMessage;
 
+   TRACE("MsqCleanupThreadMsgs %p\n",pti);
+
+   // Clear it all out.
+   if (pti->pcti)
+   {
+       pti->pcti->fsWakeBits = 0;
+       pti->pcti->fsChangeBits = 0;
+   }
+
+   pti->nCntsQBits[QSRosKey] = 0;
+   pti->nCntsQBits[QSRosMouseMove] = 0;
+   pti->nCntsQBits[QSRosMouseButton] = 0;
+   pti->nCntsQBits[QSRosPostMessage] = 0;
+   pti->nCntsQBits[QSRosSendMessage] = 0;
+   pti->nCntsQBits[QSRosHotKey] = 0;
+   pti->nCntsQBits[QSRosEvent] = 0;
+
    /* cleanup posted messages */
    while (!IsListEmpty(&pti->PostedMessagesListHead))
    {
@@ -2122,22 +2178,15 @@ MsqCleanupThreadMsgs(PTHREADINFO pti)
    /* remove the messages that have not yet been dispatched */
    while (!IsListEmpty(&pti->SentMessagesListHead))
    {
-      CurrentEntry = RemoveHeadList(&pti->SentMessagesListHead);
+      CurrentEntry = pti->SentMessagesListHead.Flink;
       CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
 
-      TRACE("Notify the sender and remove a message from the queue that had not been dispatched\n");
-      /* Only if the message has a sender was the message in the DispatchingList */
-      if ((CurrentSentMessage->ptiSender) &&
-          (!IsListEmpty(&CurrentSentMessage->DispatchingListEntry)))
-      {
-         RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
-         InitializeListHead(&CurrentSentMessage->DispatchingListEntry);
-      }
+      ERR("Thread Cleanup Sent Messages\n");
 
       /* wake the sender's thread */
-      if (CurrentSentMessage->CompletionEvent != NULL)
+      if (CurrentSentMessage->pkCompletionEvent != NULL)
       {
-         KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
+         KeSetEvent(CurrentSentMessage->pkCompletionEvent, IO_NO_INCREMENT, FALSE);
       }
 
       if (CurrentSentMessage->HasPackedLParam)
@@ -2147,71 +2196,49 @@ MsqCleanupThreadMsgs(PTHREADINFO pti)
       }
 
       /* free the message */
-      ExFreePool(CurrentSentMessage);
+      FreeUserMessage(CurrentSentMessage);
    }
 
-   /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
-      ExitThread() was called in a SendMessage() umode callback */
-   while (!IsListEmpty(&pti->LocalDispatchingMessagesHead))
+   // Process Trouble Message List
+   if (!IsListEmpty(&usmList))
    {
-      CurrentEntry = RemoveHeadList(&pti->LocalDispatchingMessagesHead);
-      CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
-
-      /* remove the message from the dispatching list */
-      if (!IsListEmpty(&CurrentSentMessage->DispatchingListEntry))
+      CurrentEntry = usmList.Flink;
+      while (CurrentEntry != &usmList)
       {
-         RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
-         InitializeListHead(&CurrentSentMessage->DispatchingListEntry);
-      }
-
-      TRACE("Notify the sender, the thread has been terminated while dispatching a message!\n");
+         CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, ListEntry);
+         CurrentEntry = CurrentEntry->Flink;
 
-      /* wake the sender's thread */
-      if (CurrentSentMessage->CompletionEvent != NULL)
-      {
-         KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
-      }
+         TRACE("Found troubled messages on the list\n");
 
-      if (CurrentSentMessage->HasPackedLParam)
-      {
-         if (CurrentSentMessage->Msg.lParam)
+         if ( pti == CurrentSentMessage->ptiReceiver )
          {
-            _PRAGMA_WARNING_SUPPRESS(__WARNING_USING_UNINIT_VAR);
-            ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
-         }
-      }
-
-      /* free the message */
-      ExFreePool(CurrentSentMessage);
-   }
+            if (CurrentSentMessage->HasPackedLParam)
+            {
+               if (CurrentSentMessage->Msg.lParam)
+                  ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
+            }
 
-   /* tell other threads not to bother returning any info to us */
-   while (! IsListEmpty(&pti->DispatchingMessagesHead))
-   {
-      CurrentEntry = RemoveHeadList(&pti->DispatchingMessagesHead);
-      CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE, DispatchingListEntry);
-      InitializeListHead(&CurrentSentMessage->DispatchingListEntry);
-      CurrentSentMessage->CompletionEvent = NULL;
-      CurrentSentMessage->Result = NULL;
+            /* free the message */
+            FreeUserMessage(CurrentSentMessage);
+         }
+         else if ( pti == CurrentSentMessage->ptiSender ||
+                   pti == CurrentSentMessage->ptiCallBackSender )
+         {
+            if (!(CurrentSentMessage->flags & SMF_RECEIVERFREE))
+            {
 
-      /* do NOT dereference our message queue as it might get attempted to be
-         locked later */
-   }
+               if (CurrentSentMessage->HasPackedLParam)
+               {
+                  if (CurrentSentMessage->Msg.lParam)
+                     ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
+               }
 
-   // Clear it all out.
-   if (pti->pcti)
-   {
-       pti->pcti->fsWakeBits = 0;
-       pti->pcti->fsChangeBits = 0;
+               /* free the message */
+               FreeUserMessage(CurrentSentMessage);
+            }
+         }
+      }
    }
-
-   pti->nCntsQBits[QSRosKey] = 0;
-   pti->nCntsQBits[QSRosMouseMove] = 0;
-   pti->nCntsQBits[QSRosMouseButton] = 0;
-   pti->nCntsQBits[QSRosPostMessage] = 0;
-   pti->nCntsQBits[QSRosSendMessage] = 0;
-   pti->nCntsQBits[QSRosHotKey] = 0;
-   pti->nCntsQBits[QSRosEvent] = 0;
 }
 
 VOID FASTCALL
@@ -2364,7 +2391,7 @@ co_MsqReplyMessage( LRESULT lResult )
 
    if (Message->QS_Flags & QS_SMRESULT) return FALSE;
 
-   //     SendMessageXxx    || Callback msg and not a notify msg
+   //     SendMessageXxx  || Callback msg and not a notify msg
    if (Message->ptiSender || Message->CompletionCallback)
    {
       Message->lResult = lResult;
index a2b9be0..e3b57e4 100644 (file)
@@ -22,20 +22,25 @@ typedef struct _USER_SENT_MESSAGE
   LIST_ENTRY ListEntry;
   MSG Msg;
   DWORD QS_Flags;  // Original QS bits used to create this message.
-  PKEVENT CompletionEvent;
-  LRESULT* Result;
+  PKEVENT pkCompletionEvent;
   LRESULT lResult;
+  DWORD flags;
   PTHREADINFO ptiSender;
   PTHREADINFO ptiReceiver;
   SENDASYNCPROC CompletionCallback;
   PTHREADINFO ptiCallBackSender;
   ULONG_PTR CompletionCallbackContext;
-  /* entry in the dispatching list of the sender's message queue */
-  LIST_ENTRY DispatchingListEntry;
   INT HookMessage;
   BOOL HasPackedLParam;
+  KEVENT CompletionEvent;
 } USER_SENT_MESSAGE, *PUSER_SENT_MESSAGE;
 
+#define SMF_RECEIVERDIED    0x00000002
+#define SMF_SENDERDIED      0x00000004
+#define SMF_RECEIVERFREE    0x00000008
+#define SMF_RECEIVEDMESSAGE 0x00000010
+#define SMF_RECEIVERBUSY    0x00004000
+
 typedef struct _USER_MESSAGE_QUEUE
 {
   /* Reference counter, only access this variable with interlocked functions! */
@@ -117,6 +122,8 @@ enum internal_event_message
 
 #define POSTEVENT_NWE 14
 
+extern LIST_ENTRY usmList;
+
 BOOL FASTCALL MsqIsHung(PTHREADINFO pti);
 VOID CALLBACK HungAppSysTimerProc(HWND,UINT,UINT_PTR,DWORD);
 NTSTATUS FASTCALL co_MsqSendMessage(PTHREADINFO ptirec,
@@ -252,6 +259,9 @@ VOID FASTCALL ClearMsgBitsMask(PTHREADINFO,UINT);
 BOOL FASTCALL IntCallMsgFilter(LPMSG,INT);
 WPARAM FASTCALL MsqGetDownKeyState(PUSER_MESSAGE_QUEUE);
 BOOL FASTCALL IsThreadSuspended(PTHREADINFO);
+PUSER_SENT_MESSAGE FASTCALL AllocateUserMessage(BOOL);
+VOID FASTCALL FreeUserMessage(PUSER_SENT_MESSAGE);
+
 
 int UserShowCursor(BOOL bShow);
 PCURICON_OBJECT
index ac5053c..eb09a46 100644 (file)
@@ -93,8 +93,7 @@ typedef struct _THREADINFO
     struct _CLIENTINFO * pClientInfo;
     FLONG               TIF_flags;
     PUNICODE_STRING     pstrAppName;
-    /* Messages that are currently dispatched to other threads */
-    LIST_ENTRY          DispatchingMessagesHead; // psmsSent
+    struct _USER_SENT_MESSAGE *pusmSent;
     struct _USER_SENT_MESSAGE *pusmCurrent;
     /* Queue of messages sent to the queue. */
     LIST_ENTRY          SentMessagesListHead;    // psmsReceiveList
@@ -127,6 +126,7 @@ typedef struct _THREADINFO
     INT                 iCursorLevel;
     POINT               ptLast;
 
+    INT                 cEnterCount;
     /* Queue of messages posted to the queue. */
     LIST_ENTRY          PostedMessagesListHead; // mlPost
     WORD                fsChangeBitsRemoved;
@@ -146,8 +146,6 @@ typedef struct _THREADINFO
     // Accounting of queue bit sets, the rest are flags. QS_TIMER QS_PAINT counts are handled in thread information.
     DWORD nCntsQBits[QSIDCOUNTS]; // QS_KEY QS_MOUSEMOVE QS_MOUSEBUTTON QS_POSTMESSAGE QS_SENDMESSAGE QS_HOTKEY
 
-    /* Messages that are currently dispatched by this message queue, required for cleanup */
-    LIST_ENTRY LocalDispatchingMessagesHead;
     LIST_ENTRY WindowListHead;
     LIST_ENTRY W32CallbackListHead;
     SINGLE_LIST_ENTRY  ReferencesList;