update for HEAD-2003091401
[reactos.git] / ntoskrnl / ps / thread.c
index 35d772e..b99447b 100644 (file)
@@ -45,6 +45,7 @@ KSPIN_LOCK PiThreadListLock;
  */
 LIST_ENTRY PiThreadListHead;
 static LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY];
+static ULONG PriorityListMask = 0;
 static BOOLEAN DoneInitYet = FALSE;
 static PETHREAD IdleThreads[MAXIMUM_PROCESSORS];
 ULONG PiNrThreads = 0;
@@ -61,28 +62,48 @@ static GENERIC_MAPPING PiThreadMapping = {THREAD_READ,
 
 /* FUNCTIONS ***************************************************************/
 
+/*
+ * @implemented
+ */
 PKTHREAD STDCALL KeGetCurrentThread(VOID)
 {
-   return(KeGetCurrentKPCR()->CurrentThread);
+   return(((PIKPCR) KeGetCurrentKPCR())->CurrentThread);
 }
 
+/*
+ * @implemented
+ */
 HANDLE STDCALL PsGetCurrentThreadId(VOID)
 {
    return(PsGetCurrentThread()->Cid.UniqueThread);
 }
 
-VOID 
+static VOID 
 PsInsertIntoThreadList(KPRIORITY Priority, PETHREAD Thread)
 {
-   if (Priority >= MAXIMUM_PRIORITY || Priority < 0)
+   assert(THREAD_STATE_READY == Thread->Tcb.State);
+   if (Priority >= MAXIMUM_PRIORITY || Priority < LOW_PRIORITY)
      {
-       DPRINT1("Invalid thread priority\n");
-       KeBugCheck(0);
+       DPRINT1("Invalid thread priority (%d)\n", Priority);
+       KEBUGCHECK(0);
      }
    InsertTailList(&PriorityListHead[Priority], &Thread->Tcb.QueueListEntry);
+   PriorityListMask |= (1 << Priority);
    PiNrReadyThreads++;
 }
 
+static VOID PsRemoveFromThreadList(PETHREAD Thread)
+{
+   assert(THREAD_STATE_READY == Thread->Tcb.State);
+   RemoveEntryList(&Thread->Tcb.QueueListEntry);
+   if (IsListEmpty(&PriorityListHead[(ULONG)Thread->Tcb.Priority]))
+     {
+        PriorityListMask &= ~(1 << Thread->Tcb.Priority);
+     }
+   PiNrReadyThreads--;
+}
+
+
 VOID PsDumpThreads(BOOLEAN IncludeSystem)
 {
    PLIST_ENTRY current_entry;
@@ -142,22 +163,31 @@ static PETHREAD PsScanThreadList (KPRIORITY Priority, ULONG Affinity)
 {
    PLIST_ENTRY current_entry;
    PETHREAD current;
+   ULONG Mask;
 
-   current_entry = PriorityListHead[Priority].Flink;
-   while (current_entry != &PriorityListHead[Priority])
+   Mask = (1 << Priority);
+   if (PriorityListMask & Mask)
      {
-       current = CONTAINING_RECORD(current_entry, ETHREAD,
-                                  Tcb.QueueListEntry);
-       assert(current->Tcb.State == THREAD_STATE_READY);
-       DPRINT("current->Tcb.UserAffinity %x Affinity %x PID %d %d\n",
-              current->Tcb.UserAffinity, Affinity, current->Cid.UniqueThread,
-              Priority);
-       if (current->Tcb.UserAffinity & Affinity)
-        {
-          RemoveEntryList(&current->Tcb.QueueListEntry);
-          return(current);
+       current_entry = PriorityListHead[Priority].Flink;
+       while (current_entry != &PriorityListHead[Priority])
+         {
+           current = CONTAINING_RECORD(current_entry, ETHREAD,
+                                      Tcb.QueueListEntry);
+          if (current->Tcb.State != THREAD_STATE_READY)
+            {
+              DPRINT1("%d/%d\n", current->Cid.UniqueThread, current->Tcb.State);
+            }
+           assert(current->Tcb.State == THREAD_STATE_READY);
+           DPRINT("current->Tcb.UserAffinity %x Affinity %x PID %d %d\n",
+                 current->Tcb.UserAffinity, Affinity, current->Cid.UniqueThread,
+                 Priority);
+           if (current->Tcb.UserAffinity & Affinity)
+            {
+              PsRemoveFromThreadList(current);
+              return(current);
+            }
+           current_entry = current_entry->Flink;
         }
-       current_entry = current_entry->Flink;
      }
    return(NULL);
 }
@@ -191,16 +221,15 @@ VOID PsDispatchThreadNoLock (ULONG NewThreadStatus)
    KPRIORITY CurrentPriority;
    PETHREAD Candidate;
    ULONG Affinity;
-   PKTHREAD KCurrentThread = KeGetCurrentKPCR()->CurrentThread;
+   PKTHREAD KCurrentThread = ((PIKPCR) KeGetCurrentKPCR())->CurrentThread;
    PETHREAD CurrentThread = CONTAINING_RECORD(KCurrentThread, ETHREAD, Tcb);
 
-   DPRINT("PsDispatchThread() %d/%d\n", KeGetCurrentProcessorNumber(),
-          CurrentThread->Cid.UniqueThread);
+   DPRINT("PsDispatchThread() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
+          CurrentThread->Cid.UniqueThread, NewThreadStatus, CurrentThread->Tcb.State);
    
    CurrentThread->Tcb.State = NewThreadStatus;
    if (CurrentThread->Tcb.State == THREAD_STATE_READY)
      {
-       PiNrReadyThreads++;
        PsInsertIntoThreadList(CurrentThread->Tcb.Priority,
                               CurrentThread);
      }
@@ -217,6 +246,7 @@ VOID PsDispatchThreadNoLock (ULONG NewThreadStatus)
        Candidate = PsScanThreadList(CurrentPriority, Affinity);
        if (Candidate == CurrentThread)
          {
+            Candidate->Tcb.State = THREAD_STATE_RUNNING;
             KeReleaseSpinLockFromDpcLevel(&PiThreadListLock);
             return;
          }
@@ -230,18 +260,23 @@ VOID PsDispatchThreadNoLock (ULONG NewThreadStatus)
            
            OldThread = CurrentThread;
            CurrentThread = Candidate;
-            
+#if 0      
+            /*
+            * This code is moved to the end of KiArchContextSwitch.
+            * It should be execute after the context switch.
+            */
            KeReleaseSpinLockFromDpcLevel(&PiThreadListLock);
            if (PiNrThreadsAwaitingReaping > 0)
              {
                PiWakeupReaperThread();
              }
+#endif 
            KiArchContextSwitch(&CurrentThread->Tcb, &OldThread->Tcb);
            return;
          }
      }
    CPRINT("CRITICAL: No threads are ready\n");
-   KeBugCheck(0);
+   KEBUGCHECK(0);
 }
 
 VOID STDCALL
