Re: Problems with VirtualAlloc/Lock

2005-03-17 Thread Alexandre Julliard
Michael Ost <[EMAIL PROTECTED]> writes:

> This should start allocating memory from below 0x4000, to windows
> processes after the area between 0x4000, to 0x8000, is full,
> right? 

That would be nice, but unfortunately it's not what it does. Also even
if it worked it wouldn't help for libc allocations, so it would mean
that once you have allocated 1Gb you can no longer load builtin dlls.

-- 
Alexandre Julliard
[EMAIL PROTECTED]



Re: Problems with VirtualAlloc/Lock

2005-03-16 Thread Michael Ost
On Wed, 2005-03-16 at 00:32, Alexandre Julliard wrote:
> Michael Ost <[EMAIL PROTECTED]> writes:
> 
> > Wine reports that apps have 2GB of VM in GlobalMemoryStatus, but they
> > actually only have 1GB. Isn't that a Wine bug?
> 
> Not really, you do have 2GB of VM, you just can't allocate all of it
> with VirtualAlloc(NULL) because of kernel limitations. You can still
> access it by specifying explicit addresses.

Here's a suggestion. Certainly naive, but would it work? The idea is to
trap mmap allocations which go above "user_space_limit" and retry them
in the space below 0x4000,. Something like this in lib/wine/mmap.c
wine_anon_map() - 

replace:
  return mmap(start, size, prot, flags, fdzero, 0);

with
  void* addr = mmap(start, size, prot, flags, fdzero, 0);
  /* disallow allocations above the windows limit */
  /* OR can you to find this out without mmap()ing first? */
  if addr + size > user_space_limit)
munmap(addr)
addr = 0;

  /* look below linux's 0x4000 address if a specific */
  /* address wasn't requested */ 
  if start == 0 and addr == 0
  /* 0x0800 is the start of the TEXT segment - */
  /* start looking there */
  addr = mmap(0x0800, size, prot, 
  MAP_PRIVATE | MAP_ANON, -1, 0);

  return addr;

This should start allocating memory from below 0x4000, to windows
processes after the area between 0x4000, to 0x8000, is full,
right? 

>From way out of my depth %) ... mo

PS: my company is very interested in getting this fixed. I might be able
to shake some money loose for the development.




Re: Problems with VirtualAlloc/Lock

2005-03-16 Thread Mike Hearn
On Tue, 15 Mar 2005 13:12:42 -0800, Michael Ost wrote:
> What's involved in doing such a hack/syscall? Are there any patches that
> make this change lying around somewhere that I could look at?

I thought the flex-mmap patches in very recent kernels changed stuff so
you could do this. I'd ask on the kernel list.




Re: Problems with VirtualAlloc/Lock

2005-03-16 Thread Alexandre Julliard
Michael Ost <[EMAIL PROTECTED]> writes:

> Wine reports that apps have 2GB of VM in GlobalMemoryStatus, but they
> actually only have 1GB. Isn't that a Wine bug?

Not really, you do have 2GB of VM, you just can't allocate all of it
with VirtualAlloc(NULL) because of kernel limitations. You can still
access it by specifying explicit addresses.

-- 
Alexandre Julliard
[EMAIL PROTECTED]



Re: Problems with VirtualAlloc/Lock

2005-03-15 Thread Michael Ost
On Tue, 2005-03-15 at 11:12, Alexandre Julliard wrote:
> Michael Ost <[EMAIL PROTECTED]> writes:
> 
> > On Tue, 2005-03-15 at 01:09, Alexandre Julliard wrote:
> > > That's a kernel limitation. If you hack the kernel to start allocating
> > > from lower addresses (or implement the syscall we discussed to let us
> > > specify the mmap range) you can get the full 2GB.
> > 
> > Could you point me to the kernel limitation? I can mmap() 2GB on an
> > unhacked 2.4.19 kernel with this loop:
> 
> That's because you can mmap above 0x800, but that's not allowed
> under Windows. You'll note that on a standard kernel you can only mmap
> 2GB even though you have a 3GB address space.  If you set the large
> address flag when building your application you will get a 3GB address
> space on Wine too, which will then let you allocate 2GB; but the
> resulting high addresses may break your plugins. The real problem is
> that the kernel starts allocations at 0x4000.

