TlsAlloc limitation in winxp mode

Alexandre Julliard julliard at winehq.org
Fri Mar 18 05:30:55 CST 2005


Michael Ost <most at museresearch.com> writes:

> With the emulation mode set to "winxp" I can only TlsAlloc 64 indexes,
> even though the MSDN docs say there should be at least 20 million.
> 
> http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/thread_local_storage.asp
> 
> Has anyone done any work on this? Any workaround/hackarounds? ... mo

It's not 20 million, it's 1088 (64 + 1024). You need to use the TLS
expansion slots for the extra 1024, something like this (completely
untested):

Index: dlls/kernel/process.c
===================================================================
RCS file: /opt/cvs-commit/wine/dlls/kernel/process.c,v
retrieving revision 1.85
diff -u -p -r1.85 process.c
--- dlls/kernel/process.c	7 Mar 2005 19:24:44 -0000	1.85
+++ dlls/kernel/process.c	18 Mar 2005 11:24:53 -0000
@@ -2192,11 +2192,32 @@ UINT WINAPI SetErrorMode( UINT mode )
 DWORD WINAPI TlsAlloc( void )
 {
     DWORD index;
+    PEB * const peb = NtCurrentTeb()->Peb;
 
     RtlAcquirePebLock();
-    index = RtlFindClearBitsAndSet( NtCurrentTeb()->Peb->TlsBitmap, 1, 0 );
+    index = RtlFindClearBitsAndSet( peb->TlsBitmap, 1, 0 );
     if (index != ~0UL) NtCurrentTeb()->TlsSlots[index] = 0; /* clear the value */
-    else SetLastError( ERROR_NO_MORE_ITEMS );
+    else
+    {
+        index = RtlFindClearBitsAndSet( peb->TlsExpansionBitmap, 1, 0 );
+        if (index != ~0UL)
+        {
+            if (!NtCurrentTeb()->TlsExpansionSlots &&
+                !(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                              peb->TlsExpansionBitmap->SizeOfBitMap*sizeof(void*) )))
+            {
+                RtlClearBits( peb->TlsExpansionBitmap, index, 1 );
+                index = ~0UL;
+                SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+            }
+            else
+            {
+                NtCurrentTeb()->TlsExpansionSlots[index] = 0; /* clear the value */
+                index += peb->TlsBitmap->SizeOfBitMap;
+            }
+        }
+        else SetLastError( ERROR_NO_MORE_ITEMS );
+    }
     RtlReleasePebLock();
     return index;
 }
