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 = ¶ms;
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