Change KEBUGCHECK -> KEBUGCHECKEX
[reactos.git] / reactos / ntoskrnl / ex / work.c
index 94fbba3..5001689 100644 (file)
@@ -1,12 +1,11 @@
-/* $Id$
- *
+/*
  * COPYRIGHT:          See COPYING in the top level directory
  * PROJECT:            ReactOS kernel
- * FILE:               mkernel/kernel/work.c
+ * FILE:               ntoskrnl/ex/work.c
  * PURPOSE:            Manage system work queues
- * PROGRAMMER:         David Welch (welch@mcmail.com)
- * REVISION HISTORY:
- *             29/06/98: Created
+ *
+ * PROGRAMMERS:        Alex Ionescu - Used correct work queue array and added some fixes and checks.
+ *                     Gunnar Dalsnes - Implemented
  */
 
 /* INCLUDES ******************************************************************/
 /*
  * PURPOSE: Queue of items waiting to be processed at normal priority
  */
-KQUEUE EiNormalWorkQueue;
-
-KQUEUE EiCriticalWorkQueue;
-
-KQUEUE EiHyperCriticalWorkQueue;
+EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue];
 
 /* FUNCTIONS ****************************************************************/
 
-//static NTSTATUS STDCALL
-static VOID STDCALL
-ExWorkerThreadEntryPoint(IN PVOID context)
 /*
  * FUNCTION: Entry point for a worker thread
  * ARGUMENTS:
@@ -45,138 +37,145 @@ ExWorkerThreadEntryPoint(IN PVOID context)
  * NOTE: To kill a worker thread you must queue an item whose callback
  * calls PsTerminateSystemThread
  */
+static
+VOID
+STDCALL
+ExpWorkerThreadEntryPoint(IN PVOID Context)
 {
-
-   PWORK_QUEUE_ITEM item;
-   PLIST_ENTRY current;
-   
-   while (TRUE) 
-   {
-      current = KeRemoveQueue( (PKQUEUE)context, KernelMode, NULL );
-      
-      /* can't happend since we do a KernelMode wait (and we're a system thread) */
-      ASSERT((NTSTATUS)current != STATUS_USER_APC);
-      
-      /* this should never happend either, since we wait with NULL timeout,
-       * but there's a slight possibility that STATUS_TIMEOUT is returned
-       * at queue rundown in NT (unlikely) -Gunnar
-       */
-      ASSERT((NTSTATUS)current != STATUS_TIMEOUT);
-      
-      /* based on INVALID_WORK_QUEUE_ITEM bugcheck desc. */
-      if (current->Flink == NULL || current->Blink == NULL)
-      {
-         KeBugCheck(INVALID_WORK_QUEUE_ITEM);
-      }
-      
-      /* "reinitialize" item (same as done in ExInitializeWorkItem) */
-      current->Flink = NULL;
-      
-      item = CONTAINING_RECORD( current, WORK_QUEUE_ITEM, List);
-      item->WorkerRoutine(item->Parameter);
-      
-      if (KeGetCurrentIrql() != PASSIVE_LEVEL)
-      {
-         KeBugCheck(IRQL_NOT_LESS_OR_EQUAL);
-      }
-   }
-   
+    PWORK_QUEUE_ITEM WorkItem;
+    PLIST_ENTRY QueueEntry;
+    WORK_QUEUE_TYPE WorkQueueType;
+    PEX_WORK_QUEUE WorkQueue;
+
+    /* Get Queue Type and Worker Queue */
+    WorkQueueType = (WORK_QUEUE_TYPE)Context;
+    WorkQueue = &ExWorkerQueue[WorkQueueType];
+
+    /* Loop forever */
+    while (TRUE) {
+
+        /* Wait for Something to Happen on the Queue */
+        QueueEntry = KeRemoveQueue(&WorkQueue->WorkerQueue, KernelMode, NULL);
+
+        /* Can't happen since we do a KernelMode wait (and we're a system thread) */
+        ASSERT((NTSTATUS)QueueEntry != STATUS_USER_APC);
+
+        /* this should never happen either, since we wait with NULL timeout,
+         * but there's a slight possibility that STATUS_TIMEOUT is returned
+         * at queue rundown in NT (unlikely) -Gunnar
+         */
+        ASSERT((NTSTATUS)QueueEntry != STATUS_TIMEOUT);
+
+        /* Increment Processed Work Items */
+        InterlockedIncrement((PLONG)&WorkQueue->WorkItemsProcessed);
+
+        /* Get the Work Item */
+        WorkItem = CONTAINING_RECORD(QueueEntry, WORK_QUEUE_ITEM, List);
+
+        /* Call the Worker Routine */
+        WorkItem->WorkerRoutine(WorkItem->Parameter);
+
+        /* Make sure it returned at right IRQL */
+        if (KeGetCurrentIrql() != PASSIVE_LEVEL) {
+
+            KEBUGCHECKEX(WORKER_THREAD_RETURNED_AT_BAD_IRQL,
+                         (ULONG_PTR)WorkItem->WorkerRoutine,
+                         KeGetCurrentIrql(),
+                         (ULONG_PTR)WorkItem->Parameter,
+                         (ULONG_PTR)WorkItem);
+        }
+
+        /* Make sure it returned with Impersionation Disabled */
+        if (PsGetCurrentThread()->ActiveImpersonationInfo) {
+
+            KEBUGCHECKEX(IMPERSONATING_WORKER_THREAD,
+                         (ULONG_PTR)WorkItem->WorkerRoutine,
+                         (ULONG_PTR)WorkItem->Parameter,
+                         (ULONG_PTR)WorkItem,
+                         0);
+        }
+    }
 }
 
