-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Safeguards / alternatives for MAP_FIXED mmap? #73
Comments
Recently I ran into a problem with peyla's android port of a Basilisk II codebase where the video mode change was working some of the time but other times it would result in video corruption and/or crashes. Guess what? The video corruption was when the This resulted in repeating patterns of a very spooky automata-looking nature (pelya/BasiliskII-android#9 (comment)), because the change detection would copy the changed framebuffer to the copy, but because of the overlap that copy would go into the original framebuffer at a different screen location, which would then triggering the change detection again for that second location and get copied to a third location, etc. (rinse, repeat) But the problem wasn't just video stuff; for instance quitting would sometimes hang in In that Android port's case since it was the slowest plain vanilla interpreted 68k emulating Basilisk II using "virtual" addressing (i.e. the Mac memory is just a glorified array of bytes you got with glorified But let's look into the case of the video mode change on systems where the fixed allocation is needed. To make it simple let's set aside the The sequence of events for a video mode change at a high level is:
That destructor releases the old framebuffer allocation:
which Then the
That sets the video mode:
Which results in a call to
and only then does it do a fixed framebuffer allocation at the same location (with a new size):
So even in the ideal world where the framebuffer was always the same size and you could only clobber things allocated from when it was freed to when it was allocated again, that's still a fair amount of things, and that's not considering what is happening in other threads. But actually it's not the same size, it's potentially expanding, so it can clobber other things besides. |
There are a variety of tricks already used to address the problem of not really being able to change a fixed allocation like this, that exist in a quality spectrum from a little better than handwaving to kinda sorta working some substantial percentage of the time:
|
Some other hypothetical options:
|
I vaguely remember that previous issues around this had led to an allocation for the framebuffer being done very early in the process, maybe in |
Background:
On a real 68k host, where the Mac memory addresses need to be real host program memory addresses, and for emulation speed on non-68k hosts, macemu can take advantage of having the mac memory in host memory at a fixed location known at compile time, so that the offset between mac addresses and host addresses is fixed. The general case of a fixed offset is
DIRECT_ADDRESSING
; the special case where that offset is0
isREAL_ADDRESSING
. For more information on addressing modes seeTECH
. These fixed offsets are especially useful under JIT where it means you don't have to deal with shuffling a memory offset around, and reserve another register or incur access to another global to get it basically every load/store.Of course this is used for the mac's entire main RAM and ROM, which we know the sizes of at launch time.
But also the framebuffer: The various SDL video implementations basically assume you are doing one of the fixed addressing modes, and always use their
vm_acquire_framebuffer()
to do a fixed allocation for the framebuffer, using whatever suitable OS platform functionality exists invm_alloc.cpp
, and the way the code is organized it needs to free and reallocate that framebuffer as the size changes when we change the video mode.To support a fixed address block on a modern OS with virtual addressing you need to allocate process memory at fixed addresses.
On a platform where there is
mmap()
that supports theMAP_FIXED
flag we use that...The issue:
Unfortunately the common
mmap()
MAP_FIXED
behaviour is that if there is already a memory allocation in the process address space covering the memory address range you asked for, it just cuts it up and deletes the part that overlaps the request and gives it to themmap()
caller instead.And with multiple threads potentially making allocations you can't just use the API to check there are no pages currently in the range and then allocate.
Let me just quote the Linux manpage verbatim:
Here's FreeBSD:
OpenBSD:
Solutions:
There's no way to actually recover if the fixed memory allocation is actually needed and the memory space in the process is already allocated; the only possible improvement to a given fixed allocation call as it concerns memory already allocated is that we detect that it can't not overlap and crash out and at least not give the user a partly working system that is slowly destroying itself. But of course, if we can do the fixed allocations more wisely in the first place, i.e. 1) do them once and never change them and 2) do them as soon as possible at program start so the least possible other stuff is allocated, that would be an improvement irrespective of whether we can detect the overlap or not.
The text was updated successfully, but these errors were encountered: