* mmap.cc: Restructure. Add, remove and rewrite comments throughout

for better readability.  Change function names for better
	understanding.
	(MAP_SET): Accomodate name change from map_map_ to page_map_.
	(MAP_CLR): Ditto.
	(MAP_ISSET): Ditto.
	(mmap_record::page_map_): Rename from page_map_.
	(mmap_record::get_map): Remove.
	(mmap_record::alloc_page_map): Rename from alloc_map. Return bool
	indicating success of cygheap memory allocation.
	(mmap_record::free_page_map): Rename from free_map.
	(mmap_record::fixup_page_map): Rename from fixup_map.
	(mmap_record::find_unused_pages): Rename from find_empty.
	(mmap_record::map_pages): Rename from map_map.
	(mmap_record::unmap_pages): Rename from unmap_map.
	(class list): Make all class members private.
	(list::list): Remove.
	(list::~list): Remove.
	(list::get_fd): New attribute reader.
	(list::get_hash): Ditto.
	(list::get_record): Ditto.
	(list::add_record): Manage all allocation for mmap_records.  Check
	for failed memory allocation and return NULL if so.
	(list::set): New function.
	(list::del_record): Rename from erase. Return true if last mmap_record
	has been deleted, false otherwise. Check for legal incoming index
	value.
	(list::erase): Remove erase/0.
	(list::search_record): Rename from match.
	(map::map): Remove.
	(map::~map): Remove.
	(map::add_list): Manage all allocation for lists.  Check for failed
	memory allocation and return NULL if so.
	(map::get_list): New method.
	(map::del_list): Rename from erase. Check for legal incoming index
	value.
	(mmap64): Check for failed mmap_record memory allocation.  Return
	with MAP_FAILED and errno set to ENOMEM if so.
	(munmap): Rearrange loop using new list and mmap_record accessor
	functions.  Rename loop index variables for better understanding.
	Check if list can be deleted after last mmap_record in it has been
	deleted.
	(msync): Rearrange loop using new list and mmap_record accessor
	functions.  Rename loop index variables for better understanding.
	(fixup_mmaps_after_fork): Ditto.
This commit is contained in:
Corinna Vinschen 2003-09-04 10:27:51 +00:00
parent 026dcb34c6
commit 4544f7f6a2
2 changed files with 331 additions and 252 deletions

View File

@ -1,3 +1,51 @@
2003-09-04 Corinna Vinschen <corinna@vinschen.de>
* mmap.cc: Restructure. Add, remove and rewrite comments throughout
for better readability. Change function names for better
understanding.
(MAP_SET): Accomodate name change from map_map_ to page_map_.
(MAP_CLR): Ditto.
(MAP_ISSET): Ditto.
(mmap_record::page_map_): Rename from page_map_.
(mmap_record::get_map): Remove.
(mmap_record::alloc_page_map): Rename from alloc_map. Return bool
indicating success of cygheap memory allocation.
(mmap_record::free_page_map): Rename from free_map.
(mmap_record::fixup_page_map): Rename from fixup_map.
(mmap_record::find_unused_pages): Rename from find_empty.
(mmap_record::map_pages): Rename from map_map.
(mmap_record::unmap_pages): Rename from unmap_map.
(class list): Make all class members private.
(list::list): Remove.
(list::~list): Remove.
(list::get_fd): New attribute reader.
(list::get_hash): Ditto.
(list::get_record): Ditto.
(list::add_record): Manage all allocation for mmap_records. Check
for failed memory allocation and return NULL if so.
(list::set): New function.
(list::del_record): Rename from erase. Return true if last mmap_record
has been deleted, false otherwise. Check for legal incoming index
value.
(list::erase): Remove erase/0.
(list::search_record): Rename from match.
(map::map): Remove.
(map::~map): Remove.
(map::add_list): Manage all allocation for lists. Check for failed
memory allocation and return NULL if so.
(map::get_list): New method.
(map::del_list): Rename from erase. Check for legal incoming index
value.
(mmap64): Check for failed mmap_record memory allocation. Return
with MAP_FAILED and errno set to ENOMEM if so.
(munmap): Rearrange loop using new list and mmap_record accessor
functions. Rename loop index variables for better understanding.
Check if list can be deleted after last mmap_record in it has been
deleted.
(msync): Rearrange loop using new list and mmap_record accessor
functions. Rename loop index variables for better understanding.
(fixup_mmaps_after_fork): Ditto.
2003-09-03 Christopher Faylor <cgf@redhat.com> 2003-09-03 Christopher Faylor <cgf@redhat.com>
* cxx.cc (new): Fix formatting. Just return result of ccalloc rather * cxx.cc (new): Fix formatting. Just return result of ccalloc rather