@@ -2215,14 +2236,21 @@ BOOL WINAPI TlsFree(
     DWORD index) /* [in] TLS Index to free */
 {
     BOOL ret;
+    PEB * const peb = NtCurrentTeb()->Peb;
 
     RtlAcquirePebLock();
-    ret = RtlAreBitsSet( NtCurrentTeb()->Peb->TlsBitmap, index, 1 );
-    if (ret)
+    if (index >= peb->TlsBitmap->SizeOfBitMap)
     {
-        RtlClearBits( NtCurrentTeb()->Peb->TlsBitmap, index, 1 );
-        NtSetInformationThread( GetCurrentThread(), ThreadZeroTlsCell, &index, sizeof(index) );
+        DWORD exp_index = index - peb->TlsBitmap->SizeOfBitMap;
+        ret = RtlAreBitsSet( peb->TlsExpansionBitmap, exp_index, 1 );
+        if (ret) RtlClearBits( peb->TlsExpansionBitmap, exp_index, 1 );
     }
+    else
+    {
+        ret = RtlAreBitsSet( peb->TlsBitmap, index, 1 );
+        if (ret) RtlClearBits( peb->TlsBitmap, index, 1 );
+    }
+    if (ret) NtSetInformationThread( GetCurrentThread(), ThreadZeroTlsCell, &index, sizeof(index) );
     else SetLastError( ERROR_INVALID_PARAMETER );
     RtlReleasePebLock();
     return TRUE;
@@ -2239,13 +2267,25 @@ BOOL WINAPI TlsFree(
 LPVOID WINAPI TlsGetValue(
     DWORD index) /* [in] TLS index to retrieve value for */
 {
-    if (index >= NtCurrentTeb()->Peb->TlsBitmap->SizeOfBitMap)
+    LPVOID ret;
+
+    if (index < NtCurrentTeb()->Peb->TlsBitmap->SizeOfBitMap)
     {
-        SetLastError( ERROR_INVALID_PARAMETER );
-        return NULL;
+        ret = NtCurrentTeb()->TlsSlots[index];
+    }
+    else
+    {
+        index -= NtCurrentTeb()->Peb->TlsBitmap->SizeOfBitMap;
+        if (index >= NtCurrentTeb()->Peb->TlsExpansionBitmap->SizeOfBitMap)
+        {
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return NULL;
+        }
+        if (!NtCurrentTeb()->TlsExpansionSlots) ret = NULL;
+        else ret = NtCurrentTeb()->TlsExpansionSlots[index];
     }
     SetLastError( ERROR_SUCCESS );
-    return NtCurrentTeb()->TlsSlots[index];
+    return ret;
 }
 
 
@@ -2260,12 +2300,29 @@ BOOL WINAPI TlsSetValue(
     DWORD index,  /* [in] TLS index to set value for */
     LPVOID value) /* [in] Value to be stored */
 {
-    if (index >= NtCurrentTeb()->Peb->TlsBitmap->SizeOfBitMap)
+    PEB * const peb = NtCurrentTeb()->Peb;
+
+    if (index < peb->TlsBitmap->SizeOfBitMap)
+    {
+        NtCurrentTeb()->TlsSlots[index] = value;
+    }
+    else
     {
-        SetLastError( ERROR_INVALID_PARAMETER );
-        return FALSE;
+        index -= peb->TlsBitmap->SizeOfBitMap;
+        if (index >= peb->TlsExpansionBitmap->SizeOfBitMap)
+        {
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return FALSE;
+        }
+        if (!NtCurrentTeb()->TlsExpansionSlots &&
+            !(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                              peb->TlsExpansionBitmap->SizeOfBitMap*sizeof(void*) )))
+        {
+            SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+            return FALSE;
+        }
+        NtCurrentTeb()->TlsExpansionSlots[index] = value;
     }
-    NtCurrentTeb()->TlsSlots[index] = value;
     return TRUE;
 }
 
Index: dlls/ntdll/thread.c
===================================================================
RCS file: /opt/cvs-commit/wine/dlls/ntdll/thread.c,v
retrieving revision 1.24
diff -u -p -r1.24 thread.c
--- dlls/ntdll/thread.c	22 Feb 2005 19:33:50 -0000	1.24
+++ dlls/ntdll/thread.c	18 Mar 2005 11:24:57 -0000
@@ -49,6 +49,7 @@ static PEB peb;
 static PEB_LDR_DATA ldr;
 static RTL_USER_PROCESS_PARAMETERS params;  /* default parameters if no parent */
 static RTL_BITMAP tls_bitmap;
+static RTL_BITMAP tls_expansion_bitmap;
 static LIST_ENTRY tls_links;
 
 
@@ -109,8 +110,11 @@ void thread_init(void)
     peb.NumberOfProcessors = 1;
     peb.ProcessParameters  = &params;
     peb.TlsBitmap          = &tls_bitmap;
+    peb.TlsExpansionBitmap = &tls_expansion_bitmap;
     peb.LdrData            = &ldr;
     RtlInitializeBitMap( &tls_bitmap, peb.TlsBitmapBits, sizeof(peb.TlsBitmapBits) * 8 );
+    RtlInitializeBitMap( &tls_expansion_bitmap, peb.TlsExpansionBitmapBits,
+                         sizeof(peb.TlsExpansionBitmapBits) * 8 );
     InitializeListHead( &ldr.InLoadOrderModuleList );
     InitializeListHead( &ldr.InMemoryOrderModuleList );
     InitializeListHead( &ldr.InInitializationOrderModuleList );
@@ -535,14 +539,28 @@ NTSTATUS WINAPI NtSetInformationThread( 
 
             if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
             index = *(const DWORD *)data;
-            if (index >= 64) return STATUS_INVALID_PARAMETER;
-            RtlAcquirePebLock();
-            for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
+            if (index < tls_bitmap.SizeOfBitMap)
             {
-                TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
-                teb->TlsSlots[index] = 0;
+                RtlAcquirePebLock();
+                for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
+                {
+                    TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
+                    teb->TlsSlots[index] = 0;
+                }
+                RtlReleasePebLock();
+            }
+            else
+            {
+                index -= tls_bitmap.SizeOfBitMap;
+                if (index >= tls_expansion_bitmap.SizeOfBitMap) return STATUS_INVALID_PARAMETER;
+                RtlAcquirePebLock();
+                for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
+                {
+                    TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
+                    if (teb->TlsExpansionSlots) teb->TlsExpansionSlots[index] = 0;
+                }
+                RtlReleasePebLock();
             }
-            RtlReleasePebLock();
             return STATUS_SUCCESS;
         }
         FIXME( "ZeroTlsCell not supported on other threads\n" );
Index: include/thread.h
===================================================================
RCS file: /opt/cvs-commit/wine/include/thread.h,v
retrieving revision 1.98
diff -u -p -r1.98 thread.h
--- include/thread.h	14 Jan 2005 19:54:39 -0000	1.98
+++ include/thread.h	18 Mar 2005 11:25:26 -0000
@@ -132,7 +132,7 @@ typedef struct _TEB
     DWORD        pad9[24];                   /* --n f20 */
     PVOID        ReservedForOle;             /* -2- f80 used by ole32 (IErrorInfo*) */
     PVOID        pad10[4];                   /* --n f84 */
-    PVOID        TlsExpansionSlots;          /* -2- f94 */
+    PVOID       *TlsExpansionSlots;          /* -2- f94 */
 } TEB;
 #endif /* WINE_TEB_DEFINED */
 