@@ -258,7 +293,7 @@ PsDispatchThread(ULONG NewThreadStatus)
    /*
     * Save wait IRQL
     */
-   KeGetCurrentKPCR()->CurrentThread->WaitIrql = oldIrql;   
+   ((PIKPCR) KeGetCurrentKPCR())->CurrentThread->WaitIrql = oldIrql;   
    PsDispatchThreadNoLock(NewThreadStatus);
    KeLowerIrql(oldIrql);
 }
@@ -269,12 +304,27 @@ PsUnblockThread(PETHREAD Thread, PNTSTATUS WaitStatus)
   KIRQL oldIrql;
 
   KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
-  if (WaitStatus != NULL)
+  if (THREAD_STATE_TERMINATED_1 == Thread->Tcb.State || 
+      THREAD_STATE_TERMINATED_2 == Thread->Tcb.State)
     {
-      Thread->Tcb.WaitStatus = *WaitStatus;
+       DPRINT("Can't unblock thread %d because it's terminating\n", 
+              Thread->Cid.UniqueThread);
+    }
+  else if (THREAD_STATE_READY == Thread->Tcb.State ||
+           THREAD_STATE_RUNNING == Thread->Tcb.State)
+    {
+       DPRINT("Can't unblock thread %d because it's ready or running\n", 
+              Thread->Cid.UniqueThread);
+    }
+  else
+    {
+      if (WaitStatus != NULL)
+       {
+         Thread->Tcb.WaitStatus = *WaitStatus;
+       }
+      Thread->Tcb.State = THREAD_STATE_READY;
+      PsInsertIntoThreadList(Thread->Tcb.Priority, Thread);
     }
-  Thread->Tcb.State = THREAD_STATE_READY;
-  PsInsertIntoThreadList(Thread->Tcb.Priority, Thread);
   KeReleaseSpinLock(&PiThreadListLock, oldIrql);
 }
 