View File

@ -27,15 +27,29 @@ details. */
#define PGBITS (sizeof (DWORD)*8) #define PGBITS (sizeof (DWORD)*8)
#define MAPSIZE(pages) howmany ((pages), PGBITS) #define MAPSIZE(pages) howmany ((pages), PGBITS)
#define MAP_SET(n) (map_map_[(n)/PGBITS] |= (1L << ((n) % PGBITS))) #define MAP_SET(n) (page_map_[(n)/PGBITS] |= (1L << ((n) % PGBITS)))
#define MAP_CLR(n) (map_map_[(n)/PGBITS] &= ~(1L << ((n) % PGBITS))) #define MAP_CLR(n) (page_map_[(n)/PGBITS] &= ~(1L << ((n) % PGBITS)))
#define MAP_ISSET(n) (map_map_[(n)/PGBITS] & (1L << ((n) % PGBITS))) #define MAP_ISSET(n) (page_map_[(n)/PGBITS] & (1L << ((n) % PGBITS)))
/* /* Used for accessing the page file (anonymous mmaps). */
* Simple class used to keep a record of all current static fhandler_disk_file fh_paging_file;
* mmap areas in a process. Needed so that
* they can be duplicated after a fork(). /* Class structure used to keep a record of all current mmap areas
*/ in a process. Needed for bookkeeping all mmaps in a process and
for duplicating all mmaps after fork() since mmaps are not propagated
to child processes by Windows. All information must be duplicated
by hand, see fixup_mmaps_after_fork().
The class structure:
One member of class map per process, global variable mmapped_areas.
Contains a dynamic class list array. Each list entry represents all
mapping to a file, keyed by file descriptor and file name hash.
Each list entry contains a dynamic class mmap_record array. Each
mmap_record represents exactly one mapping. For each mapping, there's
an additional so called `page_map'. It's an array of bits, one bit
per mapped memory page. The bit is set if the page is accessible,
unset otherwise. */
class mmap_record class mmap_record
{ {
@ -47,7 +61,7 @@ class mmap_record
_off64_t offset_; _off64_t offset_;
DWORD size_to_map_; DWORD size_to_map_;
caddr_t base_address_; caddr_t base_address_;
DWORD *map_map_; DWORD *page_map_;
public: public:
mmap_record (int fd, HANDLE h, DWORD ac, _off64_t o, DWORD s, caddr_t b) : mmap_record (int fd, HANDLE h, DWORD ac, _off64_t o, DWORD s, caddr_t b) :
@ -58,15 +72,12 @@ class mmap_record
offset_ (o), offset_ (o),
size_to_map_ (s), size_to_map_ (s),
base_address_ (b), base_address_ (b),
map_map_ (NULL) page_map_ (NULL)
{ {
if (fd >= 0 && !cygheap->fdtab.not_open (fd)) if (fd >= 0 && !cygheap->fdtab.not_open (fd))
devtype_ = cygheap->fdtab[fd]->get_device (); devtype_ = cygheap->fdtab[fd]->get_device ();
} }
/* Default Copy constructor/operator=/destructor are ok */
/* Simple accessors */
int get_fd () const { return fdesc_; } int get_fd () const { return fdesc_; }
HANDLE get_handle () const { return mapping_handle_; } HANDLE get_handle () const { return mapping_handle_; }
DWORD get_device () const { return devtype_; } DWORD get_device () const { return devtype_; }
@ -74,22 +85,61 @@ class mmap_record
DWORD get_offset () const { return offset_; } DWORD get_offset () const { return offset_; }
DWORD get_size () const { return size_to_map_; } DWORD get_size () const { return size_to_map_; }
caddr_t get_address () const { return base_address_; } caddr_t get_address () const { return base_address_; }
DWORD *get_map () const { return map_map_; }
void alloc_map (_off64_t off, DWORD len);
void free_map () { if (map_map_) cfree (map_map_); }
DWORD find_empty (DWORD pages); bool alloc_page_map (_off64_t off, DWORD len);
_off64_t map_map (_off64_t off, DWORD len); void free_page_map () { if (page_map_) cfree (page_map_); }
BOOL unmap_map (caddr_t addr, DWORD len); void fixup_page_map (void);
void fixup_map (void);
DWORD find_unused_pages (DWORD pages);
_off64_t map_pages (_off64_t off, DWORD len);
BOOL unmap_pages (caddr_t addr, DWORD len);
int access (caddr_t address); int access (caddr_t address);
fhandler_base *alloc_fh (); fhandler_base *alloc_fh ();
void free_fh (fhandler_base *fh); void free_fh (fhandler_base *fh);
}; };
class list
{
private:
mmap_record *recs;
int nrecs, maxrecs;
int fd;
DWORD hash;
public:
int get_fd () const { return fd; }
DWORD get_hash () const { return hash; }
mmap_record *get_record (int i) { return i >= nrecs ? NULL : recs + i; }
void set (int nfd);
mmap_record *add_record (mmap_record r, _off64_t off, DWORD len);
bool del_record (int i);
void free_recs () { if (recs) cfree (recs); }
mmap_record *search_record (_off64_t off, DWORD len);
long search_record (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len,
long start);
};
class map
{
private:
list *lists;
int nlists, maxlists;
public:
list *get_list (int i) { return i >= nlists ? NULL : lists + i; }
list *get_list_by_fd (int fd);
list *add_list (int fd);
void del_list (int i);
};
/* This is the global map structure pointer. It's allocated once on the
first call to mmap64(). */
static map *mmapped_areas;
DWORD DWORD
mmap_record::find_empty (DWORD pages) mmap_record::find_unused_pages (DWORD pages)
{ {
DWORD mapped_pages = PAGE_CNT (size_to_map_); DWORD mapped_pages = PAGE_CNT (size_to_map_);
DWORD start; DWORD start;
@ -109,12 +159,15 @@ mmap_record::find_empty (DWORD pages)
return (DWORD)-1; return (DWORD)-1;
} }
void bool
mmap_record::alloc_map (_off64_t off, DWORD len) mmap_record::alloc_page_map (_off64_t off, DWORD len)
{ {
/* Allocate one bit per page */ /* Allocate one bit per page */
map_map_ = (DWORD *) ccalloc (HEAP_MMAP, MAPSIZE (PAGE_CNT (size_to_map_)), if (!(page_map_ = (DWORD *) ccalloc (HEAP_MMAP,
sizeof (DWORD)); MAPSIZE (PAGE_CNT (size_to_map_)),
sizeof (DWORD))))
return false;
if (wincap.virtual_protect_works_on_shared_pages ()) if (wincap.virtual_protect_works_on_shared_pages ())
{ {
DWORD old_prot; DWORD old_prot;
@ -135,15 +188,16 @@ mmap_record::alloc_map (_off64_t off, DWORD len)
while (len-- > 0) while (len-- > 0)
MAP_SET (off + len); MAP_SET (off + len);
} }
return true;
} }
_off64_t _off64_t
mmap_record::map_map (_off64_t off, DWORD len) mmap_record::map_pages (_off64_t off, DWORD len)
{ {
/* Used ONLY if this mapping matches into the chunk of another already /* Used ONLY if this mapping matches into the chunk of another already
performed mapping in a special case of MAP_ANON|MAP_PRIVATE. performed mapping in a special case of MAP_ANON|MAP_PRIVATE.
Otherwise it's job is now done by alloc_map(). */ Otherwise it's job is now done by alloc_page_map(). */
DWORD prot, old_prot; DWORD prot, old_prot;
switch (access_mode_) switch (access_mode_)
{ {
@ -158,10 +212,10 @@ mmap_record::map_map (_off64_t off, DWORD len)
break; break;
} }
debug_printf ("map_map (fd=%d, off=%D, len=%u)", fdesc_, off, len); debug_printf ("map_pages (fd=%d, off=%D, len=%u)", fdesc_, off, len);
len = PAGE_CNT (len); len = PAGE_CNT (len);
if ((off = find_empty (len)) == (DWORD)-1) if ((off = find_unused_pages (len)) == (DWORD)-1)
return 0L; return 0L;
if (wincap.virtual_protect_works_on_shared_pages () if (wincap.virtual_protect_works_on_shared_pages ()
&& !VirtualProtect (base_address_ + off * getpagesize (), && !VirtualProtect (base_address_ + off * getpagesize (),
@ -177,7 +231,7 @@ mmap_record::map_map (_off64_t off, DWORD len)
} }
BOOL BOOL
mmap_record::unmap_map (caddr_t addr, DWORD len) mmap_record::unmap_pages (caddr_t addr, DWORD len)
{ {
DWORD old_prot; DWORD old_prot;
DWORD off = addr - base_address_; DWORD off = addr - base_address_;
@ -186,20 +240,20 @@ mmap_record::unmap_map (caddr_t addr, DWORD len)
if (wincap.virtual_protect_works_on_shared_pages () if (wincap.virtual_protect_works_on_shared_pages ()
&& !VirtualProtect (base_address_ + off * getpagesize (), && !VirtualProtect (base_address_ + off * getpagesize (),
len * getpagesize (), PAGE_NOACCESS, &old_prot)) len * getpagesize (), PAGE_NOACCESS, &old_prot))
syscall_printf ("-1 = unmap_map (): %E"); syscall_printf ("-1 = unmap_pages (): %E");
for (; len-- > 0; ++off) for (; len-- > 0; ++off)
MAP_CLR (off); MAP_CLR (off);
/* Return TRUE if all pages are free'd which may result in unmapping /* Return TRUE if all pages are free'd which may result in unmapping
the whole chunk. */ the whole chunk. */
for (len = MAPSIZE (PAGE_CNT (size_to_map_)); len > 0; ) for (len = MAPSIZE (PAGE_CNT (size_to_map_)); len > 0; )
if (map_map_[--len]) if (page_map_[--len])
return FALSE; return FALSE;
return TRUE; return TRUE;
} }
void void
mmap_record::fixup_map () mmap_record::fixup_page_map ()
{ {
if (!wincap.virtual_protect_works_on_shared_pages ()) if (!wincap.virtual_protect_works_on_shared_pages ())
return; return;
@ -232,8 +286,6 @@ mmap_record::access (caddr_t address)
return MAP_ISSET (off); return MAP_ISSET (off);
} }
static fhandler_disk_file fh_paging_file;
fhandler_base * fhandler_base *
mmap_record::alloc_fh () mmap_record::alloc_fh ()
{ {
@ -258,57 +310,38 @@ mmap_record::free_fh (fhandler_base *fh)
cfree (fh); cfree (fh);
} }
class list {
public:
mmap_record *recs;
int nrecs, maxrecs;
int fd;
DWORD hash;
list ();
~list ();
mmap_record *add_record (mmap_record r, _off64_t off, DWORD len);
void erase (int i);
void erase ();
mmap_record *match (_off64_t off, DWORD len);
long match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len,
long start);
};
list::list ()
: nrecs (0), maxrecs (10), fd (0), hash (0)
{
recs = (mmap_record *) cmalloc (HEAP_MMAP, 10 * sizeof (mmap_record));
}
list::~list ()
{
for (mmap_record *rec = recs; nrecs-- > 0; ++rec)
rec->free_map ();
cfree (recs);
}
mmap_record * mmap_record *
list::add_record (mmap_record r, _off64_t off, DWORD len) list::add_record (mmap_record r, _off64_t off, DWORD len)
{ {
if (nrecs == maxrecs) if (nrecs == maxrecs)
{ {
mmap_record *new_recs;
if (maxrecs == 0)
new_recs = (mmap_record *)
cmalloc (HEAP_MMAP, 5 * sizeof (mmap_record));
else
new_recs = (mmap_record *)
crealloc (recs, (maxrecs + 5) * sizeof (mmap_record));
if (!new_recs)
return NULL;
maxrecs += 5; maxrecs += 5;
recs = (mmap_record *) crealloc (recs, maxrecs * sizeof (mmap_record)); recs = new_recs;
} }
recs[nrecs] = r; recs[nrecs] = r;
recs[nrecs].alloc_map (off, len); if (!recs[nrecs].alloc_page_map (off, len))
return NULL;
return recs + nrecs++; return recs + nrecs++;
} }
/* Used in mmap() */ /* Used in mmap() */
mmap_record * mmap_record *
list::match (_off64_t off, DWORD len) list::search_record (_off64_t off, DWORD len)
{ {
if (fd == -1 && !off) if (fd == -1 && !off)
{ {
len = PAGE_CNT (len); len = PAGE_CNT (len);
for (int i = 0; i < nrecs; ++i) for (int i = 0; i < nrecs; ++i)
if (recs[i].find_empty (len) != (DWORD)-1) if (recs[i].find_unused_pages (len) != (DWORD)-1)
return recs + i; return recs + i;
} }
else else
@ -324,7 +357,7 @@ list::match (_off64_t off, DWORD len)
/* Used in munmap() */ /* Used in munmap() */
long long
list::match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, list::search_record (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len,
_off_t start) _off_t start)
{ {
caddr_t low, high; caddr_t low, high;
@ -346,41 +379,27 @@ list::match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len,
} }
void void
list::erase (int i) list::set (int nfd)
{ {
recs[i].free_map (); if ((fd = nfd) != -1)
for (; i < nrecs-1; i++) hash = cygheap->fdtab[fd]->get_namehash ();
recs[i] = recs[i+1]; nrecs = maxrecs = 0;
nrecs--; recs = NULL;
} }
void bool
list::erase () list::del_record (int i)
{ {
erase (nrecs-1); if (i < nrecs)
} {
recs[i].free_page_map ();
class map { for (; i < nrecs - 1; i++)
public: recs[i] = recs[i + 1];
list **lists; nrecs--;
int nlists, maxlists; }
map (); /* Return true if the list is empty which allows the caller to remove
~map (); this list from the list array. */
list *get_list_by_fd (int fd); return !nrecs;
list *add_list (list *l, int fd);
void erase (int i);
};
map::map ()
{
lists = (list **) cmalloc (HEAP_MMAP, 10 * sizeof (list *));
nlists = 0;
maxlists = 10;
}
map::~map ()
{
cfree (lists);
} }
list * list *
@ -388,50 +407,47 @@ map::get_list_by_fd (int fd)
{ {
int i; int i;
for (i=0; i<nlists; i++) for (i=0; i<nlists; i++)
#if 0 /* The fd isn't sufficient since it could already be another file. */ /* The fd isn't sufficient since it could already be the fd of another
if (lists[i]->fd == fd file. So we use the name hash value to identify the file unless
#else /* so we use the name hash value to identify the file unless it's an anonymous mapping in which case the fd (-1) is sufficient. */
it's not an anonymous mapping. */ if ((fd == -1 && lists[i].get_fd () == -1)
if ((fd == -1 && lists[i]->fd == -1) || (fd != -1
|| (fd != -1 && lists[i]->hash == cygheap->fdtab[fd]->get_namehash ())) && lists[i].get_hash () == cygheap->fdtab[fd]->get_namehash ()))
#endif return lists + i;
return lists[i];
return 0; return 0;
} }
list * list *
map::add_list (list *l, int fd) map::add_list (int fd)
{ {
l->fd = fd;
if (fd != -1)
l->hash = cygheap->fdtab[fd]->get_namehash ();
if (nlists == maxlists) if (nlists == maxlists)
{ {
list *new_lists;
if (maxlists == 0)
new_lists = (list *) cmalloc (HEAP_MMAP, 5 * sizeof (list));
else
new_lists = (list *) crealloc (lists, (maxlists + 5) * sizeof (list));
if (!new_lists)
return NULL;
maxlists += 5; maxlists += 5;
lists = (list **) crealloc (lists, maxlists * sizeof (list *)); lists = new_lists;
} }
lists[nlists++] = l; lists[nlists].set (fd);
return lists[nlists-1]; return lists + nlists++;
} }
void void
map::erase (int i) map::del_list (int i)
{ {
for (; i < nlists-1; i++) if (i < nlists)
lists[i] = lists[i+1]; {
nlists--; lists[i].free_recs ();
for (; i < nlists - 1; i++)
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 across a fork(), it
* needs to be specially handled by the fork code.
*/
static map *mmapped_areas;
extern "C" caddr_t extern "C" caddr_t
mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off)
{ {
@ -463,7 +479,7 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off)
if (mmapped_areas == NULL) if (mmapped_areas == NULL)
{ {
/* First mmap call, create STL map */ /* First mmap call, create STL map */
mmapped_areas = new map; mmapped_areas = (map *) ccalloc (HEAP_MMAP, 1, sizeof (map));
if (mmapped_areas == NULL) if (mmapped_areas == NULL)
{ {
set_errno (ENOMEM); set_errno (ENOMEM);
@ -530,9 +546,9 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off)
if (map_list && fd == -1 && off == 0 && !(flags & MAP_FIXED)) if (map_list && fd == -1 && off == 0 && !(flags & MAP_FIXED))
{ {
mmap_record *rec; mmap_record *rec;
if ((rec = map_list->match (off, len)) != NULL) if ((rec = map_list->search_record (off, len)) != NULL)
{ {
if ((off = rec->map_map (off, len)) == (_off64_t)-1) if ((off = rec->map_pages (off, len)) == (_off64_t)-1)
{ {
syscall_printf ("-1 = mmap()"); syscall_printf ("-1 = mmap()");
ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK|WRITE_LOCK, "mmap"); ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK|WRITE_LOCK, "mmap");
@ -574,9 +590,8 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off)
return MAP_FAILED; return MAP_FAILED;
} }
/* Now we should have a successfully mmapped area. /* At this point we should have a successfully mmapped area.
Need to save it so forked children can reproduce it. Now it's time for bookkeeping stuff. */
*/
if (fd == -1) if (fd == -1)
gran_len = PAGE_CNT (gran_len) * getpagesize (); gran_len = PAGE_CNT (gran_len) * getpagesize ();
mmap_record mmap_rec (fd, h, access, gran_off, gran_len, base); mmap_record mmap_rec (fd, h, access, gran_off, gran_len, base);
@ -587,7 +602,7 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off)
if (!map_list) if (!map_list)
{ {
/* Create a new one */ /* Create a new one */
map_list = new list; map_list = mmapped_areas->add_list (fd);
if (!map_list) if (!map_list)
{ {
fh->munmap (h, base, gran_len); fh->munmap (h, base, gran_len);
@ -596,11 +611,20 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off)
ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
return MAP_FAILED; return MAP_FAILED;
} }
map_list = mmapped_areas->add_list (map_list, fd);
} }
/* Insert into the list */ /* Insert into the list */
mmap_record *rec = map_list->add_record (mmap_rec, off, len > gran_len ? gran_len : len); mmap_record *rec = map_list->add_record (mmap_rec, off,
len > gran_len ? gran_len : len);
if (!rec)
{
fh->munmap (h, base, gran_len);
set_errno (ENOMEM);
syscall_printf ("-1 = mmap(): ENOMEM");
ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
return MAP_FAILED;
}
caddr_t ret = rec->get_address () + (off - gran_off); caddr_t ret = rec->get_address () + (off - gran_off);
syscall_printf ("%x = mmap() succeeded", ret); syscall_printf ("%x = mmap() succeeded", ret);
ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");
@ -639,27 +663,33 @@ munmap (caddr_t addr, size_t len)
/* Iterate through the map, unmap pages between addr and addr+len /* Iterate through the map, unmap pages between addr and addr+len
in all maps. */ in all maps. */
list *map_list;
for (int it = 0; it < mmapped_areas->nlists; ++it) for (int list_idx = 0;
(map_list = mmapped_areas->get_list (list_idx));
++list_idx)
{ {
list *map_list = mmapped_areas->lists[it]; long record_idx = -1;
if (map_list) caddr_t u_addr;
DWORD u_len;
while ((record_idx = map_list->search_record(addr, len, u_addr,
u_len, record_idx)) >= 0)
{ {
long li = -1; mmap_record *rec = map_list->get_record (record_idx);
caddr_t u_addr; if (rec->unmap_pages (u_addr, u_len))
DWORD u_len;
while ((li = map_list->match(addr, len, u_addr, u_len, li)) >= 0)
{ {
mmap_record *rec = map_list->recs + li; /* The whole record has been unmapped, so... */
if (rec->unmap_map (u_addr, u_len)) fhandler_base *fh = rec->alloc_fh ();
{ fh->munmap (rec->get_handle (), addr, len);
fhandler_base *fh = rec->alloc_fh (); rec->free_fh (fh);
fh->munmap (rec->get_handle (), addr, len);
rec->free_fh (fh);
/* Delete the entry. */ /* ...delete the record. */
map_list->erase (li); if (map_list->del_record (record_idx--))
{
/* Yay, the last record has been removed from the list,
we can remove the list now, too. */
mmapped_areas->del_list (list_idx--);
break;
} }
} }
} }
@ -700,33 +730,34 @@ msync (caddr_t addr, size_t len, int flags)
/* Iterate through the map, looking for the mmapped area. /* Iterate through the map, looking for the mmapped area.
Error if not found. */ Error if not found. */
for (int it = 0; it < mmapped_areas->nlists; ++it) list *map_list;
for (int list_idx = 0;
(map_list = mmapped_areas->get_list (list_idx));
++list_idx)
{ {
list *map_list = mmapped_areas->lists[it]; mmap_record *rec;
if (map_list != 0) for (int record_idx = 0;
(rec = map_list->get_record (record_idx));
++record_idx)
{ {
for (int li = 0; li < map_list->nrecs; ++li) if (rec->access (addr))
{ {
mmap_record *rec = map_list->recs + li; /* Check whole area given by len. */
if (rec->access (addr)) for (DWORD i = getpagesize (); i < len; ++i)
{ if (!rec->access (addr + i))
/* Check whole area given by len. */ goto invalid_address_range;
for (DWORD i = getpagesize (); i < len; ++i) fhandler_base *fh = rec->alloc_fh ();
if (!rec->access (addr + i)) int ret = fh->msync (rec->get_handle (), addr, len, flags);
goto invalid_address_range; rec->free_fh (fh);
fhandler_base *fh = rec->alloc_fh ();
int ret = fh->msync (rec->get_handle (), addr, len, flags);
rec->free_fh (fh);
if (ret) if (ret)
syscall_printf ("%d = msync(): %E", ret); syscall_printf ("%d = msync(): %E", ret);
else else
syscall_printf ("0 = msync()"); syscall_printf ("0 = msync()");
ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK,
"msync"); "msync");
return 0; return 0;
}
} }
} }
} }
@ -975,94 +1006,94 @@ fixup_mmaps_after_fork (HANDLE parent)
return 0; return 0;
/* Iterate through the map */ /* Iterate through the map */
for (int it = 0; it < mmapped_areas->nlists; ++it) list *map_list;
for (int list_idx = 0;
(map_list = mmapped_areas->get_list (list_idx));
++list_idx)
{ {
list *map_list = mmapped_areas->lists[it]; mmap_record *rec;
if (map_list) for (int record_idx = 0;
(rec = map_list->get_record (record_idx));
++record_idx)
{ {
int li;
for (li = 0; li < map_list->nrecs; ++li) debug_printf ("fd %d, h %x, access %x, offset %D, size %u, address %p",
rec->get_fd (), rec->get_handle (), rec->get_access (),
rec->get_offset (), rec->get_size (), rec->get_address ());
fhandler_base *fh = rec->alloc_fh ();
BOOL ret = fh->fixup_mmap_after_fork (rec->get_handle (),
rec->get_access (),
rec->get_offset (),
rec->get_size (),
rec->get_address ());
rec->free_fh (fh);
if (!ret)
return -1;
if (rec->get_access () == FILE_MAP_COPY)
{ {
mmap_record *rec = map_list->recs + li; for (char *address = rec->get_address ();
address < rec->get_address () + rec->get_size ();
address += getpagesize ())
if (rec->access (address)
&& !ReadProcessMemory (parent, address, address,
getpagesize (), NULL))
{
DWORD old_prot;
DWORD last_error = GetLastError ();
debug_printf ("fd %d, h %x, access %x, offset %D, size %u, address %p", if (last_error != ERROR_PARTIAL_COPY
rec->get_fd (), rec->get_handle (), rec->get_access (), && last_error != ERROR_NOACCESS
rec->get_offset (), rec->get_size (), rec->get_address ()); || !wincap.virtual_protect_works_on_shared_pages ())
fhandler_base *fh = rec->alloc_fh ();
BOOL ret = fh->fixup_mmap_after_fork (rec->get_handle (),
rec->get_access (),
rec->get_offset (),
rec->get_size (),
rec->get_address ());
rec->free_fh (fh);
if (!ret)
return -1;
if (rec->get_access () == FILE_MAP_COPY)
{
for (char *address = rec->get_address ();
address < rec->get_address () + rec->get_size ();
address += getpagesize ())
if (rec->access (address)
&& !ReadProcessMemory (parent, address, address,
getpagesize (), NULL))
{ {
DWORD old_prot; system_printf ("ReadProcessMemory failed for "
DWORD last_error = GetLastError (); "MAP_PRIVATE address %p, %E",
rec->get_address ());
return -1;
}
if (!VirtualProtectEx (parent,
address, getpagesize (),
PAGE_READONLY, &old_prot))
{
system_printf ("VirtualProtectEx failed for "
"MAP_PRIVATE address %p, %E",
rec->get_address ());
return -1;
}
else
{
BOOL ret;
DWORD dummy_prot;
if (last_error != ERROR_PARTIAL_COPY ret = ReadProcessMemory (parent, address, address,
&& last_error != ERROR_NOACCESS getpagesize (), NULL);
|| !wincap.virtual_protect_works_on_shared_pages ()) if (!VirtualProtectEx(parent,
address, getpagesize (),
old_prot, &dummy_prot))
system_printf ("WARNING: VirtualProtectEx to "
"return to previous state "
"in parent failed for "
"MAP_PRIVATE address %p, %E",
rec->get_address ());
if (!VirtualProtect (address, getpagesize (),
old_prot, &dummy_prot))
system_printf ("WARNING: VirtualProtect to copy "
"protection to child failed for"
"MAP_PRIVATE address %p, %E",
rec->get_address ());
if (!ret)
{ {
system_printf ("ReadProcessMemory failed for " system_printf ("ReadProcessMemory (2nd try) "
"failed for "
"MAP_PRIVATE address %p, %E", "MAP_PRIVATE address %p, %E",
rec->get_address ()); rec->get_address ());
return -1; return -1;
} }
if (!VirtualProtectEx (parent,
address, getpagesize (),
PAGE_READONLY, &old_prot))
{
system_printf ("VirtualProtectEx failed for "
"MAP_PRIVATE address %p, %E",
rec->get_address ());
return -1;
}
else
{
BOOL ret;
DWORD dummy_prot;
ret = ReadProcessMemory (parent, address, address,
getpagesize (), NULL);
if (!VirtualProtectEx(parent,
address, getpagesize (),
old_prot, &dummy_prot))
system_printf ("WARNING: VirtualProtectEx to "
"return to previous state "
"in parent failed for "
"MAP_PRIVATE address %p, %E",
rec->get_address ());
if (!VirtualProtect (address, getpagesize (),
old_prot, &dummy_prot))
system_printf ("WARNING: VirtualProtect to copy "
"protection to child failed for"
"MAP_PRIVATE address %p, %E",
rec->get_address ());
if (!ret)
{
system_printf ("ReadProcessMemory (2nd try) "
"failed for "
"MAP_PRIVATE address %p, %E",
rec->get_address ());
return -1;
}
}
} }
} }
rec->fixup_map ();
} }
rec->fixup_page_map ();
} }
} }