Added process ids.
[reactos.git] / reactos / ntoskrnl / ps / thread.c
index 0975fc2..285c7f2 100644 (file)
-/*\r
- * COPYRIGHT:              See COPYING in the top level directory\r
- * PROJECT:                ReactOS kernel\r
- * FILE:                   ntoskrnl/ps/thread.c\r
- * PURPOSE:                Thread managment\r
- * PROGRAMMER:             David Welch (welch@mcmail.com)\r
- * REVISION HISTORY: \r
- *               23/06/98: Created\r
- */\r
-\r
-/*\r
- * NOTE:\r
- * \r
- * All of the routines that manipulate the thread queue synchronize on\r
- * a single spinlock\r
- * \r
- */\r
-\r
-/* INCLUDES ****************************************************************/\r
-\r
-#include <windows.h>\r
-#include <ddk/ntddk.h>\r
-#include <internal/ke.h>\r
-#include <internal/ob.h>\r
-#include <internal/string.h>\r
-#include <internal/hal.h>\r
-#include <internal/ps.h>\r
-\r
-#define NDEBUG\r
-#include <internal/debug.h>\r
-\r
-/* TYPES *******************************************************************/\r
-\r
-/* GLOBALS ******************************************************************/\r
-\r
-POBJECT_TYPE PsThreadType = NULL;\r
-\r
-#define NR_THREAD_PRIORITY_LEVELS (31)\r
-#define THREAD_PRIORITY_MAX (15)\r
-\r
-static KSPIN_LOCK ThreadListLock = {0,};\r
-\r
-/*\r
- * PURPOSE: List of threads associated with each priority level\r
- */\r
-static LIST_ENTRY PriorityListHead[NR_THREAD_PRIORITY_LEVELS]={{NULL,NULL},};\r
-static BOOLEAN DoneInitYet = FALSE;\r
-ULONG PiNrThreads = 0;\r
-\r
-static PETHREAD CurrentThread = NULL;\r
-\r
-static ULONG NextThreadUniqueId = 0;\r
-\r
-/* FUNCTIONS ***************************************************************/\r
-\r
-PKTHREAD KeGetCurrentThread(VOID)\r
-{\r
-   return(&(CurrentThread->Tcb));\r
-}\r
-\r
-PETHREAD PsGetCurrentThread(VOID)\r
-{\r
-   return((PETHREAD)KeGetCurrentThread());\r
-}\r
-\r
-static VOID PsInsertIntoThreadList(KPRIORITY Priority, PETHREAD Thread)\r
-{\r
-   KIRQL oldlvl;\r
-   \r
-   DPRINT("PsInsertIntoThreadList(Priority %x, Thread %x)\n",Priority,\r
-           Thread);\r
-   \r
-   KeAcquireSpinLock(&ThreadListLock,&oldlvl);\r
-   InsertTailList(&PriorityListHead[THREAD_PRIORITY_MAX+Priority],\r
-                 &Thread->Tcb.Entry);\r
-   KeReleaseSpinLock(&ThreadListLock,oldlvl);\r
-}\r
-\r
-VOID PsBeginThread(PKSTART_ROUTINE StartRoutine, PVOID StartContext)\r
-{\r
-   NTSTATUS Ret;\r
-   \r
-   KeReleaseSpinLock(&ThreadListLock,PASSIVE_LEVEL);\r
-   Ret = StartRoutine(StartContext);\r
-   PsTerminateSystemThread(Ret);\r
-   for(;;);\r
-}\r
-\r
-static PETHREAD PsScanThreadList(KPRIORITY Priority)\r
-{\r
-   PLIST_ENTRY current_entry;\r
-   PETHREAD current;\r
-   PETHREAD oldest = NULL;\r
-   ULONG oldest_time = 0;\r
-   \r
-//   DPRINT("PsScanThreadList(Priority %d)\n",Priority);\r
-   \r
-   current_entry = PriorityListHead[THREAD_PRIORITY_MAX+Priority].Flink;\r
-   while (current_entry != &PriorityListHead[THREAD_PRIORITY_MAX+Priority])\r
-     {\r
-       current = CONTAINING_RECORD(current_entry,ETHREAD,Tcb.Entry);\r
-       #if 0\r
-       if (current->Tcb.ThreadState == THREAD_STATE_TERMINATED &&\r
-           current != CurrentThread)\r
-         {\r
-            PsReleaseThread(CurrentThread);\r
-         }\r
-       #endif\r
-       if (current->Tcb.ThreadState == THREAD_STATE_RUNNABLE)\r
-         {\r
-            if (oldest == NULL || oldest_time > current->Tcb.LastTick)\r
-              {\r
-                 oldest = current;\r
-                 oldest_time = current->Tcb.LastTick;\r
-              }\r
-         }\r
-       current_entry = current_entry->Flink;\r
-     }\r
-//   DPRINT("PsScanThreadList() = %x\n",oldest);\r
-   return(oldest);\r
-}\r
-\r
-VOID PsDispatchThread(VOID)\r
-{\r
-   KPRIORITY CurrentPriority;\r
-   PETHREAD Candidate;\r
-   KIRQL irql;\r
-   LARGE_INTEGER TickCount;\r
-   \r
-   KeAcquireSpinLock(&ThreadListLock,&irql);\r
-   \r
-   if (!DoneInitYet)\r
-     {\r
-       return;\r
-     }\r
-   \r
-   DPRINT("PsDispatchThread() Current %x\n",CurrentThread);\r
-      \r
-   if (CurrentThread->Tcb.ThreadState==THREAD_STATE_RUNNING)     \r
-     {\r
-       CurrentThread->Tcb.ThreadState=THREAD_STATE_RUNNABLE;\r
-     }\r
-   \r
-   for (CurrentPriority=THREAD_PRIORITY_TIME_CRITICAL; \r
-       CurrentPriority>=THREAD_PRIORITY_IDLE;\r
-       CurrentPriority--)\r
-     {\r
-       Candidate = PsScanThreadList(CurrentPriority);\r
-       if (Candidate == CurrentThread)\r
-         {\r
-//             DbgPrint("Scheduling current thread\n");\r
-             KeQueryTickCount(&TickCount);\r
-             CurrentThread->Tcb.LastTick = GET_LARGE_INTEGER_LOW_PART(TickCount);\r
-            CurrentThread->Tcb.ThreadState = THREAD_STATE_RUNNING;\r
-            KeReleaseSpinLock(&ThreadListLock,irql);\r
-            return;\r
-         }\r
-       if (Candidate != NULL)\r
-         {     \r
-//             DbgPrint("Scheduling %x\n",Candidate);\r
-            \r
-            Candidate->Tcb.ThreadState = THREAD_STATE_RUNNING;\r
-            \r
-            KeQueryTickCount(&TickCount);\r
-            CurrentThread->Tcb.LastTick = GET_LARGE_INTEGER_LOW_PART(TickCount);\r
-            \r
-            CurrentThread = Candidate;\r
-            \r
-            HalTaskSwitch(&CurrentThread->Tcb);\r
-            KeReleaseSpinLock(&ThreadListLock,irql);\r
-            return;\r
-         }\r
-     }\r
-}\r
-\r
-NTSTATUS PsInitializeThread(HANDLE ProcessHandle, \r
-                           PETHREAD* ThreadPtr,\r
-                           PHANDLE ThreadHandle,\r
-                           ACCESS_MASK DesiredAccess,\r
-                           POBJECT_ATTRIBUTES ThreadAttributes)\r
-{\r
-   ULONG ThreadId;\r
-   ULONG ProcessId;\r
-   PETHREAD Thread;\r
-   NTSTATUS Status;\r
-   \r
-   PiNrThreads++;\r
-   \r
-   Thread = ObGenericCreateObject(ThreadHandle,\r
-                                 DesiredAccess,\r
-                                 ThreadAttributes,\r
-                                 PsThreadType);\r
-   DPRINT("Thread = %x\n",Thread);\r
-   Thread->Tcb.LastTick = 0;\r
-   Thread->Tcb.ThreadState=THREAD_STATE_SUSPENDED;\r
-   Thread->Tcb.BasePriority=THREAD_PRIORITY_NORMAL;\r
-   Thread->Tcb.CurrentPriority=THREAD_PRIORITY_NORMAL;\r
-   Thread->Tcb.ApcList=ExAllocatePool(NonPagedPool,sizeof(LIST_ENTRY));\r
-   Thread->Tcb.SuspendCount = 1;\r
-   if (ProcessHandle!=NULL)\r
-     {\r
-       Status = ObReferenceObjectByHandle(ProcessHandle,\r
-                                          PROCESS_CREATE_THREAD,\r
-                                          PsProcessType,\r
-                                          UserMode,\r
-                                          (PVOID*)&Thread->ThreadsProcess,\r
-                                          NULL);\r
-       if (Status != STATUS_SUCCESS)\r
-         {\r
-            return(Status);\r
-         }\r
-     }\r
-   else\r
-     {\r
-       Thread->ThreadsProcess=SystemProcess;\r
-       ObReferenceObjectByPointer(Thread->ThreadsProcess,\r
-                                  PROCESS_CREATE_THREAD,\r
-                                  PsProcessType,\r
-                                  UserMode);\r
-     }\r
-   ObReferenceObjectByPointer(Thread->ThreadsProcess,\r
-                             PROCESS_CREATE_THREAD,\r
-                             PsProcessType,\r
-                             UserMode);\r
-   InitializeListHead(Thread->Tcb.ApcList);\r
-   InitializeListHead(&(Thread->IrpList));\r
-   Thread->Cid.UniqueThread=InterlockedIncrement(&NextThreadUniqueId);\r
-   PsInsertIntoThreadList(Thread->Tcb.CurrentPriority,Thread);\r
-   \r
-   *ThreadPtr = Thread;\r
-   \r
-   ObDereferenceObject(Thread->ThreadsProcess);   \r
-   return(STATUS_SUCCESS);\r
-}\r
-\r
-VOID PsResumeThread(PETHREAD Thread)\r
-{\r
-   DPRINT("PsResumeThread(Thread %x)\n",Thread);\r
-   \r
-   Thread->Tcb.SuspendCount--;\r
-   DPRINT("Thread->Tcb.SuspendCount %d\n",Thread->Tcb.SuspendCount);\r
-   DPRINT("Thread->Tcb.ThreadState %d THREAD_STATE_RUNNING %d\n",\r
-           Thread->Tcb.ThreadState,THREAD_STATE_RUNNING);\r
-   if (Thread->Tcb.SuspendCount <= 0 && \r
-       Thread->Tcb.ThreadState != THREAD_STATE_RUNNING)\r
-     {\r
-        DPRINT("Setting thread to runnable\n");\r
-       Thread->Tcb.ThreadState = THREAD_STATE_RUNNABLE;\r
-     }\r
-   DPRINT("Finished PsResumeThread()\n");\r
-}\r
-\r
-VOID PsSuspendThread(PETHREAD Thread)\r
-{\r
-   DPRINT("PsSuspendThread(Thread %x)\n",Thread);\r
-   Thread->Tcb.SuspendCount++;\r
-   if (Thread->Tcb.SuspendCount > 0)\r
-     {\r
-       Thread->Tcb.ThreadState = THREAD_STATE_SUSPENDED;\r
-       if (Thread == CurrentThread)\r
-         {\r
-            PsDispatchThread();\r
-         }\r
-     }\r
-}\r
-\r
-void PsInitThreadManagment(void)\r
-/*\r
- * FUNCTION: Initialize thread managment\r
- */\r
-{\r
-   PETHREAD FirstThread;\r
-   ULONG i;\r
-   ANSI_STRING AnsiString;\r
-   HANDLE FirstThreadHandle;\r
-   \r
-   KeInitializeSpinLock(&ThreadListLock);\r
-   for (i=0; i<NR_THREAD_PRIORITY_LEVELS; i++)\r
-     {\r
-       InitializeListHead(&PriorityListHead[i]);\r
-     }\r
-   \r
-   PsThreadType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));\r
-   \r
-   RtlInitAnsiString(&AnsiString,"Thread");\r
-   RtlAnsiStringToUnicodeString(&PsThreadType->TypeName,&AnsiString,TRUE);\r
-   \r
-   PsThreadType->TotalObjects = 0;\r
-   PsThreadType->TotalHandles = 0;\r
-   PsThreadType->MaxObjects = 0;\r
-   PsThreadType->MaxHandles = 0;\r
-   PsThreadType->PagedPoolCharge = 0;\r
-   PsThreadType->NonpagedPoolCharge = sizeof(ETHREAD);\r
-   PsThreadType->Dump = NULL;\r
-   PsThreadType->Open = NULL;\r
-   PsThreadType->Close = NULL;\r
-   PsThreadType->Delete = NULL;\r
-   PsThreadType->Parse = NULL;\r
-   PsThreadType->Security = NULL;\r
-   PsThreadType->QueryName = NULL;\r
-   PsThreadType->OkayToClose = NULL;\r
-   \r
-   PsInitializeThread(NULL,&FirstThread,&FirstThreadHandle,\r
-                     THREAD_ALL_ACCESS,NULL);\r
-   HalInitFirstTask(FirstThread);\r
-   FirstThread->Tcb.ThreadState = THREAD_STATE_RUNNING;\r
-   FirstThread->Tcb.SuspendCount = 0;\r
-\r
-   DPRINT("FirstThread %x\n",FirstThread);\r
-   \r
-   CurrentThread = FirstThread;\r
-   \r
-   DoneInitYet = TRUE;\r
-}\r
-\r
-NTSTATUS NtCreateThread(PHANDLE ThreadHandle,\r
-                       ACCESS_MASK DesiredAccess,\r
-                       POBJECT_ATTRIBUTES ObjectAttributes,\r
-                       HANDLE ProcessHandle,\r
-                       PCLIENT_ID Client,\r
-                       PCONTEXT ThreadContext,\r
-                       PINITIAL_TEB InitialTeb,\r
-                       BOOLEAN CreateSuspended)\r
-{\r
-   return(ZwCreateThread(ThreadHandle,\r
-                        DesiredAccess,\r
-                        ObjectAttributes,\r
-                        ProcessHandle,\r
-                        Client,\r
-                        ThreadContext,\r
-                        InitialTeb,\r
-                        CreateSuspended));\r
-}\r
-\r
-NTSTATUS ZwCreateThread(PHANDLE ThreadHandle,\r
-                       ACCESS_MASK DesiredAccess,\r
-                       POBJECT_ATTRIBUTES ObjectAttributes,\r
-                       HANDLE ProcessHandle,\r
-                       PCLIENT_ID Client,\r
-                       PCONTEXT ThreadContext,\r
-                       PINITIAL_TEB InitialTeb,\r
-                       BOOLEAN CreateSuspended)\r
-{\r
-   PETHREAD Thread;\r
-   NTSTATUS Status;\r
-   \r
-   DbgPrint("ZwCreateThread(ThreadHandle %x, PCONTEXT %x)\n",\r
-         ThreadHandle,ThreadContext);\r
-   \r
-   Status = PsInitializeThread(ProcessHandle,&Thread,ThreadHandle,\r
-                              DesiredAccess,ObjectAttributes);\r
-   if (Status != STATUS_SUCCESS)\r
-     {\r
-       return(Status);\r
-     }\r
-   \r
-   HalInitTaskWithContext(Thread,ThreadContext);\r
-   Thread->StartAddress=NULL;\r
-\r
-   if (Client!=NULL)\r
-     {\r
-       *Client=Thread->Cid;\r
-     }  \r
-   \r
-   if (!CreateSuspended)\r
-     {\r
-        DPRINT("Not creating suspended\n");\r
-       PsResumeThread(Thread);\r
-     }\r
-   DPRINT("Finished PsCreateThread()\n");\r
-   return(STATUS_SUCCESS);\r
-}\r
-\r
-NTSTATUS PsCreateSystemThread(PHANDLE ThreadHandle,\r
-                             ACCESS_MASK DesiredAccess,\r
-                             POBJECT_ATTRIBUTES ObjectAttributes,\r
-                             HANDLE ProcessHandle,\r
-                             PCLIENT_ID ClientId,\r
-                             PKSTART_ROUTINE StartRoutine,\r
-                             PVOID StartContext)\r
-/*\r
- * FUNCTION: Creates a thread which executes in kernel mode\r
- * ARGUMENTS:\r
- *       ThreadHandle (OUT) = Caller supplied storage for the returned thread \r
- *                            handle\r
- *       DesiredAccess = Requested access to the thread\r
- *       ObjectAttributes = Object attributes (optional)\r
- *       ProcessHandle = Handle of process thread will run in\r
- *                       NULL to use system process\r
- *       ClientId (OUT) = Caller supplied storage for the returned client id\r
- *                        of the thread (optional)\r
- *       StartRoutine = Entry point for the thread\r
- *       StartContext = Argument supplied to the thread when it begins\r
- *                     execution\r
- * RETURNS: Success or failure status\r
- */\r
-{\r
-   PETHREAD Thread;\r
-   NTSTATUS Status;\r
-   \r
-   DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",\r
-           ThreadHandle,ProcessHandle);\r
-   \r
-   Status = PsInitializeThread(ProcessHandle,&Thread,ThreadHandle,\r
-                              DesiredAccess,ObjectAttributes);\r
-   if (Status != STATUS_SUCCESS)\r
-     {\r
-       return(Status);\r
-     }\r
-   \r
-   Thread->StartAddress=StartRoutine;\r
-   HalInitTask(Thread,StartRoutine,StartContext);\r
-\r
-   if (ClientId!=NULL)\r
-     {\r
-       *ClientId=Thread->Cid;\r
-     }  \r
-\r
-   PsResumeThread(Thread);\r
-   \r
-   return(STATUS_SUCCESS);\r
-}\r
-\r
-LONG KeSetBasePriorityThread(PKTHREAD Thread, LONG Increment)\r
-{\r
-   UNIMPLEMENTED;\r
-}\r
-\r
-KPRIORITY KeSetPriorityThread(PKTHREAD Thread, KPRIORITY Priority)\r
-{\r
-   KPRIORITY OldPriority;\r
-   OldPriority = Thread->CurrentPriority;\r
-   Thread->CurrentPriority = Priority;\r
-\r
-   RemoveEntryList(&Thread->Entry);\r
-   PsInsertIntoThreadList(Thread->CurrentPriority,\r
-                         CONTAINING_RECORD(Thread,ETHREAD,Tcb));\r
-   \r
-   return(OldPriority);\r
-}\r
-\r
-NTSTATUS STDCALL NtAlertResumeThread(IN HANDLE ThreadHandle,\r
-                                    OUT PULONG SuspendCount)\r
-{\r
-   return(ZwAlertResumeThread(ThreadHandle,SuspendCount));\r
-}\r
-\r
-NTSTATUS STDCALL ZwAlertResumeThread(IN HANDLE ThreadHandle,\r
-                                    OUT PULONG SuspendCount)\r
-{\r
-   UNIMPLEMENTED;\r
-}\r
-\r
-NTSTATUS STDCALL NtAlertThread(IN HANDLE ThreadHandle)\r
-{\r
-   return(ZwAlertThread(ThreadHandle));\r
-}\r
-\r
-NTSTATUS STDCALL ZwAlertThread(IN HANDLE ThreadHandle)\r
-{\r
-   UNIMPLEMENTED;\r
-}\r
-\r
-NTSTATUS STDCALL NtGetContextThread(IN HANDLE ThreadHandle, \r
-                                   OUT PCONTEXT Context)\r
-{\r
-   return(ZwGetContextThread(ThreadHandle,Context));\r
-}\r
-\r
-NTSTATUS STDCALL ZwGetContextThread(IN HANDLE ThreadHandle, \r
-                                   OUT PCONTEXT Context)\r
-{\r
-   UNIMPLEMENTED;\r
-}\r
-\r
-NTSTATUS STDCALL NtOpenThread(OUT PHANDLE ThreadHandle,\r
-                             IN ACCESS_MASK DesiredAccess,\r
-                             IN POBJECT_ATTRIBUTES ObjectAttributes,\r
-                             IN PCLIENT_ID ClientId)\r
-{\r
-   return(ZwOpenThread(ThreadHandle,\r
-                      DesiredAccess,\r
-                      ObjectAttributes,\r
-                      ClientId));\r
-}\r
-\r
-NTSTATUS STDCALL ZwOpenThread(OUT PHANDLE ThreadHandle,\r
-                             IN ACCESS_MASK DesiredAccess,\r
-                             IN POBJECT_ATTRIBUTES ObjectAttributes,\r
-                             IN PCLIENT_ID ClientId)\r
-{\r
-   UNIMPLEMENTED;\r
-}\r
-\r
-NTSTATUS STDCALL NtResumeThread(IN HANDLE ThreadHandle,\r
-                               IN PULONG SuspendCount)\r
-{\r
-   return(ZwResumeThread(ThreadHandle,SuspendCount));\r
-}\r
-\r
-NTSTATUS STDCALL ZwResumeThread(IN HANDLE ThreadHandle,\r
-                               IN PULONG SuspendCount)\r
-/*\r
- * FUNCTION: Decrements a thread's resume count\r
- * ARGUMENTS: \r
- *        ThreadHandle = Handle to the thread that should be resumed\r
- *        ResumeCount =  The resulting resume count.\r
- * REMARK:\r
- *       A thread is resumed if its suspend count is 0. This procedure maps to\r
- *        the win32 ResumeThread function. ( documentation about the the suspend count can be found here aswell )\r
- * RETURNS: Status\r
- */\r
-{\r
-   PETHREAD Thread;\r
-   NTSTATUS Status;\r
-   \r
-   Status = ObReferenceObjectByHandle(ThreadHandle,\r
-                                     THREAD_SUSPEND_RESUME,\r
-                                     PsThreadType,\r
-                                     UserMode,\r
-                                     (PVOID*)&Thread,\r
-                                     NULL);\r
-   if (Status != STATUS_SUCCESS)\r
-     {\r
-       return(Status);\r
-     }\r
-   \r
-   (*SuspendCount) = InterlockedDecrement(&Thread->Tcb.SuspendCount);\r
-   if (Thread->Tcb.SuspendCount <= 0)\r
-     {\r
-       Thread->Tcb.ThreadState = THREAD_STATE_RUNNABLE;\r
-     }\r
-   \r
-   ObDereferenceObject(Thread);\r
-   return(STATUS_SUCCESS);\r
-}\r
-\r
-NTSTATUS STDCALL NtSetContextThread(IN HANDLE ThreadHandle,\r
-                                   IN PCONTEXT Context)\r
-{\r
-   return(ZwSetContextThread(ThreadHandle,Context));\r
-}\r
-\r
-NTSTATUS STDCALL ZwSetContextThread(IN HANDLE ThreadHandle,\r
-                                   IN PCONTEXT Context)\r
-{\r
-   UNIMPLEMENTED;\r
-}\r
-\r
-NTSTATUS STDCALL NtSuspendThread(IN HANDLE ThreadHandle,\r
-                                IN PULONG PreviousSuspendCount)\r
-{\r
-   return(ZwSuspendThread(ThreadHandle,PreviousSuspendCount));\r
-}\r
-\r
-NTSTATUS STDCALL ZwSuspendThread(IN HANDLE ThreadHandle,\r
-                                IN PULONG PreviousSuspendCount)\r
-/*\r
- * FUNCTION: Increments a thread's suspend count\r
- * ARGUMENTS: \r
- *        ThreadHandle = Handle to the thread that should be resumed\r
- *        PreviousSuspendCount =  The resulting/previous suspend count.\r
- * REMARK:\r
- *       A thread will be suspended if its suspend count is greater than 0. \r
- *        This procedure maps to the win32 SuspendThread function. ( \r
- *        documentation about the the suspend count can be found here aswell )\r
- *        The suspend count is not increased if it is greater than \r
- *        MAXIMUM_SUSPEND_COUNT.\r
- * RETURNS: Status\r
- */ \r
-{\r
-   PETHREAD Thread;\r
-   NTSTATUS Status;\r
-   \r
-   Status = ObReferenceObjectByHandle(ThreadHandle,\r
-                                     THREAD_SUSPEND_RESUME,\r
-                                     PsThreadType,\r
-                                     UserMode,\r
-                                     (PVOID*)&Thread,\r
-                                     NULL);\r
-   if (Status != STATUS_SUCCESS)\r
-     {\r
-       return(Status);\r
-     }\r
-   \r
-   (*PreviousSuspendCount) = InterlockedIncrement(&Thread->Tcb.SuspendCount);\r
-   if (Thread->Tcb.SuspendCount > 0)\r
-     {\r
-       Thread->Tcb.ThreadState = THREAD_STATE_SUSPENDED;\r
-       if (Thread == PsGetCurrentThread())\r
-         {\r
-            PsDispatchThread();\r
-         }\r
-     }\r
-   \r
-   ObDereferenceObject(Thread);\r
-   return(STATUS_SUCCESS);\r
-}\r
-\r
-NTSTATUS STDCALL NtContinue(IN PCONTEXT Context, IN CINT IrqLevel)\r
-{\r
-   return(ZwContinue(Context,IrqLevel));\r
-}\r
-\r
-NTSTATUS STDCALL ZwContinue(IN PCONTEXT Context, IN CINT IrqLevel)\r
-{\r
-   UNIMPLEMENTED;\r
-}\r
-\r
-NTSTATUS STDCALL NtYieldExecution(VOID)\r
-{\r
-   return(ZwYieldExecution());\r
-}\r
-\r
-NTSTATUS STDCALL ZwYieldExecution(VOID)\r
-{\r
-   PsDispatchThread();\r
-   return(STATUS_SUCCESS);\r
-}\r
+/*
+ * COPYRIGHT:              See COPYING in the top level directory
+ * PROJECT:                ReactOS kernel
+ * FILE:                   ntoskrnl/ps/thread.c
+ * PURPOSE:                Thread managment
+ * PROGRAMMER:             David Welch (welch@mcmail.com)
+ * REVISION HISTORY: 
+ *               23/06/98: Created
+ */
+
+/*
+ * NOTE:
+ * 
+ * All of the routines that manipulate the thread queue synchronize on
+ * a single spinlock
+ * 
+ */
+
+/* INCLUDES ****************************************************************/
+
+#include <windows.h>
+#include <ddk/ntddk.h>
+#include <internal/ke.h>
+#include <internal/ob.h>
+#include <string.h>
+#include <internal/string.h>
+#include <internal/hal.h>
+#include <internal/ps.h>
+#include <internal/ob.h>
+
+#define NDEBUG
+#include <internal/debug.h>
+
+/* TYPES *******************************************************************/
+
+/* GLOBALS ******************************************************************/
+
+POBJECT_TYPE PsThreadType = NULL;
+
+#define NR_THREAD_PRIORITY_LEVELS (31)
+#define THREAD_PRIORITY_MAX (15)
+
+static KSPIN_LOCK ThreadListLock = {0,};
+
+/*
+ * PURPOSE: List of threads associated with each priority level
+ */
+static LIST_ENTRY PriorityListHead[NR_THREAD_PRIORITY_LEVELS]={{NULL,NULL},};
+static BOOLEAN DoneInitYet = FALSE;
+ULONG PiNrThreads = 0;
+ULONG PiNrRunnableThreads = 0;
+
+static PETHREAD CurrentThread = NULL;
+
+static ULONG NextUniqueThreadId = 0;
+
+/* FUNCTIONS ***************************************************************/
+
+PKTHREAD KeGetCurrentThread(VOID)
+{
+   return(&(CurrentThread->Tcb));
+}
+
+PETHREAD PsGetCurrentThread(VOID)
+{
+   return(CurrentThread);
+}
+
+VOID PiTerminateProcessThreads(PEPROCESS Process, NTSTATUS ExitStatus)
+{
+   KIRQL oldlvl;
+   PLIST_ENTRY current_entry;
+   PETHREAD current;
+   ULONG i;
+
+   KeAcquireSpinLock(&ThreadListLock, &oldlvl);
+
+   for (i=0; i<NR_THREAD_PRIORITY_LEVELS; i++)
+   {
+        current_entry = PriorityListHead[i].Flink;
+        while (current_entry != &PriorityListHead[i])
+        {
+             current = CONTAINING_RECORD(current_entry,ETHREAD,Tcb.Entry);
+             if (current->ThreadsProcess == Process &&
+                 current != PsGetCurrentThread())
+             {
+                  PsTerminateOtherThread(current, ExitStatus);
+             }
+             current_entry = current_entry->Flink;
+        }
+   }
+
+   KeReleaseSpinLock(&ThreadListLock, oldlvl);
+}
+
+static VOID PsInsertIntoThreadList(KPRIORITY Priority, PETHREAD Thread)
+{
+   KIRQL oldlvl;
+   
+   DPRINT("PsInsertIntoThreadList(Priority %x, Thread %x)\n",Priority,
+           Thread);
+   
+   KeAcquireSpinLock(&ThreadListLock,&oldlvl);
+   InsertTailList(&PriorityListHead[THREAD_PRIORITY_MAX+Priority],
+                 &Thread->Tcb.Entry);
+   KeReleaseSpinLock(&ThreadListLock,oldlvl);
+}
+
+VOID PsBeginThread(PKSTART_ROUTINE StartRoutine, PVOID StartContext)
+{
+   NTSTATUS Ret;
+   
+   KeReleaseSpinLock(&ThreadListLock,PASSIVE_LEVEL);
+   Ret = StartRoutine(StartContext);
+   PsTerminateSystemThread(Ret);
+   KeBugCheck(0);
+}
+
+static PETHREAD PsScanThreadList(KPRIORITY Priority)
+{
+   PLIST_ENTRY current_entry;
+   PETHREAD current;
+   PETHREAD oldest = NULL;
+   ULONG oldest_time = 0;
+   
+//   DPRINT("PsScanThreadList(Priority %d)\n",Priority);
+   
+   current_entry = PriorityListHead[THREAD_PRIORITY_MAX+Priority].Flink;
+   while (current_entry != &PriorityListHead[THREAD_PRIORITY_MAX+Priority])
+     {
+       current = CONTAINING_RECORD(current_entry,ETHREAD,Tcb.Entry);
+
+       if (current->Tcb.ThreadState == THREAD_STATE_TERMINATED &&
+           current != CurrentThread)
+         {
+            PsReleaseThread(current);
+         }
+
+       if (current->Tcb.ThreadState == THREAD_STATE_RUNNABLE)
+         {
+            if (oldest == NULL || oldest_time > current->Tcb.LastTick)
+              {
+                 oldest = current;
+                 oldest_time = current->Tcb.LastTick;
+              }
+         }
+       current_entry = current_entry->Flink;
+     }
+//   DPRINT("PsScanThreadList() = %x\n",oldest);
+   return(oldest);
+}
+
+VOID PsDispatchThread(VOID)
+{
+   KPRIORITY CurrentPriority;
+   PETHREAD Candidate;
+   KIRQL irql;
+   LARGE_INTEGER TickCount;
+   
+   KeAcquireSpinLock(&ThreadListLock,&irql);
+   
+   if (!DoneInitYet)
+     {
+       return;
+     }
+   
+   DPRINT("PsDispatchThread() Current %x\n",CurrentThread);
+      
+   if (CurrentThread->Tcb.ThreadState==THREAD_STATE_RUNNING)     
+     {
+       CurrentThread->Tcb.ThreadState=THREAD_STATE_RUNNABLE;
+     }
+   
+   for (CurrentPriority=THREAD_PRIORITY_TIME_CRITICAL; 
+       CurrentPriority>=THREAD_PRIORITY_IDLE;
+       CurrentPriority--)
+     {
+       Candidate = PsScanThreadList(CurrentPriority);
+       if (Candidate == CurrentThread)
+         {
+             DPRINT("Scheduling current thread\n");
+             KeQueryTickCount(&TickCount);
+             CurrentThread->Tcb.LastTick = TickCount.LowPart;
+            CurrentThread->Tcb.ThreadState = THREAD_STATE_RUNNING;
+            KeReleaseSpinLock(&ThreadListLock,irql);
+            return;
+         }
+       if (Candidate != NULL)
+         {     
+             DPRINT("Scheduling %x\n",Candidate);
+            
+            Candidate->Tcb.ThreadState = THREAD_STATE_RUNNING;
+            
+            KeQueryTickCount(&TickCount);
+             CurrentThread->Tcb.LastTick = TickCount.LowPart;
+            
+            CurrentThread = Candidate;
+            
+            HalTaskSwitch(&CurrentThread->Tcb);
+            KeReleaseSpinLock(&ThreadListLock,irql);
+            return;
+         }
+     }
+   DbgPrint("CRITICAL: No threads are runnable\n");
+   KeBugCheck(0);
+}
+
+NTSTATUS PsInitializeThread(HANDLE ProcessHandle, 
+                           PETHREAD* ThreadPtr,
+                           PHANDLE ThreadHandle,
+                           ACCESS_MASK DesiredAccess,
+                           POBJECT_ATTRIBUTES ThreadAttributes)
+{
+   PETHREAD Thread;
+   NTSTATUS Status;
+   
+   PiNrThreads++;
+   
+   Thread = ObCreateObject(ThreadHandle,
+                          DesiredAccess,
+                          ThreadAttributes,
+                          PsThreadType);
+   DPRINT("Thread = %x\n",Thread);
+   Thread->Tcb.LastTick = 0;
+   Thread->Tcb.ThreadState=THREAD_STATE_SUSPENDED;
+   Thread->Tcb.BasePriority=THREAD_PRIORITY_NORMAL;
+   Thread->Tcb.CurrentPriority=THREAD_PRIORITY_NORMAL;
+   Thread->Tcb.ApcList=ExAllocatePool(NonPagedPool,sizeof(LIST_ENTRY));
+   Thread->Tcb.SuspendCount = 1;
+   if (ProcessHandle != NULL)
+     {
+       Status = ObReferenceObjectByHandle(ProcessHandle,
+                                          PROCESS_CREATE_THREAD,
+                                          PsProcessType,
+                                          UserMode,
+                                          (PVOID*)&Thread->ThreadsProcess,
+                                          NULL);
+       if (Status != STATUS_SUCCESS)
+         {
+            DPRINT("Failed at %s:%d\n",__FILE__,__LINE__);
+            return(Status);
+         }
+     }
+   else
+     {
+       Thread->ThreadsProcess = SystemProcess;
+       ObReferenceObjectByPointer(Thread->ThreadsProcess,
+                                  PROCESS_CREATE_THREAD,
+                                  PsProcessType,
+                                  UserMode);
+     }
+   ObReferenceObjectByPointer(Thread->ThreadsProcess,
+                             PROCESS_CREATE_THREAD,
+                             PsProcessType,
+                             UserMode);
+   InitializeListHead(Thread->Tcb.ApcList);
+   InitializeListHead(&(Thread->IrpList));
+   Thread->Cid.UniqueThread = (HANDLE)InterlockedIncrement(
+                                                          &NextUniqueThreadId);
+   Thread->Cid.UniqueProcess = (HANDLE)Thread->ThreadsProcess->UniqueProcessId;
+   DbgPrint("Thread->Cid.UniqueThread %d\nThread->Cid.UniqueProcess %d\n",
+            Thread->Cid.UniqueThread, Thread->Cid.UniqueThread);
+   ObReferenceObjectByPointer(Thread,
+                             THREAD_ALL_ACCESS,
+                             PsThreadType,
+                             UserMode);
+   PsInsertIntoThreadList(Thread->Tcb.CurrentPriority,Thread);
+   
+   *ThreadPtr = Thread;
+   
+   ObDereferenceObject(Thread->ThreadsProcess);
+   return(STATUS_SUCCESS);
+}
+
+VOID PsResumeThread(PETHREAD Thread)
+{
+   DPRINT("PsResumeThread(Thread %x)\n",Thread);
+   Thread->Tcb.SuspendCount--;
+   if (Thread->Tcb.SuspendCount <= 0 &&
+       Thread->Tcb.ThreadState != THREAD_STATE_RUNNING)
+     {
+        DPRINT("Setting thread to runnable\n");
+       Thread->Tcb.ThreadState = THREAD_STATE_RUNNABLE;
+     }
+   DPRINT("Finished PsResumeThread()\n");
+}
+
+VOID PsSuspendThread(PETHREAD Thread)
+{
+   DPRINT("PsSuspendThread(Thread %x)\n",Thread);
+   Thread->Tcb.SuspendCount++;
+   if (Thread->Tcb.SuspendCount > 0)
+     {
+       Thread->Tcb.ThreadState = THREAD_STATE_SUSPENDED;
+       if (Thread == CurrentThread)
+         {
+            PsDispatchThread();
+         }
+     }
+}
+
+VOID PiDeleteThread(PVOID ObjectBody)
+{
+   DbgPrint("PiDeleteThread(ObjectBody %x)\n",ObjectBody);
+}
+
+VOID PsInitThreadManagment(VOID)
+/*
+ * FUNCTION: Initialize thread managment
+ */
+{
+   PETHREAD FirstThread;
+   ULONG i;
+   ANSI_STRING AnsiString;
+   HANDLE FirstThreadHandle;
+   
+   KeInitializeSpinLock(&ThreadListLock);
+   for (i=0; i<NR_THREAD_PRIORITY_LEVELS; i++)
+     {
+       InitializeListHead(&PriorityListHead[i]);
+     }
+   
+   PsThreadType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
+   
+   RtlInitAnsiString(&AnsiString,"Thread");
+   RtlAnsiStringToUnicodeString(&PsThreadType->TypeName,&AnsiString,TRUE);
+   
+   PsThreadType->TotalObjects = 0;
+   PsThreadType->TotalHandles = 0;
+   PsThreadType->MaxObjects = 0;
+   PsThreadType->MaxHandles = 0;
+   PsThreadType->PagedPoolCharge = 0;
+   PsThreadType->NonpagedPoolCharge = sizeof(ETHREAD);
+   PsThreadType->Dump = NULL;
+   PsThreadType->Open = NULL;
+   PsThreadType->Close = NULL;
+   PsThreadType->Delete = PiDeleteThread;
+   PsThreadType->Parse = NULL;
+   PsThreadType->Security = NULL;
+   PsThreadType->QueryName = NULL;
+   PsThreadType->OkayToClose = NULL;
+   
+   PsInitializeThread(NULL,&FirstThread,&FirstThreadHandle,
+                     THREAD_ALL_ACCESS,NULL);
+   HalInitFirstTask(FirstThread);
+   FirstThread->Tcb.ThreadState = THREAD_STATE_RUNNING;
+   FirstThread->Tcb.SuspendCount = 0;
+
+   DPRINT("FirstThread %x\n",FirstThread);
+   
+   CurrentThread = FirstThread;
+   
+   DoneInitYet = TRUE;
+}
+
+NTSTATUS NtCreateThread(PHANDLE ThreadHandle,
+                       ACCESS_MASK DesiredAccess,
+                       POBJECT_ATTRIBUTES ObjectAttributes,
+                       HANDLE ProcessHandle,
+                       PCLIENT_ID Client,
+                       PCONTEXT ThreadContext,
+                       PINITIAL_TEB InitialTeb,
+                       BOOLEAN CreateSuspended)
+{
+   return(ZwCreateThread(ThreadHandle,
+                        DesiredAccess,
+                        ObjectAttributes,
+                        ProcessHandle,
+                        Client,
+                        ThreadContext,
+                        InitialTeb,
+                        CreateSuspended));
+}
+
+NTSTATUS ZwCreateThread(PHANDLE ThreadHandle,
+                       ACCESS_MASK DesiredAccess,
+                       POBJECT_ATTRIBUTES ObjectAttributes,
+                       HANDLE ProcessHandle,
+                       PCLIENT_ID Client,
+                       PCONTEXT ThreadContext,
+                       PINITIAL_TEB InitialTeb,
+                       BOOLEAN CreateSuspended)
+{
+   PETHREAD Thread;
+   NTSTATUS Status;
+   
+   DPRINT("ZwCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
+         ThreadHandle,ThreadContext);
+   
+   Status = PsInitializeThread(ProcessHandle,&Thread,ThreadHandle,
+                              DesiredAccess,ObjectAttributes);
+   if (!NT_SUCCESS(Status))
+     {
+       return(Status);
+     }
+   
+   Status = HalInitTaskWithContext(Thread,ThreadContext);
+   if (!NT_SUCCESS(Status))
+     {
+       return(Status);
+     }
+   Thread->StartAddress=NULL;
+
+   if (Client!=NULL)
+     {
+       *Client=Thread->Cid;
+     }  
+   
+   if (!CreateSuspended)
+     {
+        DPRINT("Not creating suspended\n");
+       PsResumeThread(Thread);
+     }
+   DPRINT("Finished PsCreateThread()\n");
+   return(STATUS_SUCCESS);
+}
+
+NTSTATUS PsCreateSystemThread(PHANDLE ThreadHandle,
+                             ACCESS_MASK DesiredAccess,
+                             POBJECT_ATTRIBUTES ObjectAttributes,
+                             HANDLE ProcessHandle,
+                             PCLIENT_ID ClientId,
+                             PKSTART_ROUTINE StartRoutine,
+                             PVOID StartContext)
+/*
+ * FUNCTION: Creates a thread which executes in kernel mode
+ * ARGUMENTS:
+ *       ThreadHandle (OUT) = Caller supplied storage for the returned thread 
+ *                            handle
+ *       DesiredAccess = Requested access to the thread
+ *       ObjectAttributes = Object attributes (optional)
+ *       ProcessHandle = Handle of process thread will run in
+ *                       NULL to use system process
+ *       ClientId (OUT) = Caller supplied storage for the returned client id
+ *                        of the thread (optional)
+ *       StartRoutine = Entry point for the thread
+ *       StartContext = Argument supplied to the thread when it begins
+ *                     execution
+ * RETURNS: Success or failure status
+ */
+{
+   PETHREAD Thread;
+   NTSTATUS Status;
+   
+   DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
+           ThreadHandle,ProcessHandle);
+   
+   Status = PsInitializeThread(ProcessHandle,&Thread,ThreadHandle,
+                              DesiredAccess,ObjectAttributes);
+   if (!NT_SUCCESS(Status))
+     {
+       return(Status);
+     }
+   
+   Thread->StartAddress=StartRoutine;
+   Status = HalInitTask(Thread,StartRoutine,StartContext);
+   if (!NT_SUCCESS(Status))
+     {
+       return(Status);
+     }
+
+   if (ClientId!=NULL)
+     {
+       *ClientId=Thread->Cid;
+     }  
+
+   PsResumeThread(Thread);
+   
+   return(STATUS_SUCCESS);
+}
+
+LONG KeSetBasePriorityThread(PKTHREAD Thread, LONG Increment)
+{
+   UNIMPLEMENTED;
+}
+
+KPRIORITY KeSetPriorityThread(PKTHREAD Thread, KPRIORITY Priority)
+{
+   KPRIORITY OldPriority;
+   OldPriority = Thread->CurrentPriority;
+   Thread->CurrentPriority = Priority;
+
+   RemoveEntryList(&Thread->Entry);
+   PsInsertIntoThreadList(Thread->CurrentPriority,
+                         CONTAINING_RECORD(Thread,ETHREAD,Tcb));
+   
+   return(OldPriority);
+}
+
+NTSTATUS STDCALL NtAlertResumeThread(IN HANDLE ThreadHandle,
+                                    OUT PULONG SuspendCount)
+{
+   return(ZwAlertResumeThread(ThreadHandle,SuspendCount));
+}
+
+NTSTATUS STDCALL ZwAlertResumeThread(IN HANDLE ThreadHandle,
+                                    OUT PULONG SuspendCount)
+{
+   UNIMPLEMENTED;
+}
+
+NTSTATUS STDCALL NtAlertThread(IN HANDLE ThreadHandle)
+{
+   return(ZwAlertThread(ThreadHandle));
+}
+
+NTSTATUS STDCALL ZwAlertThread(IN HANDLE ThreadHandle)
+{
+   UNIMPLEMENTED;
+}
+
+NTSTATUS STDCALL NtGetContextThread(IN HANDLE ThreadHandle, 
+                                   OUT PCONTEXT Context)
+{
+   return(ZwGetContextThread(ThreadHandle,Context));
+}
+
+NTSTATUS STDCALL ZwGetContextThread(IN HANDLE ThreadHandle, 
+                                   OUT PCONTEXT Context)
+{
+   UNIMPLEMENTED;
+}
+
+NTSTATUS STDCALL NtOpenThread(OUT PHANDLE ThreadHandle,
+                             IN ACCESS_MASK DesiredAccess,
+                             IN POBJECT_ATTRIBUTES ObjectAttributes,
+                             IN PCLIENT_ID ClientId)
+{
+   return(ZwOpenThread(ThreadHandle,
+                      DesiredAccess,
+                      ObjectAttributes,
+                      ClientId));
+}
+
+NTSTATUS STDCALL ZwOpenThread(OUT PHANDLE ThreadHandle,
+                             IN ACCESS_MASK DesiredAccess,
+                             IN POBJECT_ATTRIBUTES ObjectAttributes,
+                             IN PCLIENT_ID ClientId)
+{
+   UNIMPLEMENTED;
+}
+
+NTSTATUS STDCALL NtResumeThread(IN HANDLE ThreadHandle,
+                               IN PULONG SuspendCount)
+{
+   return(ZwResumeThread(ThreadHandle,SuspendCount));
+}
+
+NTSTATUS STDCALL ZwResumeThread(IN HANDLE ThreadHandle,
+                               IN PULONG SuspendCount)
+/*
+ * FUNCTION: Decrements a thread's resume count
+ * ARGUMENTS: 
+ *        ThreadHandle = Handle to the thread that should be resumed
+ *        ResumeCount =  The resulting resume count.
+ * REMARK:
+ *       A thread is resumed if its suspend count is 0. This procedure maps to
+ *        the win32 ResumeThread function. ( documentation about the the suspend count can be found here aswell )
+ * RETURNS: Status
+ */
+{
+   PETHREAD Thread;
+   NTSTATUS Status;
+   
+   Status = ObReferenceObjectByHandle(ThreadHandle,
+                                     THREAD_SUSPEND_RESUME,
+                                     PsThreadType,
+                                     UserMode,
+                                     (PVOID*)&Thread,
+                                     NULL);
+   if (Status != STATUS_SUCCESS)
+     {
+       return(Status);
+     }
+   
+   (*SuspendCount) = InterlockedDecrement(&Thread->Tcb.SuspendCount);
+   if (Thread->Tcb.SuspendCount <= 0)
+     {
+       Thread->Tcb.ThreadState = THREAD_STATE_RUNNABLE;
+     }
+   
+   ObDereferenceObject(Thread);
+   return(STATUS_SUCCESS);
+}
+
+NTSTATUS STDCALL NtSetContextThread(IN HANDLE ThreadHandle,
+                                   IN PCONTEXT Context)
+{
+   return(ZwSetContextThread(ThreadHandle,Context));
+}
+
+NTSTATUS STDCALL ZwSetContextThread(IN HANDLE ThreadHandle,
+                                   IN PCONTEXT Context)
+{
+   UNIMPLEMENTED;
+}
+
+NTSTATUS STDCALL NtSuspendThread(IN HANDLE ThreadHandle,
+                                IN PULONG PreviousSuspendCount)
+{
+   return(ZwSuspendThread(ThreadHandle,PreviousSuspendCount));
+}
+
+NTSTATUS STDCALL ZwSuspendThread(IN HANDLE ThreadHandle,
+                                IN PULONG PreviousSuspendCount)
+/*
+ * FUNCTION: Increments a thread's suspend count
+ * ARGUMENTS: 
+ *        ThreadHandle = Handle to the thread that should be resumed
+ *        PreviousSuspendCount =  The resulting/previous suspend count.
+ * REMARK:
+ *       A thread will be suspended if its suspend count is greater than 0. 
+ *        This procedure maps to the win32 SuspendThread function. ( 
+ *        documentation about the the suspend count can be found here aswell )
+ *        The suspend count is not increased if it is greater than 
+ *        MAXIMUM_SUSPEND_COUNT.
+ * RETURNS: Status
+ */ 
+{
+   PETHREAD Thread;
+   NTSTATUS Status;
+   
+   Status = ObReferenceObjectByHandle(ThreadHandle,
+                                     THREAD_SUSPEND_RESUME,
+                                     PsThreadType,
+                                     UserMode,
+                                     (PVOID*)&Thread,
+                                     NULL);
+   if (Status != STATUS_SUCCESS)
+     {
+       return(Status);
+     }
+   
+   (*PreviousSuspendCount) = InterlockedIncrement(&Thread->Tcb.SuspendCount);
+   if (Thread->Tcb.SuspendCount > 0)
+     {
+       Thread->Tcb.ThreadState = THREAD_STATE_SUSPENDED;
+       if (Thread == PsGetCurrentThread())
+         {
+            PsDispatchThread();
+         }
+     }
+   
+   ObDereferenceObject(Thread);
+   return(STATUS_SUCCESS);
+}
+
+NTSTATUS STDCALL NtContinue(IN PCONTEXT Context, IN CINT IrqLevel)
+{
+   return(ZwContinue(Context,IrqLevel));
+}
+
+NTSTATUS STDCALL ZwContinue(IN PCONTEXT Context, IN CINT IrqLevel)
+{
+   UNIMPLEMENTED;
+}
+
+NTSTATUS STDCALL NtYieldExecution(VOID)
+{
+   return(ZwYieldExecution());
+}
+
+NTSTATUS STDCALL ZwYieldExecution(VOID)
+{
+   PsDispatchThread();
+   return(STATUS_SUCCESS);
+}