* 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:
parent
026dcb34c6
commit
4544f7f6a2
@ -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
|
||||||
|
@ -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 ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user