- Allow TLS usage for 1088 TLS slots, fixes part of Bug 191. Patch by Filip Navara (navaraf@reactos.com)
Modified: trunk/reactos/lib/kernel32/thread/tls.c

Modified: trunk/reactos/lib/kernel32/thread/tls.c
--- trunk/reactos/lib/kernel32/thread/tls.c	2005-12-08 00:14:59 UTC (rev 19958)
+++ trunk/reactos/lib/kernel32/thread/tls.c	2005-12-08 00:38:57 UTC (rev 19959)
@@ -17,6 +17,7 @@
 #define NDEBUG
 #include "../include/debug.h"
 
+#define TLS_EXPANSION_SLOTS (8 * sizeof(((PPEB)NULL)->TlsExpansionBitmapBits))
 
 /* FUNCTIONS *****************************************************************/
 
@@ -29,18 +30,49 @@
    ULONG Index;
 
    RtlAcquirePebLock();
-   Index = RtlFindClearBitsAndSet (NtCurrentPeb()->TlsBitmap, 1, 0);
-   if (Index == (ULONG)-1)
-     {
-       SetLastErrorByStatus(STATUS_NO_MEMORY);
-     }
+
+   /* Try to get regular TEB slot. */
+   Index = RtlFindClearBitsAndSet(NtCurrentPeb()->TlsBitmap, 1, 0);
+   if (Index == ~0)
+   {
+      /* If it fails, try to find expansion TEB slot. */
+      Index = RtlFindClearBitsAndSet(NtCurrentPeb()->TlsExpansionBitmap, 1, 0);
+      if (Index != ~0)
+      {
+         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;
+         }
+      }
+      else
+      {
+         SetLastError(ERROR_NO_MORE_ITEMS);
+      }
+   }
    else
-     {
-       NtCurrentTeb()->TlsSlots[Index] = 0;
-     }
+   {
+      /* Clear the value. */
+      NtCurrentTeb()->TlsSlots[Index] = 0;
+   }
+
    RtlReleasePebLock();
 
-   return(Index);
+   return Index;
 }
 
 
@@ -48,32 +80,47 @@
  * @implemented
  */
 BOOL STDCALL
-TlsFree(DWORD dwTlsIndex)
+TlsFree(DWORD Index)
 {
-   if (dwTlsIndex >= TLS_MINIMUM_AVAILABLE)
-     {
-	SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-	return(FALSE);
-     }
+   BOOL BitSet;
+   
+   if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
+   {
+      SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
+      return FALSE;
+   }
 
    RtlAcquirePebLock();
-   if (RtlAreBitsSet(NtCurrentPeb()->TlsBitmap, dwTlsIndex, 1))
-     {
-	/*
-	 * clear the tls cells (slots) in all threads
-	 * of the current process
-	 */
-	NtSetInformationThread(NtCurrentThread(),
-			       ThreadZeroTlsCell,
-			       &dwTlsIndex,
-			       sizeof(DWORD));
-	RtlClearBits(NtCurrentPeb()->TlsBitmap,
-		     dwTlsIndex,
-		     1);
-     }
+
+   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(TRUE);
+   return BitSet;
 }
 
 
@@ -81,22 +128,27 @@
  * @implemented
  */
 LPVOID STDCALL
-TlsGetValue(DWORD dwTlsIndex)
+TlsGetValue(DWORD Index)
 {
-   LPVOID Value;
+   if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
+   {
+      SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
+      return NULL;
+   }
 
-   if (dwTlsIndex >= TLS_MINIMUM_AVAILABLE)
-     {
-	SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-	return(NULL);
-     }
+   SetLastError(NO_ERROR);
 
-   Value = NtCurrentTeb()->TlsSlots[dwTlsIndex];
-   if (Value == 0)
+   if (Index >= TLS_MINIMUM_AVAILABLE)
    {
-      SetLastError(NO_ERROR);
+      /* The expansion slots are allocated on demand, so check for it. */
+      if (NtCurrentTeb()->TlsExpansionSlots == NULL)
+         return NULL;
+      return NtCurrentTeb()->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE];
    }
-   return Value;
+   else
+   {
+      return NtCurrentTeb()->TlsSlots[Index];
+   }
 }
 
 
@@ -104,15 +156,37 @@
  * @implemented
  */
 BOOL STDCALL
-TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue)
+TlsSetValue(DWORD Index, LPVOID Value)
 {
-   if (dwTlsIndex >= TLS_MINIMUM_AVAILABLE)
-     {
-	SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-	return(FALSE);
-     }
-   NtCurrentTeb()->TlsSlots[dwTlsIndex] = lpTlsValue;
-   return(TRUE);
+   if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
+   {
+      SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
+      return FALSE;
+   }
+
+   if (Index >= TLS_MINIMUM_AVAILABLE)
+   {
+      if (NtCurrentTeb()->TlsExpansionSlots == NULL)
+      {
+         NtCurrentTeb()->TlsExpansionSlots = HeapAlloc(
+            GetProcessHeap(), HEAP_ZERO_MEMORY,
+            TLS_EXPANSION_SLOTS * sizeof(PVOID));
+
+         if (NtCurrentTeb()->TlsExpansionSlots == NULL)
+         {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+         }
+      }
+
+      NtCurrentTeb()->TlsExpansionSlots[Index - TLS_MINIMUM_AVAILABLE] = Value;
+   }
+   else
+   {
+      NtCurrentTeb()->TlsSlots[Index] = Value;
+   }
+
+   return TRUE;
 }
 
 /* EOF */