reactos/subsys/win32k/include
diff -u -r1.36 -r1.37
--- msgqueue.h 19 May 2004 18:45:31 -0000 1.36
+++ msgqueue.h 22 May 2004 16:48:50 -0000 1.37
@@ -42,6 +42,9 @@
typedef struct _USER_MESSAGE_QUEUE
{
+ /* Reference counter, only access this variable with interlocked functions! */
+ LONG References;
+
/* Owner of the message queue */
struct _ETHREAD *Thread;
/* Queue of messages sent to the queue. */
@@ -99,6 +102,8 @@
/* messages that are currently dispatched by other threads */
LIST_ENTRY DispatchingMessagesHead;
+ /* messages that are currently dispatched by this message queue, required for cleanup */
+ LIST_ENTRY LocalDispatchingMessagesHead;
} USER_MESSAGE_QUEUE, *PUSER_MESSAGE_QUEUE;
BOOL FASTCALL
@@ -127,7 +132,7 @@
VOID FASTCALL
MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue);
VOID FASTCALL
-MsqFreeMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue);
+MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue);
PUSER_MESSAGE_QUEUE FASTCALL
MsqCreateMessageQueue(struct _ETHREAD *Thread);
VOID FASTCALL
@@ -197,20 +202,32 @@
LPARAM FASTCALL MsqGetMessageExtraInfo(VOID);
#define IntLockMessageQueue(MsgQueue) \
- ExAcquireFastMutex(&MsgQueue->Lock)
+ ExAcquireFastMutex(&(MsgQueue)->Lock)
#define IntUnLockMessageQueue(MsgQueue) \
- ExReleaseFastMutex(&MsgQueue->Lock)
+ ExReleaseFastMutex(&(MsgQueue)->Lock)
#define IntLockHardwareMessageQueue(MsgQueue) \
- KeWaitForMutexObject(&MsgQueue->HardwareLock, UserRequest, KernelMode, FALSE, NULL)
+ KeWaitForMutexObject(&(MsgQueue)->HardwareLock, UserRequest, KernelMode, FALSE, NULL)
#define IntUnLockHardwareMessageQueue(MsgQueue) \
- KeReleaseMutex(&MsgQueue->HardwareLock, FALSE)
+ KeReleaseMutex(&(MsgQueue)->HardwareLock, FALSE)
+
+#define IntReferenceMessageQueue(MsgQueue) \
+ InterlockedIncrement(&(MsgQueue)->References)
+
+#define IntDereferenceMessageQueue(MsgQueue) \
+ do { \
+ if(InterlockedDecrement(&(MsgQueue)->References) == 0) \
+ { \
+ DPRINT("Free message queue 0x%x\n", (MsgQueue)); \
+ ExFreePool((MsgQueue)); \
+ } \
+ } while(0)
/* check the queue status */
#define MsqIsSignaled(MsgQueue) \
- ((MsgQueue->WakeBits & MsgQueue->WakeMask) || (MsgQueue->ChangedBits & MsgQueue->ChangedMask))
+ (((MsgQueue)->WakeBits & (MsgQueue)->WakeMask) || ((MsgQueue)->ChangedBits & (MsgQueue)->ChangedMask))
#define IS_BTN_MESSAGE(message,code) \
((message) == WM_LBUTTON##code || \
reactos/subsys/win32k/ntuser
diff -u -r1.98 -r1.99
--- msgqueue.c 20 May 2004 21:48:41 -0000 1.98
+++ msgqueue.c 22 May 2004 16:48:50 -0000 1.99
@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* $Id: msgqueue.c,v 1.98 2004/05/20 21:48:41 weiden Exp $
+/* $Id: msgqueue.c,v 1.99 2004/05/22 16:48:50 weiden Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@@ -420,8 +420,6 @@
return FALSE;
}
- DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
-
WaitObjects[1] = &MessageQueue->NewMessages;
WaitObjects[0] = &HardwareMessageQueueLock;
do
@@ -435,6 +433,8 @@
}
while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
+ DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
+
/* Process messages in the message queue itself. */
IntLockHardwareMessageQueue(MessageQueue);
CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink;
@@ -729,6 +729,7 @@
PUSER_SENT_MESSAGE Message;
PLIST_ENTRY Entry;
LRESULT Result;
+ BOOL Freed;
PUSER_SENT_MESSAGE_NOTIFY NotifyMessage;
IntLockMessageQueue(MessageQueue);
@@ -737,19 +738,35 @@
IntUnLockMessageQueue(MessageQueue);
return(FALSE);
}
+
+ /* remove it from the list of pending messages */
Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
+
+ /* insert it to the list of messages that are currently dispatched by this
+ message queue */
+ InsertTailList(&MessageQueue->LocalDispatchingMessagesHead,
+ &Message->ListEntry);
+
IntUnLockMessageQueue(MessageQueue);
-
+
/* Call the window procedure. */
Result = IntSendMessage(Message->Msg.hwnd,
Message->Msg.message,
Message->Msg.wParam,
Message->Msg.lParam);
+
+ /* remove the message from the local dispatching list, because it doesn't need
+ to be cleaned up on thread termination anymore */
+ IntLockMessageQueue(MessageQueue);
+ RemoveEntryList(&Message->ListEntry);
+ IntUnLockMessageQueue(MessageQueue);
/* remove the message from the dispatching list, so lock the sender's message queue */
IntLockMessageQueue(Message->SenderQueue);
- if(Message->DispatchingListEntry.Flink != NULL)
+
+ Freed = (Message->DispatchingListEntry.Flink == NULL);
+ if(!Freed)
{
/* only remove it from the dispatching list if not already removed by a timeout */
RemoveEntryList(&Message->DispatchingListEntry);
@@ -768,12 +785,12 @@
{
KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
}
-
+
/* unlock the sender's message queue, the safe operation is done */
IntUnLockMessageQueue(Message->SenderQueue);
/* Notify the sender if they specified a callback. */
- if (Message->CompletionCallback != NULL)
+ if (!Freed && Message->CompletionCallback != NULL)
{
if(!(NotifyMessage = ExAllocatePoolWithTag(NonPagedPool,
sizeof(USER_SENT_MESSAGE_NOTIFY), TAG_USRMSG)))
@@ -792,7 +809,13 @@
}
Notified:
- /* FIXME - decrease reference counter of sender's message queue here */
+ if(!Freed)
+ {
+ /* only dereference our message queue if the message has not been timed out */
+ IntDereferenceMessageQueue(MessageQueue);
+ }
+
+ /* only free the message if not freed already */
ExFreePool(Message);
return(TRUE);
}
@@ -846,6 +869,8 @@
Message->SenderQueue = ThreadQueue;
Message->CompletionCallback = NULL;
+ IntReferenceMessageQueue(MessageQueue);
+
/* add it to the list of pending messages */
IntLockMessageQueue(ThreadQueue);
InsertTailList(&ThreadQueue->DispatchingMessagesHead, &Message->DispatchingListEntry);
@@ -902,6 +927,7 @@
Message->CompletionEvent = NULL;
Message->Result = NULL;
RemoveEntryList(&Message->DispatchingListEntry);
+ IntDereferenceMessageQueue(MessageQueue);
break;
}
Entry = Entry->Flink;
@@ -941,7 +967,7 @@
}
Entry = Entry->Flink;
}
- IntUnLockMessageQueue(MessageQueue);
+ IntUnLockMessageQueue(MessageQueue);
/* remove from the local dispatching list so the other thread knows,
it can't pass a result and it must not set the completion event anymore */
@@ -959,6 +985,7 @@
Message->CompletionEvent = NULL;
Message->Result = NULL;
RemoveEntryList(&Message->DispatchingListEntry);
+ IntDereferenceMessageQueue(MessageQueue);
break;
}
Entry = Entry->Flink;
@@ -1085,6 +1112,7 @@
InitializeListHead(&MessageQueue->SentMessagesListHead);
InitializeListHead(&MessageQueue->HardwareMessagesListHead);
InitializeListHead(&MessageQueue->DispatchingMessagesHead);
+ InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
KeInitializeMutex(&MessageQueue->HardwareLock, 0);
ExInitializeFastMutex(&MessageQueue->Lock);
MessageQueue->QuitPosted = FALSE;
@@ -1098,19 +1126,75 @@
}
VOID FASTCALL
-MsqFreeMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
+MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
{
PLIST_ENTRY CurrentEntry;
PUSER_MESSAGE CurrentMessage;
-
- CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
- while (CurrentEntry != &MessageQueue->PostedMessagesListHead)
+ PUSER_SENT_MESSAGE CurrentSentMessage;
+
+ IntLockMessageQueue(MessageQueue);
+
+ /* cleanup posted messages */
+ while (!IsListEmpty(&MessageQueue->PostedMessagesListHead))
{
+ CurrentEntry = RemoveHeadList(&MessageQueue->PostedMessagesListHead);
CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
ListEntry);
- CurrentEntry = CurrentEntry->Flink;
MsqDestroyMessage(CurrentMessage);
}
+
+ /* remove the messages that have not yet been dispatched */
+ while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
+ {
+ CurrentEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
+ CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
+ ListEntry);
+
+ DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
+
+ /* remove the message from the dispatching list */
+ if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
+ {
+ RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
+ }
+
+ /* wake the sender's thread */
+ if (CurrentSentMessage->CompletionEvent != NULL)
+ {
+ KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ /* dereference our message queue */
+ IntDereferenceMessageQueue(MessageQueue);
+
+ /* free the message */
+ ExFreePool(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(&MessageQueue->LocalDispatchingMessagesHead))
+ {
+ CurrentEntry = RemoveHeadList(&MessageQueue->LocalDispatchingMessagesHead);
+ CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
+ ListEntry);
+
+ DPRINT("Notify the sender, the thread has been terminated while dispatching a message!\n");
+
+ /* wake the sender's thread */
+ if (CurrentSentMessage->CompletionEvent != NULL)
+ {
+ KeSetEvent(CurrentSentMessage->CompletionEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ /* dereference our message queue */
+ IntDereferenceMessageQueue(MessageQueue);
+
+ /* free the message */
+ ExFreePool(CurrentSentMessage);
+ }
+ DbgPrint("Done cleaning up message queue...\n");
+ IntUnLockMessageQueue(MessageQueue);
}
PUSER_MESSAGE_QUEUE FASTCALL
@@ -1128,6 +1212,9 @@
}
RtlZeroMemory(MessageQueue, sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO));
+ /* hold at least one reference until it'll be destroyed */
+ IntReferenceMessageQueue(MessageQueue);
+ /* initialize the queue */
MsqInitializeMessageQueue(Thread, MessageQueue);
return MessageQueue;
@@ -1136,8 +1223,9 @@
VOID FASTCALL
MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
{
- MsqFreeMessageQueue(MessageQueue);
- ExFreePool(MessageQueue);
+ MsqCleanupMessageQueue(MessageQueue);
+ /* decrease the reference counter, if it hits zero, the queue will be freed */
+ IntDereferenceMessageQueue(MessageQueue);
}
PHOOKTABLE FASTCALL