-/*
+/* $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 */