- Update to r53061
[reactos.git] / dll / win32 / kernel32 / client / thread.c
similarity index 75%
rename from dll/win32/kernel32/thread/thread.c
rename to dll/win32/kernel32/client/thread.c
index 055342a..13975df 100644 (file)
@@ -52,22 +52,34 @@ WINAPI
 BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
                   LPVOID lpParameter)
 {
-    volatile UINT uExitCode = 0;
-
     /* Attempt to call the Thread Start Address */
     _SEH2_TRY
     {
+        /* Legacy check which is still used today for Win32 threads */
+        if (NtCurrentTeb()->NtTib.Version == (30 << 8)) // OS/2 V3.0 ("Cruiser")
+        {
+            /* This registers the termination port with CSRSS */
+            if (!BaseRunningInServerProcess) CsrNewThread();
+        }
+
         /* Get the exit code from the Thread Start */
-        uExitCode = (lpStartAddress)((PVOID)lpParameter);
+        ExitThread((lpStartAddress)((PVOID)lpParameter));
     }
     _SEH2_EXCEPT(BaseThreadExceptionFilter(_SEH2_GetExceptionInformation()))
     {
         /* Get the Exit code from the SEH Handler */
-        uExitCode = _SEH2_GetExceptionCode();
-    } _SEH2_END;
-
-    /* Exit the Thread */
-    ExitThread(uExitCode);
+        if (!BaseRunningInServerProcess)
+        {
+            /* Kill the whole process, usually */
+            ExitProcess(_SEH2_GetExceptionCode());
+        }
+        else
+        {
+            /* If running inside CSRSS, kill just this thread */
+            ExitThread(_SEH2_GetExceptionCode());
+        }
+    }
+    _SEH2_END;
 }
 
 /*
@@ -132,7 +144,7 @@ CreateRemoteThread(HANDLE hProcess,
                               &InitialTeb);
     if(!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return NULL;
     }
 
@@ -160,7 +172,7 @@ CreateRemoteThread(HANDLE hProcess,
     if(!NT_SUCCESS(Status))
     {
         BasepFreeStack(hProcess, &InitialTeb);
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return NULL;
     }
 
@@ -230,7 +242,7 @@ CreateRemoteThread(HANDLE hProcess,
     {
         ASSERT(FALSE);
     }
-    
+
     /* Success */
     if(lpThreadId) *lpThreadId = HandleToUlong(ClientId.UniqueThread);
 
@@ -310,7 +322,7 @@ OpenThread(DWORD dwDesiredAccess,
                           &ClientId);
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return NULL;
     }
 
@@ -368,7 +380,7 @@ GetThreadTimes(HANDLE hThread,
                                       NULL);
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return(FALSE);
     }
 
@@ -392,7 +404,7 @@ GetThreadContext(HANDLE hThread,
     Status = NtGetContextThread(hThread, lpContext);
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return FALSE;
     }
 
@@ -412,7 +424,7 @@ SetThreadContext(HANDLE hThread,
     Status = NtSetContextThread(hThread, (PCONTEXT)lpContext);
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return FALSE;
     }
 
@@ -437,7 +449,7 @@ GetExitCodeThread(HANDLE hThread,
                                       NULL);
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return(FALSE);
     }
 
@@ -458,7 +470,7 @@ ResumeThread(HANDLE hThread)
     Status = NtResumeThread(hThread, &PreviousResumeCount);
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return -1;
     }
 
@@ -484,7 +496,7 @@ TerminateThread(HANDLE hThread,
     Status = NtTerminateThread(hThread, dwExitCode);
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return FALSE;
     }
 
@@ -504,7 +516,7 @@ SuspendThread(HANDLE hThread)
     Status = NtSuspendThread(hThread, &PreviousSuspendCount);
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return -1;
     }
 
@@ -532,7 +544,7 @@ SetThreadAffinityMask(HANDLE hThread,
                                       NULL);
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return 0;
     }
 
@@ -542,7 +554,7 @@ SetThreadAffinityMask(HANDLE hThread,
                                     sizeof(KAFFINITY));
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         ThreadBasic.AffinityMask = 0;
     }
 
