Author: ion
Date: Sat Jul 23 11:28:35 2011
New Revision: 52800

URL: http://svn.reactos.org/svn/reactos?rev=52800&view=rev
Log:
[KERNEL32]:
Bug #35: TlsSetValue should allocate the TlsExpansionSlots under the PEB Lock.
Bug #36: TlsGetValue needs to set the last error to ERROR_SUCCESS when the 
index is valid (amd even if no expansion slots exist!).
Bug #37: TlsFree did not check the return of 
NtSetInformationThread(ThreadZeroTlsCell).
Bug #38: TlsAlloc was setting error to ERROR_NO_MORE_ITEMS instead of 
STATUS_NO_MEMORY. In principle the former is more accurate, but that's not how 
API compatibility works.
Optimize TLS functions not to call NtQueryTeb/Peb all the time. Cache the 
TEB/PEB value instead.


Modified:
    trunk/reactos/dll/win32/kernel32/client/synch.c
    trunk/reactos/dll/win32/kernel32/client/thread.c

Modified: trunk/reactos/dll/win32/kernel32/client/synch.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/synch.c?rev=52800&r1=52799&r2=52800&view=diff
==============================================================================
--- trunk/reactos/dll/win32/kernel32/client/synch.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/kernel32/client/synch.c [iso-8859-1] Sat Jul 23 
11:28:35 2011
@@ -39,7 +39,7 @@
     LARGE_INTEGER Time;
     NTSTATUS Status;
     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
-    
+
     /* APCs must execute with the default activation context */
     if (bAlertable)
     {
@@ -75,7 +75,7 @@
             Status = WAIT_FAILED;
         }
     } while ((Status == STATUS_ALERTED) && (bAlertable));
-    
+
     /* Cleanup the activation context */
     if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
 
@@ -119,7 +119,7 @@
     DWORD i;
     NTSTATUS Status;
     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
-    
+
     /* APCs must execute with the default activation context */
     if (bAlertable)
     {
@@ -196,7 +196,7 @@
 
     /* Cleanup the activation context */
     if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
-    
+
     /* Return wait status */
     return Status;
 }
@@ -215,7 +215,7 @@
     LARGE_INTEGER Time;
     NTSTATUS Status;
     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
-    
+
     /* APCs must execute with the default activation context */
     if (bAlertable)
     {
@@ -225,7 +225,7 @@
         ActCtx.Format = 
RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
         RtlActivateActivationContextUnsafeFast(&ActCtx, NULL);
     }
-    
+
     /* Get real handle */
     hObjectToWaitOn = TranslateStdHandle(hObjectToWaitOn);
 
@@ -258,7 +258,7 @@
 
     /* Cleanup the activation context */
     if (bAlertable) RtlDeactivateActivationContextUnsafeFast(&ActCtx);
-    
+
     /* Return wait status */
     return Status;
 }
@@ -674,7 +674,7 @@
     PLARGE_INTEGER TimePtr;
     NTSTATUS errCode;
     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx;
-    
+
     /* APCs must execute with the default activation context */
     if (bAlertable)
     {
@@ -702,7 +702,7 @@
         errCode = NtDelayExecution((BOOLEAN)bAlertable, TimePtr);
     }
     while ((bAlertable) && (errCode == STATUS_ALERTED));
-    
+
     /* Return the correct code */
     return (errCode == STATUS_USER_APC) ? WAIT_IO_COMPLETION : 0;
 }

Modified: trunk/reactos/dll/win32/kernel32/client/thread.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/thread.c?rev=52800&r1=52799&r2=52800&view=diff
==============================================================================
--- trunk/reactos/dll/win32/kernel32/client/thread.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/kernel32/client/thread.c [iso-8859-1] Sat Jul 23 
11:28:35 2011
@@ -230,7 +230,7 @@
     {
         ASSERT(FALSE);
     }
-    
+
     /* Success */
     if(lpThreadId) *lpThreadId = HandleToUlong(ClientId.UniqueThread);
 