What's involved in doing such a hack/syscall? Are there any patches that
make this change lying around somewhere that I could look at?

Wine reports that apps have 2GB of VM in GlobalMemoryStatus, but they
actually only have 1GB. Isn't that a Wine bug?

To summarize and make sure I understand: the problem is that Linux and
Windows allocate VM from different address ranges. While both can alloc
2GB, the intersection of addresses is only 1GB --- between 0x4000
and 0x8000. 

On Windows (based on the MSDN docs) VM is allocated from 0x0010 to
0x8000. On Linux (unhacked 2.4 kernel), mmap runs from 0x4000 to
0xC000. 

Thanks... mo




Re: Problems with VirtualAlloc/Lock

2005-03-15 Thread Alexandre Julliard
Michael Ost <[EMAIL PROTECTED]> writes:

> On Tue, 2005-03-15 at 01:09, Alexandre Julliard wrote:
> > That's a kernel limitation. If you hack the kernel to start allocating
> > from lower addresses (or implement the syscall we discussed to let us
> > specify the mmap range) you can get the full 2GB.
> 
> Could you point me to the kernel limitation? I can mmap() 2GB on an
> unhacked 2.4.19 kernel with this loop:

That's because you can mmap above 0x800, but that's not allowed
under Windows. You'll note that on a standard kernel you can only mmap
2GB even though you have a 3GB address space.  If you set the large
address flag when building your application you will get a 3GB address
space on Wine too, which will then let you allocate 2GB; but the
resulting high addresses may break your plugins. The real problem is
that the kernel starts allocations at 0x4000.

-- 
Alexandre Julliard
[EMAIL PROTECTED]



Re: Problems with VirtualAlloc/Lock

2005-03-15 Thread Michael Ost
On Tue, 2005-03-15 at 01:09, Alexandre Julliard wrote:
> Michael Ost <[EMAIL PROTECTED]> writes:
> > will stop at 1,022,976k (1GB) on any wine machine. In winxp it goes up
> > to 2GB, as it ought to. 
> 
> That's a kernel limitation. If you hack the kernel to start allocating
> from lower addresses (or implement the syscall we discussed to let us
> specify the mmap range) you can get the full 2GB.

Could you point me to the kernel limitation? I can mmap() 2GB on an
unhacked 2.4.19 kernel with this loop:

int total = 0;
for (;;) {
  void* leak = mmap(0, 1048576, PROT_READ | PROT_WRITE, 
MAP_PRIVATE | MAP_ANON, -1, 0);
  if (leak) {
total += 1048576/1024;
printf("Allocated %ldk\r", total);
  }
  else {
printf("\n");
perror("mmap");
break;
  }
}

- mo

PS: When building this loop, I tried to copy the behavior of
wine_anon_mmap from libs/wine/mmap.c. But frankly I am new to mmap() and
wine memory management. So maybe I am missing something...?





Re: Problems with VirtualAlloc/Lock

2005-03-15 Thread Uwe Bonnes
> "Alexandre" == Alexandre Julliard <[EMAIL PROTECTED]> writes:

Alexandre> Michael Ost <[EMAIL PROTECTED]> writes:
>> Yep, it does. Give it a try. As far as I can tell:
>> 
>> int total = 0; for (;;) { LPVOID* leak = ::VirtualAlloc(NULL,
>> 1048576, MEM_RESERVE, PROT_NOACCESS); if (leak) { total +=
>> 1048576/1024; printf("Allocated %ldk\r", total); } else {
>> printf("\n"); PrintWindowsError("VirtualAlloc", ::GetLastError();
>> break; } }
>> 
>> will stop at 1,022,976k (1GB) on any wine machine. In winxp it goes
>> up to 2GB, as it ought to.

Alexandre> That's a kernel limitation. If you hack the kernel to start
Alexandre> allocating from lower addresses (or implement the syscall we
Alexandre> discussed to let us specify the mmap range) you can get the
Alexandre> full 2GB.

Don't we need some "non-hack" way to tell the kernel about thw desired
allocation strategy? 
-- 
Uwe Bonnes[EMAIL PROTECTED]

Institut fuer Kernphysik  Schlossgartenstrasse 9  64289 Darmstadt
- Tel. 06151 162516  Fax. 06151 164321 --



Re: Problems with VirtualAlloc/Lock

2005-03-15 Thread Alexandre Julliard
Michael Ost <[EMAIL PROTECTED]> writes:

> Yep, it does. Give it a try. As far as I can tell:
> 
> int total = 0;
> for (;;) {
>   LPVOID* leak = ::VirtualAlloc(NULL, 1048576, 
> MEM_RESERVE, PROT_NOACCESS);
>   if (leak) {
> total += 1048576/1024;
> printf("Allocated %ldk\r", total);
>   }
>   else {
> printf("\n");
> PrintWindowsError("VirtualAlloc", ::GetLastError();
> break;
>   }
> }
> 
> will stop at 1,022,976k (1GB) on any wine machine. In winxp it goes up
> to 2GB, as it ought to. 

That's a kernel limitation. If you hack the kernel to start allocating
from lower addresses (or implement the syscall we discussed to let us
specify the mmap range) you can get the full 2GB.

-- 
Alexandre Julliard
[EMAIL PROTECTED]



Re: Problems with VirtualAlloc/Lock

2005-03-15 Thread Uwe Bonnes
> "Kuba" == Kuba Ober <[EMAIL PROTECTED]> writes:

>> * VirtualLock does nothing in Wine
Kuba> VirtualLock does nothing in win95,98,ME as well :)

Kuba> I bet the correct behaviour for wine is to do anything in
Kuba> VirtualLock only if you set windows version to NT/2000/XP. Did you
Kuba> do it?

Kuba> Anyway, mlock() seems to work fine, so this should be
Kuba> implementable.

>> * Wine makes no distinction between MEM_RESERVE and MEM_COMMIT
Kuba> Assuming that we're talking about VirtualAlloc().

In this context, the different allocation strategy with 2.6 ("flexible
mmap") and the chance of handling out Heappointers above 0x8000 should
be noted.

-- 
Uwe Bonnes[EMAIL PROTECTED]

Institut fuer Kernphysik  Schlossgartenstrasse 9  64289 Darmstadt
- Tel. 06151 162516  Fax. 06151 164321 --



Re: Problems with VirtualAlloc/Lock

2005-03-14 Thread Michael Ost
On Mon, 2005-03-14 at 20:13, you wrote:
> > * VirtualLock does nothing in Wine
> VirtualLock does nothing in win95,98,ME as well :)
> 
> I bet the correct behaviour for wine is to do anything in VirtualLock
> only if you set windows version to NT/2000/XP. Did you do it?

Good point. But the setting is "winxp". I played with the setting and it
doesn't change the behavior.

> Anyway, mlock() seems to work fine, so this should be implementable.

That would be the natural call to use. The absence of mlock in the wine
source tree was one of my early clues that there was a problem! %)
 
> > * Wine makes no distinction between MEM_RESERVE and MEM_COMMIT
> Assuming that we're talking about VirtualAlloc().

Yes, but I wasn't specific enough. VirtualAlloc(MEM_RESERVE) and
MEM_COMMIT are handled differently in the code. I don't understand the
code, the design, or Linux mmap() sufficiently to say if they work
correctly or not. They both end up calling mmap() which looks right.

What I was trying to say is that in winxp MEM_RESERVE and MEM_COMMIT
will VirtualAlloc() and/or VirtualLock very different amounts of memory
than wine, even on the same (dual booting) machine.

