Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/mmap.cc')
-rw-r--r--winsup/cygwin/mmap.cc474
1 files changed, 474 insertions, 0 deletions
diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc
new file mode 100644
index 000000000..c0cffc285
--- /dev/null
+++ b/winsup/cygwin/mmap.cc
@@ -0,0 +1,474 @@
+/* mmap.cc
+
+ Copyright 1996, 1997, 1998, 2000 Cygnus Solutions.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#include "winsup.h"
+
+/*
+ * Simple class used to keep a record of all current
+ * mmap areas in a process. Needed so that
+ * they can be duplicated after a fork().
+ */
+
+class mmap_record
+{
+ private:
+ HANDLE mapping_handle_;
+ DWORD access_mode_;
+ DWORD offset_;
+ DWORD size_to_map_;
+ void *base_address_;
+
+ public:
+ mmap_record (HANDLE h, DWORD ac, DWORD o, DWORD s, void *b) :
+ mapping_handle_ (h), access_mode_ (ac), offset_ (o),
+ size_to_map_ (s), base_address_ (b) { ; }
+
+ /* Default Copy constructor/operator=/destructor are ok */
+
+ /* Simple accessors */
+ HANDLE get_handle () const { return mapping_handle_; }
+ DWORD get_access () const { return access_mode_; }
+ DWORD get_offset () const { return offset_; }
+ DWORD get_size () const { return size_to_map_; }
+ void *get_address () const { return base_address_; }
+};
+
+class list {
+public:
+ mmap_record *recs;
+ int nrecs, maxrecs;
+ int fd;
+ list ();
+ ~list ();
+ void add_record (mmap_record r);
+ void erase (int i);
+};
+
+list::list ()
+{
+ recs = (mmap_record *) malloc (10 * sizeof(mmap_record));
+ nrecs = 0;
+ maxrecs = 10;
+ fd = 0;
+}
+
+list::~list ()
+{
+ free (recs);
+}
+
+void
+list::add_record (mmap_record r)
+{
+ if (nrecs == maxrecs)
+ {
+ maxrecs += 5;
+ recs = (mmap_record *) realloc (recs, maxrecs * sizeof (mmap_record));
+ }
+ recs[nrecs++] = r;
+}
+
+void
+list::erase (int i)
+{
+ while (i < nrecs-1)
+ recs[i] = recs[i+1];
+ nrecs--;
+}
+
+class map {
+public:
+ list **lists;
+ int nlists, maxlists;
+ map ();
+ ~map ();
+ list *get_list_by_fd (int fd);
+ list *add_list (list *l, int fd);
+ void erase (int i);
+};
+
+map::map ()
+{
+ lists = (list **) malloc (10 * sizeof(list *));
+ nlists = 0;
+ maxlists = 10;
+}
+
+map::~map ()
+{
+ free (lists);
+}
+
+list *
+map::get_list_by_fd (int fd)
+{
+ int i;
+ for (i=0; i<nlists; i++)
+ if (lists[i]->fd == fd)
+ return lists[i];
+ return 0;
+}
+
+list *
+map::add_list (list *l, int fd)
+{
+ l->fd = fd;
+ if (nlists == maxlists)
+ {
+ maxlists += 5;
+ lists = (list **) realloc (lists, maxlists * sizeof (list *));
+ }
+ lists[nlists++] = l;
+ return lists[nlists-1];
+}
+
+void
+map::erase (int i)
+{
+ while (i < nlists-1)
+ lists[i] = lists[i+1];
+ nlists--;
+}
+
+/*
+ * Code to keep a record of all mmap'ed areas in a process.
+ * Needed to duplicate tham in a child of fork().
+ * mmap_record classes are kept in an STL list in an STL map, keyed
+ * by file descriptor. This is *NOT* duplicated accross a fork(), it
+ * needs to be specially handled by the fork code.
+ */
+
+static NO_COPY map *mmapped_areas;
+
+extern "C"
+caddr_t
+mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
+{
+ syscall_printf ("addr %x, len %d, prot %x, flags %x, fd %d, off %d",
+ addr, len, prot, flags, fd, off);
+
+ SetResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
+
+ /* Windows 95 does not have fixed addresses */
+ if ((os_being_run != winNT) && (flags & MAP_FIXED))
+ {
+ set_errno (EINVAL);
+ syscall_printf ("-1 = mmap(): win95 and MAP_FIXED");
+ return (caddr_t) -1;
+ }
+
+ if (mmapped_areas == 0)
+ {
+ /* First mmap call, create STL map */
+ mmapped_areas = new map;
+ if (mmapped_areas == 0)
+ {
+ set_errno (ENOMEM);
+ syscall_printf ("-1 = mmap(): ENOMEM");
+ return (caddr_t) -1;
+ }
+ }
+
+ DWORD access = (prot & PROT_WRITE) ? FILE_MAP_WRITE : FILE_MAP_READ;
+ if (flags & MAP_PRIVATE)
+ access = FILE_MAP_COPY;
+ DWORD protect;
+
+ if (access & FILE_MAP_COPY)
+ protect = PAGE_WRITECOPY;
+ else if (access & FILE_MAP_WRITE)
+ protect = PAGE_READWRITE;
+ else
+ protect = PAGE_READONLY;
+
+ HANDLE hFile;
+
+ if (fd == -1)
+ hFile = (HANDLE) 0xFFFFFFFF;
+ else
+ {
+ /* Ensure that fd is open */
+ if (dtable.not_open (fd))
+ {
+ set_errno (EBADF);
+ syscall_printf ("-1 = mmap(): EBADF");
+ ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
+ return (caddr_t) -1;
+ }
+ hFile = dtable[fd]->get_handle ();
+ }
+
+ HANDLE h = CreateFileMapping (hFile, &sec_none, protect, 0, len, NULL);
+ if (h == 0)
+ {
+ __seterrno ();
+ syscall_printf ("-1 = mmap(): CreateFileMapping failed with %E");
+ ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
+ return (caddr_t) -1;
+ }
+
+ void *base;
+
+ if (flags & MAP_FIXED)
+ {
+ base = MapViewOfFileEx (h, access, 0, off, len, addr);
+ if (base != addr)
+ {
+ __seterrno ();
+ syscall_printf ("-1 = mmap(): MapViewOfFileEx failed with %E");
+ CloseHandle (h);
+ ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
+ return (caddr_t) -1;
+ }
+ }
+ else
+ {
+ base = MapViewOfFile (h, access, 0, off, len);
+ if (base == 0)
+ {
+ __seterrno ();
+ syscall_printf ("-1 = mmap(): MapViewOfFile failed with %E");
+ CloseHandle (h);
+ ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
+ return (caddr_t) -1;
+ }
+ }
+
+ /* Now we should have a successfully mmaped area.
+ Need to save it so forked children can reproduce it.
+ */
+
+ mmap_record mmap_rec (h, access, off, len, base);
+
+ /* Get list of mmapped areas for this fd, create a new one if
+ one does not exist yet.
+ */
+
+ list *l = mmapped_areas->get_list_by_fd (fd);
+ if (l == 0)
+ {
+ /* Create a new one */
+ l = new list;
+ if (l == 0)
+ {
+ UnmapViewOfFile (base);
+ CloseHandle (h);
+ set_errno (ENOMEM);
+ syscall_printf ("-1 = mmap(): ENOMEM");
+ ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
+ return (caddr_t) -1;
+ }
+ l = mmapped_areas->add_list (l, fd);
+ }
+
+ /* Insert into the list */
+ l->add_record (mmap_rec);
+
+ syscall_printf ("%x = mmap() succeeded", base);
+ ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
+ return (caddr_t) base;
+}
+
+/* munmap () removes an mmapped area. It insists that base area
+ requested is the same as that mmapped, error if not. */
+
+extern "C"
+int
+munmap (caddr_t addr, size_t len)
+{
+ syscall_printf ("munmap (addr %x, len %d)", addr, len);
+
+ SetResourceLock(LOCK_MMAP_LIST,WRITE_LOCK|READ_LOCK," munmap");
+ /* Check if a mmap'ed area was ever created */
+ if (mmapped_areas == 0)
+ {
+ syscall_printf ("-1 = munmap(): mmapped_areas == 0");
+ set_errno (EINVAL);
+ ReleaseResourceLock(LOCK_MMAP_LIST,WRITE_LOCK|READ_LOCK," munmap");
+ return -1;
+ }
+
+ /* Iterate through the map, looking for the mmapped area.
+ Error if not found. */
+
+ int it;
+ for (it = 0; it < mmapped_areas->nlists; ++it)
+ {
+ list *l = mmapped_areas->lists[it];
+ if (l != 0)
+ {
+ int li;
+ for (li = 0; li < l->nrecs; ++li)
+ {
+ mmap_record rec = l->recs[li];
+ if (rec.get_address () == addr)
+ {
+ /* Unmap the area */
+ UnmapViewOfFile (addr);
+ CloseHandle (rec.get_handle ());
+ /* Delete the entry. */
+ l->erase (li);
+ syscall_printf ("0 = munmap(): %x", addr);
+ ReleaseResourceLock(LOCK_MMAP_LIST,WRITE_LOCK|READ_LOCK," munmap");
+ return 0;
+ }
+ }
+ }
+ }
+ set_errno (EINVAL);
+
+ syscall_printf ("-1 = munmap(): EINVAL");
+
+ ReleaseResourceLock(LOCK_MMAP_LIST,WRITE_LOCK|READ_LOCK," munmap");
+ return -1;
+}
+
+/* Sync file with memory. Ignore flags for now. */
+
+extern "C"
+int
+msync (caddr_t addr, size_t len, int flags)
+{
+ syscall_printf ("addr = %x, len = %d, flags = %x",
+ addr, len, flags);
+
+ if (FlushViewOfFile (addr, len) == 0)
+ {
+ syscall_printf ("-1 = msync: %E");
+ __seterrno ();
+ return -1;
+ }
+ syscall_printf ("0 = msync");
+ return 0;
+}
+
+/* Set memory protection */
+
+extern "C"
+int
+mprotect (caddr_t addr, size_t len, int prot)
+{
+ DWORD old_prot;
+ DWORD new_prot = 0;
+
+ syscall_printf ("mprotect (addr %x, len %d, prot %x)", addr, len, prot);
+
+ if (prot == PROT_NONE)
+ new_prot = PAGE_NOACCESS;
+ else
+ {
+ switch (prot)
+ {
+ case PROT_READ | PROT_WRITE | PROT_EXEC:
+ new_prot = PAGE_EXECUTE_READWRITE;
+ break;
+ case PROT_READ | PROT_WRITE:
+ new_prot = PAGE_READWRITE;
+ break;
+ case PROT_READ | PROT_EXEC:
+ new_prot = PAGE_EXECUTE_READ;
+ break;
+ case PROT_READ:
+ new_prot = PAGE_READONLY;
+ break;
+ default:
+ syscall_printf ("-1 = mprotect (): invalid prot value");
+ set_errno (EINVAL);
+ return -1;
+ }
+ }
+
+ if (VirtualProtect (addr, len, new_prot, &old_prot) == 0)
+ {
+ __seterrno ();
+ syscall_printf ("-1 = mprotect (): %E");
+ return -1;
+ }
+
+ syscall_printf ("0 = mprotect ()");
+ return 0;
+}
+
+/*
+ * Call to re-create all the file mappings in a forked
+ * child. Called from the child in initialization. At this
+ * point we are passed a valid mmaped_areas map, and all the
+ * HANDLE's are valid for the child, but none of the
+ * mapped areas are in our address space. We need to iterate
+ * through the map, doing the MapViewOfFile calls.
+ */
+
+int __stdcall
+recreate_mmaps_after_fork (void *param)
+{
+ map *areas = (map *)param;
+ void *base;
+
+ debug_printf ("recreate_mmaps_after_fork, mmapped_areas %p", areas);
+
+ /* Check if a mmapped area was ever created */
+ if (areas == 0)
+ return 0;
+
+ /* Iterate through the map */
+
+ int it;
+
+ for (it = 0; it < areas->nlists; ++it)
+ {
+ list *l = areas->lists[it];
+ if (l != 0)
+ {
+ int li;
+ for (li = 0; li < l->nrecs; ++li)
+ {
+ mmap_record rec = l->recs[li];
+
+ debug_printf ("h %x, access %x, offset %d, size %d, address %p",
+ rec.get_handle (), rec.get_access (), rec.get_offset (),
+ rec.get_size (), rec.get_address ());
+
+ /* Now re-create the MapViewOfFileEx call */
+ base = MapViewOfFileEx (rec.get_handle (),
+ rec.get_access (), 0,
+ rec.get_offset (),
+ rec.get_size (),
+ rec.get_address ());
+ if (base != rec.get_address ())
+ {
+ system_printf ("base address %p fails to match requested address %p",
+ rec.get_address ());
+ return -1;
+ }
+ }
+ }
+ }
+
+ /* Now set our mmap record in case the child forks. */
+ mmapped_areas = areas;
+
+ debug_printf ("succeeded");
+
+ return 0;
+}
+
+/* Set a child mmap ptr from our static one. Used to set child mmap
+ pointer for fork. */
+
+void __stdcall
+set_child_mmap_ptr (pinfo *child)
+{
+ child->mmap_ptr = (void *) mmapped_areas;
+}