@@ -939,51 +939,61 @@
 TlsAlloc(VOID)
 {
     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(NtCurrentPeb()->TlsBitmap, 1, 0);
-    if (Index == ~0U)
-    {
-        /* If it fails, try to find expansion TEB slot. */
-        Index = RtlFindClearBitsAndSet(NtCurrentPeb()->TlsExpansionBitmap, 1, 
0);
-        if (Index != ~0U)
+    /* 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 it fails, try to find expansion TEB slot. */
+    Index = RtlFindClearBitsAndSet(Peb->TlsExpansionBitmap, 1, 0);
+    if (Index != 0xFFFFFFFF)
+    {
+        /* Is there no expansion slot yet? */
+        if (!Teb->TlsExpansionSlots)
         {
-            if (NtCurrentTeb()->TlsExpansionSlots == NULL)
-            {
-                NtCurrentTeb()->TlsExpansionSlots = HeapAlloc(GetProcessHeap(),
-                                                              HEAP_ZERO_MEMORY,
-                                                              
TLS_EXPANSION_SLOTS *
-                                                              sizeof(PVOID));
-            }
-
-            if (NtCurrentTeb()->TlsExpansionSlots == NULL)
-            {
-                RtlClearBits(NtCurrentPeb()->TlsExpansionBitmap, Index, 1);
-                Index = ~0;
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            }
-            else
-            {
-                /* Clear the value. */
-                NtCurrentTeb()->TlsExpansionSlots[Index] = 0;
-                Index += TLS_MINIMUM_AVAILABLE;
-            }
+            /* 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;
+            SetLastErrorByStatus(STATUS_NO_MEMORY);
         }
         else
         {
-            SetLastError(ERROR_NO_MORE_ITEMS);
+            /* Clear the value. */
+            Teb->TlsExpansionSlots[Index] = 0;
+            Index += TLS_MINIMUM_AVAILABLE;
         }
     }
     else
     {
-        /* Clear the value. */
-        NtCurrentTeb()->TlsSlots[Index] = 0;
-    }
-
+        /* Fail */
+        SetLastErrorByStatus(STATUS_NO_MEMORY);
+    }
+
+    /* Release the lock and return */
     RtlReleasePebLock();
-
     return Index;
 }
 
@@ -992,52 +1002,70 @@
  */
 BOOL
 WINAPI
-TlsFree(DWORD Index)
+TlsFree(IN DWORD Index)
 {
     BOOL BitSet;
-
-    if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
-    {
+    PPEB Peb;
+    ULONG TlsIndex;
+    PVOID TlsBitmap;
+    NTSTATUS Status;
+
+    /* Acquire the PEB lock and grab the PEB */
+    Peb = NtCurrentPeb();
+    RtlAcquirePebLock();
+
+    /* Check if the index is too high */
+    if (Index >= TLS_MINIMUM_AVAILABLE)
+    {
+        /* Check if it can fit in the expansion slots */
+        TlsIndex = Index - TLS_MINIMUM_AVAILABLE;
+        if (TlsIndex >= TLS_EXPANSION_SLOTS)
+        {
+            /* It's invalid */
+            SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
+            RtlReleasePebLock();
+            return FALSE;
+        }
+        else
+        {
+            /* Use the expansion bitmap */
+            TlsBitmap = Peb->TlsExpansionBitmap;
+            Index = TlsIndex;
+        }
+    }
+    else
+    {
+        /* Use the normal bitmap */
+        TlsBitmap = Peb->TlsBitmap;
+    }
+
+    /* 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))
+        {
+            SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
+            return FALSE;
+        }
+
+        /* Clear the bit */
+        RtlClearBits(TlsBitmap, Index, 1);
+    }
+    else
+    {
+        /* Fail */
         SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
         return FALSE;
     }
 
-    RtlAcquirePebLock();
-
-    if (Index >= TLS_MINIMUM_AVAILABLE)
-    {
-        BitSet = RtlAreBitsSet(NtCurrentPeb()->TlsExpansionBitmap,
-                               Index - TLS_MINIMUM_AVAILABLE,
-                               1);
-
-       if (BitSet)
-           RtlClearBits(NtCurrentPeb()->TlsExpansionBitmap,
-                        Index - TLS_MINIMUM_AVAILABLE,
-                        1);
-    }
-    else
-    {
-        BitSet = RtlAreBitsSet(NtCurrentPeb()->TlsBitmap, Index, 1);
-        if (BitSet)
-            RtlClearBits(NtCurrentPeb()->TlsBitmap, Index, 1);
-    }
-
-    if (BitSet)
-    {
-        /* Clear the TLS cells (slots) in all threads of the current process. 
*/
-        NtSetInformationThread(NtCurrentThread(),
-                               ThreadZeroTlsCell,
-                               &Index,
-                               sizeof(DWORD));
-    }
-    else
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-    }
-
-    RtlReleasePebLock();
-
-    return BitSet;
+    /* Done! */
+    return TRUE;
 }
 
 /*
@@ -1045,67 +1073,96 @@
  */
 LPVOID
 WINAPI