Here were my results when I tried to see how much winxp and wine would
allocate and lock. The machine has 368M of RAM on it and a ~1GB paging
file in Windows.

winxp: 
1. VirtualAlloc(MEM_RESERVE) ->  2,086,912k
2. SetProcessWorkingSetSize(260,000k) + VirtualAlloc(MEM_COMMIT) +
VirtualLock() -> 259,072k
3. VirtualAlloc(MEM_COMMIT) ->  1,011,712k

wine:
1. VirtualAlloc(MEM_RESERVE) ->  1,020,928k
2. SetProcessWorkingSetSize(260,000k) + VirtualAlloc(MEM_COMMIT) +
VirtualLock() -> 1,020,928k
3. VirtualAlloc(MEM_COMMIT) ->  1,020,928k

What I meant by "makes no distinction" is that wine always lets you
MEM_RESERVE or MEM_COMMIT 1,020,928k no matter what. 

In winxp, 
* VirtualAlloc(MEM_COMMIT) seems bounded by the size of the paging file
* VirtualAlloc(MEM_RESERVE) seems just to be 2GB
* VirtualLock() is bounded by GetProcessWorkingSet
* GetProcessWorkingSet is bounded by how much RAM you have

> > * Wine has no implementation of Windows' process working sets
> Linux doesn't either. At least I don't know of a documented API that
> could 
> reliably implement semantics of Windows working sets. Maybe it could be 
> implemented on other OSes like some BSDs if they have such APIs. Maybe 
> there's something in /proc/sys/vm or somesuch to tweak those, but then
> it 
> would probably be system-wide. I'm no expert here I'm afraid :(
I was wondering about getrtlimit/setrlimit. The upper bound of the
working set size seems to map well to RLIMIT_MEMLOCK. However I can't
see what the parallel would be for the lower bound.

Also RLIMIT_AS could be the limit for how much memory you can
MEM_RESERVE. 

These are process based values. They are available in Linux. Not sure
about other platforms. 
 
> > * Wine limits MEM_RESERVE to 1GB, but WinXP goes up to 2GB
> Wine? Maybe linux, but I doubt wine would do anything like that.
Yep, it does. Give it a try. As far as I can tell:

int total = 0;
for (;;) {
  LPVOID* leak = ::VirtualAlloc(NULL, 1048576, 
MEM_RESERVE, PROT_NOACCESS);
  if (leak) {
total += 1048576/1024;
printf("Allocated %ldk\r", total);
  }
  else {
printf("\n");
PrintWindowsError("VirtualAlloc", ::GetLastError();
break;
  }
}

will stop at 1,022,976k (1GB) on any wine machine. In winxp it goes up
to 2GB, as it ought to. 
 
> > Further, these DLLs are audio processing plugins. The apparent fact
> that
> > VirtualLock doesn't _actually_ lock memory into RAM for real time
> I didn't look into the code, but anyway a prerequisite for it would be
> to set 
> windows version to NT/2000/XP. Or at least wine should behave like that,
> assuming that MSDN doesn't lie here.
> 
> Apart from that, I bet you didn't raise ulimits for your processes. On
> my FC3 
> system, ulimit -l gives a meager 32 pages. So that's how many mlock()
> could 
> lock anyway.
There's not a problem there. My ulimit -l is "unlimited". 

BTW we are using an old kernel which required a hack to mlock to allow
us to lock more than half the ram (regardless of the ulimit), but that
doesn't change any of this behavior.
 
Thanks for your feedback... mo






Re: Problems with VirtualAlloc/Lock

2005-03-14 Thread Kuba Ober
> * VirtualLock does nothing in Wine
VirtualLock does nothing in win95,98,ME as well :)

I bet the correct behaviour for wine is to do anything in VirtualLock only if 
you set windows version to NT/2000/XP. Did you do it?

Anyway, mlock() seems to work fine, so this should be implementable.

> * Wine makes no distinction between MEM_RESERVE and MEM_COMMIT
Assuming that we're talking about VirtualAlloc().

It would use mmap():
MAP_PRIVATE must be set. Always.
MEM_RESERVE translates to MAP_NORESERVE (sic!)
MEM_COMMIT translates to nothing, but it should zero the page and methinks 
linux would do it by default (?)
MEM_TOP_DOWN translates maybe to MAP_GROWSDOWN (?)
MEM_WRITE_WATCH can be implemented by mmapping a PROT_READ region, handling 
SEGSIGVs and then mprotect()ing it back to PROT_READ | PROT_WRITE

It would also use madvise():
MEM_RESET translates to MADV_DONTNEED

I wonder to what extent Wine really does any of that. Too busy to take a look 
at the actual code.

> * Wine has no implementation of Windows' process working sets
Linux doesn't either. At least I don't know of a documented API that could 
reliably implement semantics of Windows working sets. Maybe it could be 
implemented on other OSes like some BSDs if they have such APIs. Maybe 
there's something in /proc/sys/vm or somesuch to tweak those, but then it 
would probably be system-wide. I'm no expert here I'm afraid :(

> * Wine limits MEM_RESERVE to 1GB, but WinXP goes up to 2GB
Wine? Maybe linux, but I doubt wine would do anything like that.

> Further, these DLLs are audio processing plugins. The apparent fact that
> VirtualLock doesn't _actually_ lock memory into RAM for real time
I didn't look into the code, but anyway a prerequisite for it would be to set 
windows version to NT/2000/XP. Or at least wine should behave like that, 
assuming that MSDN doesn't lie here.

Apart from that, I bet you didn't raise ulimits for your processes. On my FC3 
system, ulimit -l gives a meager 32 pages. So that's how many mlock() could 
lock anyway.

So, in order for VirtualLock to be able to potentially screw up your 
rock-stable linux system, you have to let it first :)

Cheers, Kuba



Re: Problems with VirtualAlloc/Lock

2005-03-14 Thread MIchael Ost
On Mon, 2005-03-14 at 13:16, Raphael wrote:
> seems we have a bug report about that problem (behavior differences)
>  http://bugs.winehq.org/show_bug.cgi?id=890

I guess I am adding VirtualLock and VirtualAlloc to the list of APIs
that don't work the same in Wine vs Windows. Bug #890 is about
VirtualQuery and seems to have been patched/fixed...? 

The diff is that  the issues I raise aren't bugs, but behaviors that
just haven't been implemented like actually locking virtual memory, and
using the win32 working sets.

That bug dates back to 2002! Oh, no. I guess this must be a low priority
issue for Wine. Bad news for me. ... mo

PS: thanks for the hint about the bug db, tho. I didn't think to check
there! Ooops... %)




Re: Problems with VirtualAlloc/Lock

2005-03-14 Thread Raphael
Hi,

interesting

seems we have a bug report about that problem (behavior differences)
 http://bugs.winehq.org/show_bug.cgi?id=890

Regards,
Raphael


pgphdqoXTIGCs.pgp
Description: PGP signature


Problems with VirtualAlloc/Lock

2005-03-14 Thread MIchael Ost
There are major differences in the handling of virtual memory in Wine vs
WinXP that are causing problems for my winelib application. Can someone
provide background and/or workarounds for these issues?

As near as I can tell the main differences are:
* VirtualLock does nothing in Wine
* Wine makes no distinction between MEM_RESERVE and MEM_COMMIT
* Wine has no implementation of Windows' process working sets
* Wine limits MEM_RESERVE to 1GB, but WinXP goes up to 2GB

The above problems seem relatively harmless on systems with < 1GB RAM.
But when our units go greater than 1GB we are seeing spectacular
crash-and-burn failures. The code-only DLLs we are running on such
systems are crashing at a stage when I suspect they are attempting to
lock RAM. 

I suspect that they are confused by the report from GlobalMemoryStatus
that more than 1GB of RAM is installed, but that they are only able to
VirtualLock up to 1GB. And in this unexpected situation, they are
crashing.