@@ -283,12 +333,14 @@ PsBlockThread(PNTSTATUS Status, UCHAR Alertable, ULONG WaitMode,
              BOOLEAN DispatcherLock, KIRQL WaitIrql, UCHAR WaitReason)
 {
   KIRQL oldIrql;
-  PKTHREAD KThread = KeGetCurrentKPCR()->CurrentThread;
-  PETHREAD Thread = CONTAINING_RECORD (KThread, ETHREAD, Tcb);
+  PKTHREAD KThread;
+  PETHREAD Thread;
   PKWAIT_BLOCK WaitBlock;
 
   KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
 
+  KThread = ((PIKPCR) KeGetCurrentKPCR())->CurrentThread;
+  Thread = CONTAINING_RECORD (KThread, ETHREAD, Tcb);
   if (KThread->ApcState.KernelApcPending)
   {
     if (!DispatcherLock)
@@ -362,7 +414,7 @@ PsFreezeAllThreads(PEPROCESS Process)
 VOID
 PsApplicationProcessorInit(VOID)
 {
-  KeGetCurrentKPCR()->CurrentThread = 
+  ((PIKPCR) KeGetCurrentKPCR())->CurrentThread = 
     (PVOID)IdleThreads[KeGetCurrentProcessorNumber()];
 }
 
@@ -435,7 +487,7 @@ PsInitThreadManagment(VOID)
                      THREAD_ALL_ACCESS,NULL, TRUE);
    FirstThread->Tcb.State = THREAD_STATE_RUNNING;
    FirstThread->Tcb.FreezeCount = 0;
-   KeGetCurrentKPCR()->CurrentThread = (PVOID)FirstThread;
+   ((PIKPCR) KeGetCurrentKPCR())->CurrentThread = (PVOID)FirstThread;
    NtClose(FirstThreadHandle);
    
    DPRINT("FirstThread %x\n",FirstThread);
@@ -451,15 +503,18 @@ PsInitThreadManagment(VOID)
                                 NULL,
                                 NULL,
                                 NULL,
-                                PiReaperThreadMain,
+                                (PKSTART_ROUTINE) PiReaperThreadMain,
                                 NULL);
    if (!NT_SUCCESS(Status))
      {
        DPRINT1("PS: Failed to create reaper thread.\n");
-       KeBugCheck(0);
+       KEBUGCHECK(0);
      }
 }
 
+/*
+ * @implemented
+ */
 LONG STDCALL
 KeSetBasePriorityThread (PKTHREAD      Thread,
                         LONG           Increment)
@@ -468,45 +523,89 @@ KeSetBasePriorityThread (PKTHREAD Thread,
  * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
  */
 {
-   Thread->BasePriority = 
-     ((PETHREAD)Thread)->ThreadsProcess->Pcb.BasePriority + Increment;
-   if (Thread->BasePriority < LOW_PRIORITY)
-     Thread->BasePriority = LOW_PRIORITY;
-   else if (Thread->BasePriority >= MAXIMUM_PRIORITY)
-          Thread->BasePriority = HIGH_PRIORITY;
-   Thread->Priority = Thread->BasePriority;
+   KPRIORITY Priority;
+   if (Increment < -2)
+     {
+       Increment = -2;
+     }
+   else if (Increment > 2)
+     {
+       Increment = 2;
+     }
+   Priority = ((PETHREAD)Thread)->ThreadsProcess->Pcb.BasePriority + Increment;
+   if (Priority < LOW_PRIORITY)
+   {
+     Priority = LOW_PRIORITY;
+   }
+   else if (Priority >= MAXIMUM_PRIORITY)
+     {
+       Thread->BasePriority = HIGH_PRIORITY;
+     }
+   KeSetPriorityThread(Thread, Priority);
    return 1;
 }
 
 
+/*
+ * @implemented
+ */
 KPRIORITY STDCALL
 KeSetPriorityThread (PKTHREAD Thread, KPRIORITY Priority)
 {
    KPRIORITY OldPriority;
    KIRQL oldIrql;
+   PKTHREAD CurrentThread;
+   ULONG Mask;
    
-   if (Priority < 0 || Priority >= MAXIMUM_PRIORITY)
+   if (Priority < LOW_PRIORITY || Priority >= MAXIMUM_PRIORITY)
      {
-       KeBugCheck(0);
+       KEBUGCHECK(0);
      }
    
+   KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
+
    OldPriority = Thread->Priority;
-   Thread->Priority = (CHAR)Priority;
+   Thread->BasePriority = Thread->Priority = (CHAR)Priority;
 
-   KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
-   if (Thread->State == THREAD_STATE_READY)
-    {
-       RemoveEntryList(&Thread->QueueListEntry);
-       PsInsertIntoThreadList(Thread->BasePriority, 
-                              CONTAINING_RECORD(Thread,ETHREAD,Tcb));
+   if (OldPriority != Priority)
+     {
+       if (Thread->State == THREAD_STATE_READY)
+         {
+          PsRemoveFromThreadList((PETHREAD)Thread);
+          PsInsertIntoThreadList(Priority, (PETHREAD)Thread);
+          CurrentThread = ((PIKPCR) KeGetCurrentKPCR())->CurrentThread;
+          if (CurrentThread->Priority < Priority)
+            {
+               PsDispatchThreadNoLock(THREAD_STATE_READY);
+               KeLowerIrql(oldIrql);
+              return (OldPriority);
+            }
+        }
+       else if (Thread->State == THREAD_STATE_RUNNING)
+         {
+          if (Priority < OldPriority)
+            {
+              /* Check for threads with a higher priority */
+              Mask = ~((1 << (Priority + 1)) - 1);
+              if (PriorityListMask & Mask)
+                {
+                   PsDispatchThreadNoLock(THREAD_STATE_READY);
+                   KeLowerIrql(oldIrql);
+                  return (OldPriority);
+                }
+            }
+        }
      }
    KeReleaseSpinLock(&PiThreadListLock, oldIrql);
    return(OldPriority);
 }
 
+/*
+ * @unimplemented
+ */
 NTSTATUS STDCALL
 KeSetAffinityThread(PKTHREAD   Thread,
-                                       PVOID           AfMask)
+                   PVOID       AfMask)
 /*
  * Sets thread's affinity
  */
@@ -549,13 +648,71 @@ NTSTATUS STDCALL NtAlertThread (IN HANDLE ThreadHandle)
    return(STATUS_SUCCESS);
 }
 