-TlsGetValue(DWORD Index)
-{
+TlsGetValue(IN DWORD Index)
+{
+    PTEB Teb;
+
+    /* Get the TEB and clear the last error */
+    Teb = NtCurrentTeb();
+    Teb->LastErrorValue = 0;
+
+    /* Check for simple TLS index */
+    if (Index < TLS_MINIMUM_AVAILABLE)
+    {
+        /* Return it */
+        return Teb->TlsSlots[Index];
+    }
+
+    /* Check for valid index */
     if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
     {
+        /* Fail */
         SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
         return NULL;
     }
 
-    SetLastError(NO_ERROR);
-
-    if (Index >= TLS_MINIMUM_AVAILABLE)
-    {
-        /* The expansion slots are allocated on demand, so check for it. */
-        if (NtCurrentTeb()->TlsExpansionSlots == NULL)
-            return NULL;
-        return NtCurrentTeb()->TlsExpansionSlots[Index - 
TLS_MINIMUM_AVAILABLE];
-    }
-    else
-    {
-        return NtCurrentTeb()->TlsSlots[Index];
-    }
-}
-
-/*
- * @implemented
- */
-BOOL
-WINAPI
-TlsSetValue(DWORD Index,
-            LPVOID Value)
-{
-    if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
-    {
+    /* 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
+TlsSetValue(IN DWORD Index,
+            IN LPVOID Value)
+{
+    DWORD TlsIndex;
+    PTEB Teb = NtCurrentTeb();
+
+    /* Check for simple TLS index */
+    if (Index < TLS_MINIMUM_AVAILABLE)
+    {
+        /* 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 */
         SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
         return FALSE;
     }
 
-    if (Index >= TLS_MINIMUM_AVAILABLE)
-    {
-        if (NtCurrentTeb()->TlsExpansionSlots == NULL)
+    /* Do we not have expansion slots? */
+    if (!Teb->TlsExpansionSlots)
+    {
+        /* Get the PEB lock to see if we still need them */
+        RtlAcquirePebLock();
+        if (!Teb->TlsExpansionSlots)
         {
-            NtCurrentTeb()->TlsExpansionSlots = HeapAlloc(GetProcessHeap(),
-                                                          HEAP_ZERO_MEMORY,
-                                                          TLS_EXPANSION_SLOTS *
-                                                          sizeof(PVOID));
-
-            if (NtCurrentTeb()->TlsExpansionSlots == NULL)
+            /* Allocate them */
+            Teb->TlsExpansionSlots = RtlAllocateHeap(RtlGetProcessHeap(),
+                                                     HEAP_ZERO_MEMORY,
+                                                     TLS_EXPANSION_SLOTS *
+                                                     sizeof(PVOID));
+            if (!Teb->TlsExpansionSlots)
             {
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                /* Fail */
+                RtlReleasePebLock();
+                SetLastErrorByStatus(STATUS_NO_MEMORY);
                 return FALSE;
             }
         }
 
-        NtCurrentTeb()->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE] = 
Value;
-    }
-    else
-    {
-        NtCurrentTeb()->TlsSlots[Index] = Value;
-    }
-
-    return TRUE;
-}
+        /* Release the lock */
+        RtlReleasePebLock();
+    }
+
+    /* Write the value */
+    Teb->TlsExpansionSlots[TlsIndex] = Value;
+
+    /* Success */
+    return TRUE;
+}
+
 
 /* EOF */


Reply via email to