Index: include/winternl.h
===================================================================
RCS file: /opt/cvs-commit/wine/include/winternl.h,v
retrieving revision 1.109
diff -u -p -r1.109 winternl.h
--- include/winternl.h	15 Feb 2005 20:47:24 -0000	1.109
+++ include/winternl.h	18 Mar 2005 11:25:32 -0000
@@ -197,7 +197,7 @@ typedef struct _PEB
     ULONG                        ImageProcessAffinityMask;          /*  c0 */
     ULONG                        GdiHandleBuffer[34];               /*  c4 */
     ULONG                        PostProcessInitRoutine;            /* 14c */
-    ULONG                        TlsExpansionBitmap;                /* 150 */
+    PRTL_BITMAP                  TlsExpansionBitmap;                /* 150 */
     ULONG                        TlsExpansionBitmapBits[32];        /* 154 */
     ULONG                        SessionId;                         /* 1d4 */
 } PEB, *PPEB;
@@ -235,7 +235,7 @@ typedef struct _TEB
     PVOID           Reserved4[26];              /* f18 */
     PVOID           ReservedForOle;             /* f80 Windows 2000 only */
     PVOID           Reserved5[4];               /* f84 */
-    PVOID           TlsExpansionSlots;          /* f94 */
+    PVOID          *TlsExpansionSlots;          /* f94 */
 } TEB, *PTEB;
 # endif /* WINE_TEB_DEFINED */
 #endif  /* WINE_NO_TEB */


-- 
Alexandre Julliard
julliard at winehq.org



More information about the wine-devel mailing list