Re: TlsAlloc limitation in winxp mode

2005-03-18 Thread Francois Gouget
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).

--
Francois Gouget [EMAIL PROTECTED]http://fgouget.free.fr/
 "Only wimps use tape backup: _real_ men just upload their important stuff on
   ftp, and let the rest of the world mirror it ;)" -- Linus Torvalds


Re: TlsAlloc limitation in winxp mode

2005-03-18 Thread Michael Ost
On Fri, 2005-03-18 at 03:30, Alexandre Julliard wrote:
> Michael Ost <[EMAIL PROTECTED]> 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):


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.
[EMAIL PROTECTED]




Re: TlsAlloc limitation in winxp mode

2005-03-18 Thread Alexandre Julliard
Michael Ost <[EMAIL PROTECTED]> 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 -   1.85
+++ dlls/kernel/process.c   18 Mar 2005 11:24:53 -
@@ -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,
+ 

Re: TlsAlloc limitation in winxp mode

2005-03-18 Thread Jon Griffiths
Hi Michael,

> 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.

You're misreading that page, the limits are:
Win 2000/2003 & XP - 1088 indexes per process
Win Me/98  - 80 indexes per process
Win NT and 95  - 64 indexes per process

So it seems that Me/98 add 16 on top of the original 64 limit, while
from Win2k onwards another 1024 indices were added.

You can almost certainly work around this if you have the source for
the app you are trying to run, unless your app has more than 64
threads running at once.

Just take all of the per-thread data you need and stick it into a
structure, store only the pointer to that for each thread (1 slot).
This adds a layer of indirection but means you are limited only by
the heap, provided you don't have more than 64 threads. See
dlls/msvcrt/thread.c for an implementation example.

Cheers,
Jon


"Don't wait for the seas to part, or messiahs to come;
 Don't you sit around and waste this chance..." - Live

[EMAIL PROTECTED]



__ 
Do you Yahoo!? 
Yahoo! Small Business - Try our new resources site!
http://smallbusiness.yahoo.com/resources/ 



TlsAlloc limitation in winxp mode

2005-03-17 Thread Michael Ost
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