- 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 a023dfa..357cae3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tls.c,v 1.8 2002/09/07 15:12:28 chorns Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
 
 /* INCLUDES ******************************************************************/
 
-#include <windows.h>
-#define NTOS_USER_MODE
-#include <ntos.h>
-#include <kernel32/thread.h>
-#include <kernel32/error.h>
+#include <k32.h>
 
 #define NDEBUG
-#include <kernel32/kernel32.h>
+#include "../include/debug.h"
 
+#define TLS_EXPANSION_SLOTS (8 * sizeof(((PPEB)NULL)->TlsExpansionBitmapBits))
 
 /* FUNCTIONS *****************************************************************/
 
-DWORD STDCALL 
+/*
+ * @implemented
+ */
+DWORD STDCALL
 TlsAlloc(VOID)
 {
    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;
 }
 
-WINBOOL STDCALL 
-TlsFree(DWORD dwTlsIndex)
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+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;
 }
 
-LPVOID STDCALL 
-TlsGetValue(DWORD dwTlsIndex)
+
+/*
+ * @implemented
+ */
+LPVOID STDCALL
+TlsGetValue(DWORD Index)
 {
-   if (dwTlsIndex >= TLS_MINIMUM_AVAILABLE)
-     {
-       SetLastErrorByStatus(STATUS_INVALID_PARAMETER);
-       return(NULL);
-     }
-   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)
 {
-   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 */