summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/ChangeLog11
-rw-r--r--winsup/cygwin/mmap.cc110
2 files changed, 104 insertions, 17 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 076b0ea31..5079dac1a 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -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
diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc
index d3c4fbefa..068413bb3 100644
--- a/winsup/cygwin/mmap.cc
+++ b/winsup/cygwin/mmap.cc
@@ -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);
@@ -235,6 +236,45 @@ mmap_record::map_pages (_off64_t off, DWORD len)
}
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)
{
DWORD old_prot;
@@ -536,6 +576,21 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, _off64_t off)
fh = &fh_paging_file;
}
+ 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
+ access and don't use named file mapping.
+ copy-on-write doesn't also work properly on 9x with real files.
+ While the changes are not propagated to the file, they are
+ visible to other processes sharing the same file mapping object.
+ Workaround: Don't use named file mapping. That should work since
+ sharing file mappings only works reliable using named
+ file mapping on 9x.
+ */
+ if ((flags & MAP_PRIVATE)
+ && (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
@@ -544,12 +599,14 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, _off64_t off)
if (map_list && fd == -1 && off == 0 && !(flags & MAP_FIXED))
{
mmap_record *rec;
- if ((rec = map_list->search_record (off, len)) != NULL)
+ 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");
+ ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK|WRITE_LOCK,
+ "mmap");
return MAP_FAILED;
}
caddr_t ret = rec->get_address () + off;
@@ -558,21 +615,40 @@ mmap64 (void *addr, size_t len, int prot, int flags, int fd, _off64_t off)
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
- access and don't use named file mapping.
- copy-on-write doesn't also work properly on 9x with real files.
- While the changes are not propagated to the file, they are
- visible to other processes sharing the same file mapping object.
- Workaround: Don't use named file mapping. That should work since
- sharing file mappings only works reliable using named
- file mapping on 9x.
- */
- if ((flags & MAP_PRIVATE)
- && (wincap.has_working_copy_on_write () || fd != -1))
- access = FILE_MAP_COPY;
+ 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.