Further, these DLLs are audio processing plugins. The apparent fact that
VirtualLock doesn't _actually_ lock memory into RAM for real time
processing is a disaster for our system, in that it causes audio
glitches when a page fault is handled. But that is not a problem which
crashes the system.

Any suggestions on what to do? Is there any pending work on this area
out there?

I've attached a little table that describes what I found. It shows the
differences in how Wine and WinXP handle memory related calls. I have
also attached a simple program which can be run to see these
differences.

Thanks for any help... mo 

Memory Function Differences Between Wine and WinXP
All sizes are in Kbytes

CALLWINXP   
WINE
=
1. VirtualAlloc(MEM_RESERVE)2,096,912   
1,020,976
2. VirtualAlloc(MEM_COMMIT) 1,011,712 (3)   
1,020,976
3. VirtualAlloc(MEM_COMMIT) 1,024 (1)   
1,020,976
+VirtualLock()
4. VirtualAlloc(MEM_COMMIT)   259,072   
1,020,976 (2)
+SetProcessWorkingSetSize(260,000)
+VirtualLock()
5. GlobalMemoryStatus
RAM   
392,688 386,324
Page  
942,820 522,072
Virtual 
2,097,024   2,097,024
6. GetProcessWorkingSetSize() hi/lo 1,380/200   32,768/32,768 
(2)

tests:
1. calling VirtualAlloc with MEM_RESERVE 1MB at a time until it fails. 
This
is reserving virtual space only. Without the /3GB switch windows memory 
is
limited to 2GB. So each app should be able to reserve its 2GB of space.
call: drink-memory.exe.so -reserve-only -no-lock

2. VirtualAlloc(MEM_COMMIT) 1MB at at time until it fails.  On WinXP 
this
seems to be bounded by how big the paging file is. In Wine...? dunno.
call: drink-memory.exe.so -no-lock

3. VirtualAlloc(MEM_COMMIT) + VirtualLock() 1MB at at time until it 
fails.  
On WinXP this craps out right away because the working set is very 
small,
1.3M (see line 6)
call: drink-memory.exe.so

4. Same as 2. but with SetProcessWorkingSetSize(260,000). That was the
largest value WinXP allowed me to set the working set size to. WinXP
let me lock down RAM up to its limit, as expected. Wine, again, isn't
doing anything special
call: drink-memory.exe.so -lock-limit=26

5. & 6. For reference the memory status reported WinXP and Wine

notes:
(1) VirtualLock fails - 1453 Insufficient quota
(2) FIXME: stub
(3) VirtualAlloc fails - 1455 Paging file is too small
#if _MFC
#include 
#else
#include 		// printf
#include 
#endif

	// process command line options
const char* CheckOption(const char* check, const char* match);
	// like perror() for Windows
void PrintLastError(const char* msg);

int main(int argc, char *argv[])
{
	bool usage = false;
	bool forever = false;
	bool noLock = false;
	bool reserve = false;
	int chunk = 1048576;
	int lockLimit = -1;
	
	for (int arg = 1; !usage && arg < argc; arg++) {
		const char* result;
		if ((result = CheckOption(argv[arg], "-chunk=")) != 0)
			chunk = atoi(result) * 1024;
		else if (CheckOption(argv[arg], "-forever"))
			forever = true;
		else if (CheckOption(argv[arg], "-help"))
			usage = true;
		else if ((result = CheckOption(argv[arg], "-lock-limit=")) != 0)
			lockLimit = atoi(result);
		else if (CheckOption(argv[arg], "-no-lock"))
			noLock = true;
		else if (CheckOption(argv[arg], "-reserve-only"))
			reserve = true;
		else
			usage = true;
	}
	if (usage) {
		puts("usage: wine drink-memory.