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
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 */
On Fri, 2005-03-18 at 03:30, Alexandre Julliard wrote:
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):
<snip patch>
Thanks. I suspected that was the way to go. Should the TlsAlloc code, or perhaps the thread init code, check on the windows emulation version and allow the right number of slots... 64, 80 or 1088?
- mo
=================================== Michael Ost, Software Architect Muse Research, Inc. most@museresearch.com
On Fri, 18 Mar 2005, Michael Ost wrote: [...]
Thanks. I suspected that was the way to go. Should the TlsAlloc code, or perhaps the thread init code, check on the windows emulation version and allow the right number of slots... 64, 80 or 1088?
We try not to make the implementation depend on the emulated Windows version unless we find an application that absolutely depends on it. The rationale is that this keeps Wine's code as simple as possible (it's complex enough as it is).