* mmap.cc (class mmap_record): Declare new map_pages method with

address parameter.
	(mmap_record::map_pages): New method with address parameter.
	(mmap64): Evaluate access mode before checking if already existing
	mapping can be used.
	Only use existing mapping if requested access mode matches the one
	in the existing mapping.
	Add check for existing mapping for MAP_FIXED case.
This commit is contained in:
Corinna Vinschen 2005-02-25 11:15:22 +00:00
parent 078f08b81a
commit c68de3a262
2 changed files with 110 additions and 23 deletions

View File

@ -1,3 +1,14 @@
2005-02-25 Corinna Vinschen <corinna@vinschen.de>
* mmap.cc (class mmap_record): Declare new map_pages method with
address parameter.
(mmap_record::map_pages): New method with address parameter.
(mmap64): Evaluate access mode before checking if already existing
mapping can be used.
Only use existing mapping if requested access mode matches the one
in the existing mapping.
Add check for existing mapping for MAP_FIXED case.
2005-02-23 Corinna Vinschen <corinna@vinschen.de>
* localtime.cc: Implement setting __tzrule's offset member using

View File

@ -93,6 +93,7 @@ class mmap_record
DWORD find_unused_pages (DWORD pages);
_off64_t map_pages (_off64_t off, DWORD len);
bool map_pages (caddr_t addr, DWORD len);
bool unmap_pages (caddr_t addr, DWORD len);
int access (caddr_t address);
@ -234,6 +235,45 @@ mmap_record::map_pages (_off64_t off, DWORD len)
return off * getpagesize ();
}
bool
mmap_record::map_pages (caddr_t addr, DWORD len)
{
debug_printf ("map_pages (addr=%x, len=%u)", addr, len);
DWORD prot, old_prot;
DWORD off = addr - base_address_;
off /= getpagesize ();
len = PAGE_CNT (len);
/* First check if the area is unused right now. */
for (DWORD l = 0; l < len; ++l)
if (MAP_ISSET (off + l))
{
set_errno (EINVAL);
return false;
}
switch (access_mode_)
{
case FILE_MAP_WRITE:
prot = PAGE_READWRITE;
break;
case FILE_MAP_READ:
prot = PAGE_READONLY;
break;
default:
prot = PAGE_WRITECOPY;
break;
}
if (wincap.virtual_protect_works_on_shared_pages ()
&& !VirtualProtect (base_address_ + off * getpagesize (),
len * getpagesize (), prot, &old_prot))
{
__seterrno ();
return false;
}
for (; len-- > 0; ++off)
MAP_SET (off);
return true;
}
bool
mmap_record::unmap_pages (caddr_t addr, DWORD len)
{
@ -536,29 +576,6 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, _off64_t off)
fh = &fh_paging_file;
}
list *map_list = mmapped_areas->get_list_by_fd (fd);
/* First check if this mapping matches into the chunk of another
already performed mapping. Only valid for MAP_ANON in a special
case of MAP_PRIVATE. */
if (map_list && fd == -1 && off == 0 && !(flags & MAP_FIXED))
{
mmap_record *rec;
if ((rec = map_list->search_record (off, len)) != NULL)
{
if ((off = rec->map_pages (off, len)) == (_off64_t)-1)
{
syscall_printf ("-1 = mmap()");
ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK|WRITE_LOCK, "mmap");
return MAP_FAILED;
}
caddr_t ret = rec->get_address () + off;
syscall_printf ("%x = mmap() succeeded", ret);
ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
return ret;
}
}
DWORD access = (prot & PROT_WRITE) ? FILE_MAP_WRITE : FILE_MAP_READ;
/* copy-on-write doesn't work at all on 9x using anonymous maps.
Workaround: Anonymous mappings always use normal READ or WRITE
@ -574,6 +591,65 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, _off64_t off)
&& (wincap.has_working_copy_on_write () || fd != -1))
access = FILE_MAP_COPY;
list *map_list = mmapped_areas->get_list_by_fd (fd);
/* First check if this mapping matches into the chunk of another
already performed mapping. Only valid for MAP_ANON in a special
case of MAP_PRIVATE. */
if (map_list && fd == -1 && off == 0 && !(flags & MAP_FIXED))
{
mmap_record *rec;
if ((rec = map_list->search_record (off, len)) != NULL
&& rec->get_access () == access)
{
if ((off = rec->map_pages (off, len)) == (_off64_t)-1)
{
syscall_printf ("-1 = mmap()");
ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK|WRITE_LOCK,
"mmap");
return MAP_FAILED;
}
caddr_t ret = rec->get_address () + off;
syscall_printf ("%x = mmap() succeeded", ret);
ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
return ret;
}
}
if (map_list && fd == -1 && off == 0 && (flags & MAP_FIXED))
{
caddr_t u_addr;
DWORD u_len;
long record_idx = -1;
if ((record_idx = map_list->search_record ((caddr_t)addr, len, u_addr,
u_len, record_idx)) >= 0)
{
mmap_record *rec = map_list->get_record (record_idx);
if (u_addr > (caddr_t)addr || u_addr + len < (caddr_t)addr + len
|| rec->get_access () != access)
{
/* Partial match only, or access mode doesn't match. */
/* FIXME: Handle partial mappings gracefully if adjacent
memory is available. */
set_errno (EINVAL);
syscall_printf ("-1 = mmap()");
ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK,
"mmap");
return MAP_FAILED;
}
if (!rec->map_pages ((caddr_t)addr, len))
{
syscall_printf ("-1 = mmap()");
ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK,
"mmap");
return MAP_FAILED;
}
caddr_t ret = (caddr_t)addr;
syscall_printf ("%x = mmap() succeeded", ret);
ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
return ret;
}
}
caddr_t base = (caddr_t)addr;
/* This shifts the base address to the next lower 64K boundary.
The offset is re-added when evaluating the return value. */