Michael Ost most@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/bas...
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 */