diff options
author | Christopher Faylor <me@cgf.cx> | 2000-02-17 19:38:33 +0000 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2000-02-17 19:38:33 +0000 |
commit | 1fd5e000ace55b323124c7e556a7a864b972a5c4 (patch) | |
tree | dc4fcf1e5e22a040716ef92c496b8d94959b2baa /winsup/cygwin/mmap.cc | |
parent | 369d8a8fd5e887eca547bf34bccfdf755c9e5397 (diff) | |
download | cygnal-1fd5e000ace55b323124c7e556a7a864b972a5c4.tar.gz cygnal-1fd5e000ace55b323124c7e556a7a864b972a5c4.tar.bz2 cygnal-1fd5e000ace55b323124c7e556a7a864b972a5c4.zip |
import winsup-2000-02-17 snapshot
Diffstat (limited to 'winsup/cygwin/mmap.cc')
-rw-r--r-- | winsup/cygwin/mmap.cc | 474 |
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; +} |