@@ -578,7 +590,7 @@ SetThreadPriority(HANDLE hThread,
     if (!NT_SUCCESS(Status))
     {
         /* Failure */
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return FALSE;
     }
 
@@ -605,17 +617,19 @@ GetThreadPriority(HANDLE hThread)
     if (!NT_SUCCESS(Status))
     {
         /* Failure */
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return THREAD_PRIORITY_ERROR_RETURN;
     }
 
-    /* Do some conversions for out of boundary values */
-    if (ThreadBasic.BasePriority > THREAD_BASE_PRIORITY_MAX)
+    /* Do some conversions for saturation values */
+    if (ThreadBasic.BasePriority == ((HIGH_PRIORITY + 1) / 2))
     {
+        /* Win32 calls this "time critical" */
         ThreadBasic.BasePriority = THREAD_PRIORITY_TIME_CRITICAL;
     }
-    else if (ThreadBasic.BasePriority < THREAD_BASE_PRIORITY_MIN)
+    else if (ThreadBasic.BasePriority == -((HIGH_PRIORITY + 1) / 2))
     {
+        /* Win32 calls this "idle" */
         ThreadBasic.BasePriority = THREAD_PRIORITY_IDLE;
     }
 
@@ -641,7 +655,7 @@ GetThreadPriorityBoost(IN HANDLE hThread,
                                       NULL);
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return FALSE;
     }
 
@@ -668,7 +682,7 @@ SetThreadPriorityBoost(IN HANDLE hThread,
                                     sizeof(ULONG));
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return FALSE;
     }
 
@@ -698,7 +712,7 @@ GetThreadSelectorEntry(IN HANDLE hThread,
     if (!NT_SUCCESS(Status))
     {
         /* Fail */
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return FALSE;
     }
 
@@ -727,7 +741,7 @@ SetThreadIdealProcessor(HANDLE hThread,
                                     sizeof(ULONG));
     if (!NT_SUCCESS(Status))
     {
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return -1;
     }
 
@@ -750,7 +764,7 @@ GetProcessIdOfThread(HANDLE Thread)
                                     NULL);
   if(!NT_SUCCESS(Status))
   {
-    SetLastErrorByStatus(Status);
+    BaseSetLastNTError(Status);
     return 0;
   }
 
@@ -773,7 +787,7 @@ GetThreadId(HANDLE Thread)
                                     NULL);
   if(!NT_SUCCESS(Status))
   {
-    SetLastErrorByStatus(Status);
+    BaseSetLastNTError(Status);
     return 0;
   }
 
@@ -809,13 +823,22 @@ QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData)
                             (PVOID)dwData, NULL);
   if (!NT_SUCCESS(Status))
   {
-    SetLastErrorByStatus(Status);
+    BaseSetLastNTError(Status);
     return 0;
   }
 
   return 1;
 }
 
+BOOL
+WINAPI
+SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes)
+{
+    STUB;
+    return FALSE;
+}
+
+
 /*
  * @implemented
  */
@@ -843,53 +866,11 @@ GetThreadIOPendingFlag(HANDLE hThread,
     return TRUE;
   }
 
-  SetLastErrorByStatus(Status);
+  BaseSetLastNTError(Status);
   return FALSE;
 }
 
 
-/*
- * @implemented
- */
-VOID WINAPI
-Sleep(DWORD dwMilliseconds)
-{
-  SleepEx(dwMilliseconds, FALSE);
-  return;
-}
-
-
-/*
- * @implemented
- */
-DWORD WINAPI
-SleepEx(DWORD dwMilliseconds,
-       BOOL bAlertable)
-{
-  LARGE_INTEGER Interval;
-  NTSTATUS errCode;
-
-  if (dwMilliseconds != INFINITE)
-    {
-      /*
-       * System time units are 100 nanoseconds (a nanosecond is a billionth of
-       * a second).
-       */
-      Interval.QuadPart = -((LONGLONG)dwMilliseconds * 10000);
-    }
-  else
-    {
-      /* Approximately 292000 years hence */
-      Interval.QuadPart = -0x7FFFFFFFFFFFFFFFLL;
-    }
-
-dowait:
-  errCode = NtDelayExecution ((BOOLEAN)bAlertable, &Interval);
-  if ((bAlertable) && (errCode == STATUS_ALERTED)) goto dowait;
-  return (errCode == STATUS_USER_APC) ? WAIT_IO_COMPLETION : 0;
-}
-
-
 typedef struct _QUEUE_USER_WORKITEM_CONTEXT
 {
     LPTHREAD_START_ROUTINE Function;
@@ -957,117 +938,248 @@ QueueUserWorkItem(
                     0,
                     WorkItemContext);
 
-        SetLastErrorByStatus(Status);
+        BaseSetLastNTError(Status);
         return FALSE;
     }
 
     return TRUE;
 }
 
