- Allow TLS usage for 1088 TLS slots, fixes part of Bug 191. Patch by Filip Navara...
[reactos.git] / reactos / lib / kernel32 / thread / tls.c
index 4470c22..357cae3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tls.c,v 1.5 2000/05/30 23:41:06 ea Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
 
 /* INCLUDES ******************************************************************/
 
-#include <ddk/ntddk.h>
-#include <windows.h>
-#include <kernel32/thread.h>
-#include <string.h>
-#include <ntdll/rtl.h>
+#include <k32.h>
+
+#define NDEBUG
+#include "../include/debug.h"
+
+#define TLS_EXPANSION_SLOTS (8 * sizeof(((PPEB)NULL)->TlsExpansionBitmapBits))
 
 /* FUNCTIONS *****************************************************************/
 
-DWORD STDCALL TlsAlloc(VOID)
+/*
+ * @implemented
+ */
+DWORD STDCALL
+TlsAlloc(VOID)
 {
-   PULONG TlsBitmap = NtCurrentPeb()->TlsBitmapBits;
-   ULONG i, j;
-   
+   ULONG Index;
+
    RtlAcquirePebLock();
-   
-   for (i = 0; i < 2; i++)
-     { 
-       for (j = 0; j < 32; j++)
-         {
-            if ((TlsBitmap[i] & (1 << j)) == 0)
-              {
-                 TlsBitmap[i] = TlsBitmap[i] | (1 << j);
-                 RtlReleasePebLock();
-                 return((i * 32) + j);
-              }
-         }
-     }
+
+   /* 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
+   {
+      /* Clear the value. */
+      NtCurrentTeb()->TlsSlots[Index] = 0;
+   }
 
    RtlReleasePebLock();
-   return (0xFFFFFFFFUL);
+
+   return Index;
 }
 
-WINBOOL        STDCALL TlsFree(DWORD dwTlsIndex)
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+TlsFree(DWORD Index)
 {
-   PULONG TlsBitmap = NtCurrentPeb()->TlsBitmapBits;
+   BOOL BitSet;
    
+   if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
+   {
+      SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
+      return FALSE;
+   }
+
    RtlAcquirePebLock();
-   TlsBitmap[dwTlsIndex / 32] =
-     TlsBitmap[dwTlsIndex / 32] & ~(1 << (dwTlsIndex % 32));
+
+   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;
 }
 
-LPVOID STDCALL TlsGetValue(DWORD dwTlsIndex)
+
+/*
+ * @implemented
+ */
+LPVOID STDCALL
+TlsGetValue(DWORD Index)
 {
-   return(NtCurrentTeb()->TlsSlots[dwTlsIndex]);
+   if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
+   {
+      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];
+   }
 }
 
-WINBOOL        STDCALL TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue)
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+TlsSetValue(DWORD Index, LPVOID Value)
 {
-   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 */