+/**********************************************************************
+ *     NtOpenThread/4
+ *
+ *     @implemented
+ */
 NTSTATUS STDCALL 
 NtOpenThread(OUT PHANDLE ThreadHandle,
             IN ACCESS_MASK DesiredAccess,
             IN POBJECT_ATTRIBUTES ObjectAttributes,
             IN PCLIENT_ID ClientId)
 {
-       UNIMPLEMENTED;
+   NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+   if((NULL != ThreadHandle)&&(NULL != ObjectAttributes))
+   {
+      PETHREAD EThread = NULL;
+
+      if((ClientId)
+       && (ClientId->UniqueProcess)
+       && (ClientId->UniqueThread))
+      {
+         // It is an error to specify both
+        // ObjectAttributes.ObjectName
+         // and ClientId.
+         if((ObjectAttributes)
+          && (ObjectAttributes->ObjectName)
+          && (0 < ObjectAttributes->ObjectName->Length))
+        {
+            return(STATUS_INVALID_PARAMETER_MIX);
+        }
+        // Parameters mix OK
+        Status = PsLookupProcessThreadByCid(ClientId,
+                     NULL,
+                     & EThread);
+      }
+      else if((ObjectAttributes)
+            && (ObjectAttributes->ObjectName)
+            && (0 < ObjectAttributes->ObjectName->Length))
+      {
+         // Three Ob attributes are forbidden
+         if(!(ObjectAttributes->Attributes &
+            (OBJ_PERMANENT | OBJ_EXCLUSIVE | OBJ_OPENIF)))
+        {
+            Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
+                        ObjectAttributes->Attributes,
+                        NULL,
+                        DesiredAccess,
+                        PsThreadType,
+                        UserMode,
+                        NULL,
+                        (PVOID*) & EThread);
+        }
+      }
+      // EThread may be OK...
+      if(STATUS_SUCCESS == Status)
+      {
+         Status = ObCreateHandle(PsGetCurrentProcess(),
+                     EThread,
+                     DesiredAccess,
+                     FALSE,
+                     ThreadHandle);
+         ObDereferenceObject(EThread); 
+      }
+   }
+   return(Status);  
 }
 
 NTSTATUS STDCALL 
@@ -573,7 +730,7 @@ NtContinue(IN PCONTEXT      Context,
    if (TrapFrame == NULL)
      {
        CPRINT("NtContinue called but TrapFrame was NULL\n");
-       KeBugCheck(0);
+       KEBUGCHECK(0);
      }
    KeContextToTrapFrame(Context, TrapFrame);
    return(STATUS_SUCCESS);
@@ -588,6 +745,9 @@ NtYieldExecution(VOID)
 }
 
 
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
                           OUT PEPROCESS *Process OPTIONAL,
@@ -630,6 +790,9 @@ PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
 }
 
 
+/*
+ * @implemented
+ */
 NTSTATUS STDCALL
 PsLookupThreadByThreadId(IN PVOID ThreadId,
                         OUT PETHREAD *Thread)