diff options
Diffstat (limited to 'winsup/cygwin')
-rw-r--r-- | winsup/cygwin/ChangeLog | 11 | ||||
-rw-r--r-- | winsup/cygwin/mmap.cc | 110 |
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. |