-
 /*
  * @implemented
  */
-BOOL
+DWORD
 WINAPI
-RegisterWaitForSingleObject(
-    PHANDLE phNewWaitObject,
-    HANDLE hObject,
-    WAITORTIMERCALLBACK Callback,
-    PVOID Context,
-    ULONG dwMilliseconds,
-    ULONG dwFlags
-    )
+TlsAlloc(VOID)
 {
-    NTSTATUS Status = RtlRegisterWait(phNewWaitObject,
-                                      hObject,
-                                      Callback,
-                                      Context,
-                                      dwMilliseconds,
-                                      dwFlags);
+    ULONG Index;
+    PTEB Teb;
+    PPEB Peb;
+
+    /* Get the PEB and TEB, lock the PEB */
+    Teb = NtCurrentTeb();
+    Peb = Teb->ProcessEnvironmentBlock;
+    RtlAcquirePebLock();
+
+    /* Try to get regular TEB slot */
+    Index = RtlFindClearBitsAndSet(Peb->TlsBitmap, 1, 0);
+    if (Index != 0xFFFFFFFF)
+    {
+        /* Clear the value. */
+        Teb->TlsSlots[Index] = 0;
+        RtlReleasePebLock();
+        return Index;
+    }
 
-    if (!NT_SUCCESS(Status))
+    /* If it fails, try to find expansion TEB slot. */
+    Index = RtlFindClearBitsAndSet(Peb->TlsExpansionBitmap, 1, 0);
+    if (Index != 0xFFFFFFFF)
     {
-        SetLastErrorByStatus(Status);
-        return FALSE;
+        /* Is there no expansion slot yet? */
+        if (!Teb->TlsExpansionSlots)
+        {
+            /* Allocate an array */
+            Teb->TlsExpansionSlots = RtlAllocateHeap(RtlGetProcessHeap(),
+                                                     HEAP_ZERO_MEMORY,
+                                                     TLS_EXPANSION_SLOTS *
+                                                     sizeof(PVOID));
+        }
+
+        /* Did we get an array? */
+        if (!Teb->TlsExpansionSlots)
+        {
+            /* Fail */
+            RtlClearBits(Peb->TlsExpansionBitmap, Index, 1);
+            Index = 0xFFFFFFFF;
+            BaseSetLastNTError(STATUS_NO_MEMORY);
+        }
+        else
+        {
+            /* Clear the value. */
+            Teb->TlsExpansionSlots[Index] = 0;
+            Index += TLS_MINIMUM_AVAILABLE;
+        }
+    }
+    else
+    {
+        /* Fail */
+        BaseSetLastNTError(STATUS_NO_MEMORY);
     }
-    return TRUE;
-}
 
+    /* Release the lock and return */
+    RtlReleasePebLock();
+    return Index;
+}
 
 /*
  * @implemented
  */
-HANDLE
+BOOL
 WINAPI
-RegisterWaitForSingleObjectEx(
-    HANDLE hObject,
-    WAITORTIMERCALLBACK Callback,
-    PVOID Context,
-    ULONG dwMilliseconds,
-    ULONG dwFlags
-    )
+TlsFree(IN DWORD Index)
 {
+    BOOL BitSet;
+    PPEB Peb;
+    ULONG TlsIndex;
+    PVOID TlsBitmap;
     NTSTATUS Status;
-    HANDLE hNewWaitObject;
 
-    Status = RtlRegisterWait(&hNewWaitObject,
-                             hObject,
-                             Callback,
-                             Context,
-                             dwMilliseconds,
-                             dwFlags);
+    /* Acquire the PEB lock and grab the PEB */
+    Peb = NtCurrentPeb();
+    RtlAcquirePebLock();
 
-    if (!NT_SUCCESS(Status))
+    /* Check if the index is too high */
+    if (Index >= TLS_MINIMUM_AVAILABLE)
     {
-        SetLastErrorByStatus(Status);
-        return NULL;
+        /* Check if it can fit in the expansion slots */
+        TlsIndex = Index - TLS_MINIMUM_AVAILABLE;
+        if (TlsIndex >= TLS_EXPANSION_SLOTS)
+        {
+            /* It's invalid */
+            BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+            RtlReleasePebLock();
+            return FALSE;
+        }
+        else
+        {
+            /* Use the expansion bitmap */
+            TlsBitmap = Peb->TlsExpansionBitmap;
+            Index = TlsIndex;
+        }
+    }
+    else
+    {
+        /* Use the normal bitmap */
+        TlsBitmap = Peb->TlsBitmap;
     }
 
-    return hNewWaitObject;
-}
+    /* Check if the index was set */
+    BitSet = RtlAreBitsSet(TlsBitmap, Index, 1);
+    if (BitSet)
+    {
+        /* Tell the kernel to free the TLS cells */
+        Status = NtSetInformationThread(NtCurrentThread(),
+                                        ThreadZeroTlsCell,
+                                        &Index,
+                                        sizeof(DWORD));
+        if (!NT_SUCCESS(Status))
+        {
+            BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+            RtlReleasePebLock();
+            return FALSE;
+        }
 
+        /* Clear the bit */
+        RtlClearBits(TlsBitmap, Index, 1);
+    }
+    else
+    {
+        /* Fail */
+        BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+        RtlReleasePebLock();
+        return FALSE;
+    }
+
+    /* Done! */
+    RtlReleasePebLock();
+    return TRUE;
+}
 
 /*
  * @implemented
  */
-BOOL
+LPVOID
 WINAPI
-UnregisterWait(
-    HANDLE WaitHandle
-    )
+TlsGetValue(IN DWORD Index)
 {
-    NTSTATUS Status = RtlDeregisterWaitEx(WaitHandle, NULL);
+    PTEB Teb;
 
-    if (!NT_SUCCESS(Status))
+    /* Get the TEB and clear the last error */
+    Teb = NtCurrentTeb();
+    Teb->LastErrorValue = 0;
+
+    /* Check for simple TLS index */
+    if (Index < TLS_MINIMUM_AVAILABLE)
     {
-        SetLastErrorByStatus(Status);
-        return FALSE;
+        /* Return it */
+        return Teb->TlsSlots[Index];
     }
 
-    return TRUE;
-}
+    /* Check for valid index */
+    if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
+    {
+        /* Fail */
+        BaseSetLastNTError(STATUS_INVALID_PARAMETER);
+        return NULL;
+    }
 
+    /* The expansion slots are allocated on demand, so check for it. */
+    Teb->LastErrorValue = 0;
+    if (!Teb->TlsExpansionSlots) return NULL;
+
+    /* Return the value from the expansion slots */
+    return Teb->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE];
+}
 
 /*
  * @implemented
  */
 BOOL
 WINAPI
-UnregisterWaitEx(
-    HANDLE WaitHandle,
-    HANDLE CompletionEvent
-    )
+TlsSetValue(IN DWORD Index,
+            IN LPVOID Value)
 {
-    NTSTATUS Status = RtlDeregisterWaitEx(WaitHandle, CompletionEvent);
+    DWORD TlsIndex;
+    PTEB Teb = NtCurrentTeb();
 
-    if (!NT_SUCCESS(Status))
+    /* Check for simple TLS index */
+    if (Index < TLS_MINIMUM_AVAILABLE)
     {
-        SetLastErrorByStatus(Status);
+        /* Return it */
+        Teb->TlsSlots[Index] = Value;
+        return TRUE;
+    }
+
+    /* Check if this is an expansion slot */
+    TlsIndex = Index - TLS_MINIMUM_AVAILABLE;
+    if (TlsIndex >= TLS_EXPANSION_SLOTS)
+    {
+        /* Fail */
+        BaseSetLastNTError(STATUS_INVALID_PARAMETER);
         return FALSE;
     }
 
+    /* Do we not have expansion slots? */
+    if (!Teb->TlsExpansionSlots)
+    {
+        /* Get the PEB lock to see if we still need them */
+        RtlAcquirePebLock();
+        if (!Teb->TlsExpansionSlots)
+        {
+            /* Allocate them */
+            Teb->TlsExpansionSlots = RtlAllocateHeap(RtlGetProcessHeap(),
+                                                     HEAP_ZERO_MEMORY,
+                                                     TLS_EXPANSION_SLOTS *
+                                                     sizeof(PVOID));
+            if (!Teb->TlsExpansionSlots)
+            {
+                /* Fail */
+                RtlReleasePebLock();
+                BaseSetLastNTError(STATUS_NO_MEMORY);
+                return FALSE;
+            }
+        }
+
+        /* Release the lock */
+        RtlReleasePebLock();
+    }
+
+    /* Write the value */
+    Teb->TlsExpansionSlots[TlsIndex] = Value;
+
+    /* Success */
     return TRUE;
 }
 
+
 /* EOF */