-static VOID ExInitializeWorkQueue(PKQUEUE WorkQueue,
-                                 KPRIORITY Priority)
+static
+VOID
+STDCALL
+ExpInitializeWorkQueue(WORK_QUEUE_TYPE WorkQueueType,
+                       KPRIORITY Priority)
 {
-   ULONG i;
-   PETHREAD Thread;
-   HANDLE   hThread;
-   
-   
-   for (i=0; i<NUMBER_OF_WORKER_THREADS; i++)
-     {
-        
-   PsCreateSystemThread(&hThread,
-                            THREAD_ALL_ACCESS,
-                            NULL,
-                            NULL,
-                            NULL,
-                            ExWorkerThreadEntryPoint,
-              WorkQueue);
-   ObReferenceObjectByHandle(hThread,
-                                 THREAD_ALL_ACCESS,
-                                 PsThreadType,
-                                 KernelMode,
-                                 (PVOID*)&Thread,
-                                 NULL);
-       KeSetPriorityThread(&Thread->Tcb,
-                           Priority);
-       ObDereferenceObject(Thread);
-   ZwClose(hThread);
-     }
+    ULONG i;
+    PETHREAD Thread;
+    HANDLE hThread;
+
+    /* Loop through how many threads we need to create */
+    for (i = 0; i < NUMBER_OF_WORKER_THREADS; i++) {
+
+        /* Create the System Thread */
+        PsCreateSystemThread(&hThread,
+                             THREAD_ALL_ACCESS,
+                             NULL,
+                             NULL,
+                             NULL,
+                             ExpWorkerThreadEntryPoint,
+                             (PVOID)WorkQueueType);
+
+        /* Get the Thread */
+        ObReferenceObjectByHandle(hThread,
+                                  THREAD_SET_INFORMATION,
+                                  PsThreadType,
+                                  KernelMode,
+                                  (PVOID*)&Thread,
+                                  NULL);
+
+        /* Set the Priority */
+        KeSetPriorityThread(&Thread->Tcb, Priority);
+
+        /* Dereference and close handle */
+        ObDereferenceObject(Thread);
+        ZwClose(hThread);
+    }
 }
 
-VOID INIT_FUNCTION
-ExInitializeWorkerThreads(VOID)
+VOID
+INIT_FUNCTION
+STDCALL
+ExpInitializeWorkerThreads(VOID)
 {
-   KeInitializeQueue( &EiNormalWorkQueue, NUMBER_OF_WORKER_THREADS );
-   KeInitializeQueue( &EiCriticalWorkQueue , NUMBER_OF_WORKER_THREADS );
-   KeInitializeQueue( &EiHyperCriticalWorkQueue , NUMBER_OF_WORKER_THREADS );
-
-   ExInitializeWorkQueue(&EiNormalWorkQueue,
-                        LOW_PRIORITY);
-   ExInitializeWorkQueue(&EiCriticalWorkQueue,
-                        LOW_REALTIME_PRIORITY);
-   ExInitializeWorkQueue(&EiHyperCriticalWorkQueue,
-                        HIGH_PRIORITY);
+    ULONG WorkQueueType;
+
+    /* Initialize the Array */
+    for (WorkQueueType = 0; WorkQueueType < MaximumWorkQueue; WorkQueueType++) {
+
+        RtlZeroMemory(&ExWorkerQueue[WorkQueueType], sizeof(EX_WORK_QUEUE));
+        KeInitializeQueue(&ExWorkerQueue[WorkQueueType].WorkerQueue, 0);
+    }
+
+    /* Create the built-in worker threads for each work queue */
+    ExpInitializeWorkQueue(CriticalWorkQueue, LOW_REALTIME_PRIORITY);
+    ExpInitializeWorkQueue(DelayedWorkQueue, LOW_PRIORITY);
+    ExpInitializeWorkQueue(HyperCriticalWorkQueue, HIGH_PRIORITY);
 }
 
 /*
  * @implemented
- */
-VOID STDCALL
-ExQueueWorkItem (PWORK_QUEUE_ITEM      WorkItem,
-                WORK_QUEUE_TYPE                QueueType)
-/*
+ *
  * FUNCTION: Inserts a work item in a queue for one of the system worker
  * threads to process
  * ARGUMENTS:
  *        WorkItem = Item to insert
  *        QueueType = Queue to insert it in
  */
+VOID
+STDCALL
+ExQueueWorkItem(PWORK_QUEUE_ITEM WorkItem,
+                WORK_QUEUE_TYPE QueueType)
 {
     ASSERT(WorkItem!=NULL);
     ASSERT_IRQL(DISPATCH_LEVEL);
     ASSERT(WorkItem->List.Flink == NULL);
-   /*
-    * Insert the item in the appropiate queue and wake up any thread
-    * waiting for something to do
-    */
-    switch(QueueType)
-    {
-    case DelayedWorkQueue:
-      KeInsertQueue (
-          &EiNormalWorkQueue,
-          &WorkItem->List
-            );
-       break;
-       
-    case CriticalWorkQueue:
-            KeInsertQueue (
-              &EiCriticalWorkQueue,
-              &WorkItem->List
-              );
-           break;
-
-    case HyperCriticalWorkQueue:
-            KeInsertQueue (
-             &EiHyperCriticalWorkQueue,
-             &WorkItem->List
-             );
-               break;
-     
-    default:
-        break;
 
-    }
+    /* Insert the Queue */
+    KeInsertQueue(&ExWorkerQueue[QueueType].WorkerQueue, &WorkItem->List);
 }
 
 /* EOF */