- 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 02a0208..357cae3 100644 (file)
@@ -1,4 +1,5 @@
-/*
+/* $Id$
+ *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/kernel32/thread/tls.c
 
 /* INCLUDES ******************************************************************/
 
-#include <ddk/ntddk.h>
-#include <windows.h>
-#include <kernel32/thread.h>
-#include <string.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)
 {
-#if 0
-   DWORD dwTlsIndex = GetTeb()->dwTlsIndex;
-   void        **TlsData = GetTeb()->TlsData;
-       
-   if (dwTlsIndex < (sizeof(TlsData) / sizeof(TlsData[0])))
-     {
-       TlsData[dwTlsIndex] = NULL;
-       return (dwTlsIndex++);
-     }
-   return (0xFFFFFFFFUL);
-#endif
+   ULONG Index;
+
+   RtlAcquirePebLock();
+
+   /* 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 Index;
 }
 
-WINBOOL        STDCALL TlsFree(DWORD dwTlsIndex)
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+TlsFree(DWORD Index)
 {
-#if 0
-   return (TRUE);
-#endif
+   BOOL BitSet;
+   
+   if (Index >= TLS_EXPANSION_SLOTS + TLS_MINIMUM_AVAILABLE)
+   {
+      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;
 }
 
-LPVOID STDCALL TlsGetVlue(DWORD dwTlsIndex)
+
+/*
+ * @implemented
+ */
+LPVOID STDCALL
+TlsGetValue(DWORD Index)
 {
-#if 0
-   void        **TlsData = GetTeb()->TlsData;
-       
-   if (dwTlsIndex < (sizeof(TlsData) / sizeof(TlsData[0])))
-     {
-       SetLastError(NO_ERROR);
-       return (TlsData[dwTlsIndex]);
-     }
-   SetLastError(1);
-   return (NULL);
-#endif
+   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 0
-   void        **TlsData = GetTeb()->TlsData;
-       
-   if (dwTlsIndex < (sizeof(TlsData) / sizeof(TlsData[0])))
-     {
-       TlsData[dwTlsIndex] = lpTlsValue;
-       return (TRUE);
-     }
-   return (FALSE);
-#endif
+   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 */