* mmap.cc: include <unistd.h>. Define some bit operations for
the new page map. (mmap_record): Change type of base_address_ to caddr_t. Add map_map_ member. Add several methods to manipulate map_map_. (mmap_record::alloc_map): New method. (mmap_record::free_map): Ditto. (mmap_record::find_empty): Ditto. (mmap_record::map_map): Ditto. (mmap_record::unmap_map): Ditto. (list::add_record): Change return type to `mmap_record *'. Allocate page map. (list::match): New method. (mmap): Partly rewritten to take care for the new page map. Add some parameter checking. (munmap): Ditto.
This commit is contained in:
parent
6d15efce11
commit
c6dd43f263
|
@ -1,3 +1,21 @@
|
|||
Mon Jan 15 20:34:00 2001 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* mmap.cc: include <unistd.h>. Define some bit operations for
|
||||
the new page map.
|
||||
(mmap_record): Change type of base_address_ to caddr_t.
|
||||
Add map_map_ member. Add several methods to manipulate map_map_.
|
||||
(mmap_record::alloc_map): New method.
|
||||
(mmap_record::free_map): Ditto.
|
||||
(mmap_record::find_empty): Ditto.
|
||||
(mmap_record::map_map): Ditto.
|
||||
(mmap_record::unmap_map): Ditto.
|
||||
(list::add_record): Change return type to `mmap_record *'.
|
||||
Allocate page map.
|
||||
(list::match): New method.
|
||||
(mmap): Partly rewritten to take care for the new page map. Add some
|
||||
parameter checking.
|
||||
(munmap): Ditto.
|
||||
|
||||
Mon Jan 15 13:50:00 2001 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* heap.cc (heap_init): Fix extern declaration of getpagesize.
|
||||
|
|
|
@ -9,6 +9,7 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
|||
details. */
|
||||
|
||||
#include "winsup.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/mman.h>
|
||||
|
@ -21,6 +22,15 @@ details. */
|
|||
#include "pinfo.h"
|
||||
#include "security.h"
|
||||
|
||||
#define PAGE_CNT(bytes) howmany(bytes,getpagesize())
|
||||
|
||||
#define PGBITS (sizeof(DWORD)*8)
|
||||
#define MAPSIZE(pages) howmany(pages,PGBITS)
|
||||
|
||||
#define MAP_SET(n) (map_map_[(n)/PGBITS] |= (1L << ((n) % PGBITS)))
|
||||
#define MAP_CLR(n) (map_map_[(n)/PGBITS] &= ~(1L << ((n) % PGBITS)))
|
||||
#define MAP_ISSET(n) (map_map_[(n)/PGBITS] & (1L << ((n) % PGBITS)))
|
||||
|
||||
/*
|
||||
* Simple class used to keep a record of all current
|
||||
* mmap areas in a process. Needed so that
|
||||
|
@ -35,12 +45,13 @@ class mmap_record
|
|||
DWORD access_mode_;
|
||||
DWORD offset_;
|
||||
DWORD size_to_map_;
|
||||
void *base_address_;
|
||||
caddr_t base_address_;
|
||||
DWORD *map_map_;
|
||||
|
||||
public:
|
||||
mmap_record (int fd, HANDLE h, DWORD ac, DWORD o, DWORD s, void *b) :
|
||||
mmap_record (int fd, HANDLE h, DWORD ac, DWORD o, DWORD s, caddr_t b) :
|
||||
fdesc_ (fd), mapping_handle_ (h), access_mode_ (ac), offset_ (o),
|
||||
size_to_map_ (s), base_address_ (b) { ; }
|
||||
size_to_map_ (s), base_address_ (b) , map_map_ (NULL) { ; }
|
||||
|
||||
/* Default Copy constructor/operator=/destructor are ok */
|
||||
|
||||
|
@ -50,9 +61,116 @@ class mmap_record
|
|||
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_; }
|
||||
caddr_t get_address () const { return base_address_; }
|
||||
DWORD *get_map () const { return map_map_; }
|
||||
|
||||
void alloc_map ()
|
||||
{
|
||||
/* Allocate one bit per page */
|
||||
map_map_ = (DWORD *) calloc (MAPSIZE(PAGE_CNT (size_to_map_)),
|
||||
sizeof (DWORD));
|
||||
if (os_being_run == winNT)
|
||||
{
|
||||
DWORD old_prot;
|
||||
if (!VirtualProtect (base_address_, size_to_map_,
|
||||
PAGE_NOACCESS, &old_prot))
|
||||
syscall_printf ("-1 = alloc_map (): %E");
|
||||
}
|
||||
}
|
||||
void free_map () { if (map_map_) free (map_map_); }
|
||||
|
||||
DWORD find_empty (DWORD pages);
|
||||
DWORD map_map (DWORD off, DWORD len);
|
||||
BOOL unmap_map (caddr_t addr, DWORD len);
|
||||
};
|
||||
|
||||
DWORD
|
||||
mmap_record::find_empty (DWORD pages)
|
||||
{
|
||||
DWORD mapped_pages = PAGE_CNT (size_to_map_);
|
||||
DWORD start;
|
||||
|
||||
for (start = 0; start < mapped_pages - pages; ++start)
|
||||
if (!MAP_ISSET (start))
|
||||
{
|
||||
DWORD cnt;
|
||||
for (cnt = 0; cnt < pages; ++cnt)
|
||||
if (MAP_ISSET (start + cnt))
|
||||
break;
|
||||
if (cnt >= pages)
|
||||
return start;
|
||||
}
|
||||
return (DWORD)-1;
|
||||
}
|
||||
|
||||
DWORD
|
||||
mmap_record::map_map (DWORD off, DWORD len)
|
||||
{
|
||||
DWORD prot, old_prot;
|
||||
switch (access_mode_)
|
||||
{
|
||||
case FILE_MAP_WRITE:
|
||||
prot = PAGE_READWRITE;
|
||||
break;
|
||||
case FILE_MAP_READ:
|
||||
prot = PAGE_READONLY;
|
||||
break;
|
||||
default:
|
||||
prot = PAGE_WRITECOPY;
|
||||
break;
|
||||
}
|
||||
|
||||
len = PAGE_CNT (len);
|
||||
if (fdesc_ == -1 && !off)
|
||||
{
|
||||
off = find_empty (len);
|
||||
if (off != (DWORD)-1)
|
||||
{
|
||||
if (os_being_run == winNT
|
||||
&& !VirtualProtect (base_address_ + off * getpagesize (),
|
||||
len * getpagesize (), prot, &old_prot))
|
||||
syscall_printf ("-1 = map_map (): %E");
|
||||
|
||||
while (len-- > 0)
|
||||
MAP_SET (off + len);
|
||||
return off * getpagesize ();
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
off -= offset_;
|
||||
DWORD start = off / getpagesize ();
|
||||
if (os_being_run == winNT
|
||||
&& !VirtualProtect (base_address_ + start * getpagesize (),
|
||||
len * getpagesize (), prot, &old_prot))
|
||||
syscall_printf ("-1 = map_map (): %E");
|
||||
|
||||
for (; len-- > 0; ++start)
|
||||
MAP_SET (start);
|
||||
return off;
|
||||
}
|
||||
|
||||
BOOL
|
||||
mmap_record::unmap_map (caddr_t addr, DWORD len)
|
||||
{
|
||||
DWORD old_prot;
|
||||
DWORD off = addr - base_address_;
|
||||
off /= getpagesize ();
|
||||
len = PAGE_CNT (len);
|
||||
if (os_being_run == winNT
|
||||
&& !VirtualProtect (base_address_ + off * getpagesize (),
|
||||
len * getpagesize (), PAGE_NOACCESS, &old_prot))
|
||||
syscall_printf ("-1 = unmap_map (): %E");
|
||||
|
||||
for (; len-- > 0; ++off)
|
||||
MAP_CLR (off);
|
||||
/* Return TRUE if all pages are free'd which may result in unmapping
|
||||
the whole chunk. */
|
||||
for (len = MAPSIZE(PAGE_CNT (size_to_map_)); len > 0; )
|
||||
if (map_map_[--len])
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
class list {
|
||||
public:
|
||||
mmap_record *recs;
|
||||
|
@ -60,8 +178,10 @@ public:
|
|||
int fd;
|
||||
list ();
|
||||
~list ();
|
||||
void add_record (mmap_record r);
|
||||
mmap_record *add_record (mmap_record r);
|
||||
void erase (int i);
|
||||
mmap_record *match (DWORD off, DWORD len);
|
||||
off_t match (caddr_t addr, DWORD len, off_t start);
|
||||
};
|
||||
|
||||
list::list ()
|
||||
|
@ -74,10 +194,12 @@ list::list ()
|
|||
|
||||
list::~list ()
|
||||
{
|
||||
for (mmap_record *rec = recs; nrecs-- > 0; ++rec)
|
||||
rec->free_map ();
|
||||
free (recs);
|
||||
}
|
||||
|
||||
void
|
||||
mmap_record *
|
||||
list::add_record (mmap_record r)
|
||||
{
|
||||
if (nrecs == maxrecs)
|
||||
|
@ -85,12 +207,47 @@ list::add_record (mmap_record r)
|
|||
maxrecs += 5;
|
||||
recs = (mmap_record *) realloc (recs, maxrecs * sizeof (mmap_record));
|
||||
}
|
||||
recs[nrecs++] = r;
|
||||
recs[nrecs] = r;
|
||||
recs[nrecs].alloc_map ();
|
||||
return recs + nrecs++;
|
||||
}
|
||||
|
||||
/* Used in mmap() */
|
||||
mmap_record *
|
||||
list::match (DWORD off, DWORD len)
|
||||
{
|
||||
if (fd == -1 && !off)
|
||||
{
|
||||
len = PAGE_CNT (len);
|
||||
for (int i = 0; i < nrecs; ++i)
|
||||
if (recs[i].find_empty (len) != (DWORD)-1)
|
||||
return recs + i;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < nrecs; ++i)
|
||||
if (off >= recs[i].get_offset ()
|
||||
&& off + len <= recs[i].get_offset () + recs[i].get_size ())
|
||||
return recs + i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Used in munmap() */
|
||||
off_t
|
||||
list::match (caddr_t addr, DWORD len, off_t start)
|
||||
{
|
||||
for (int i = start + 1; i < nrecs; ++i)
|
||||
if (addr >= recs[i].get_address ()
|
||||
&& addr + len <= recs[i].get_address () + recs[i].get_size ())
|
||||
return i;
|
||||
return (off_t)-1;
|
||||
}
|
||||
|
||||
void
|
||||
list::erase (int i)
|
||||
{
|
||||
recs[i].free_map ();
|
||||
for (; i < nrecs-1; i++)
|
||||
recs[i] = recs[i+1];
|
||||
nrecs--;
|
||||
|
@ -167,10 +324,28 @@ 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);
|
||||
|
||||
static DWORD granularity;
|
||||
if (!granularity)
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo (&si);
|
||||
granularity = si.dwAllocationGranularity;
|
||||
}
|
||||
|
||||
DWORD access = (prot & PROT_WRITE) ? FILE_MAP_WRITE : FILE_MAP_READ;
|
||||
if (flags & MAP_PRIVATE)
|
||||
access = FILE_MAP_COPY;
|
||||
|
||||
/* Error conditions according to SUSv2 */
|
||||
if (off % getpagesize ()
|
||||
|| ((flags & MAP_FIXED) && ((DWORD)addr % granularity))
|
||||
|| !len)
|
||||
{
|
||||
set_errno (EINVAL);
|
||||
syscall_printf ("-1 = mmap(): Invalid parameters");
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
SetResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
|
||||
|
||||
#if 0
|
||||
|
@ -183,7 +358,7 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
|
|||
{
|
||||
set_errno (EINVAL);
|
||||
syscall_printf ("-1 = mmap(): win95 and MAP_FIXED");
|
||||
return (caddr_t) -1;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -195,21 +370,43 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
|
|||
{
|
||||
set_errno (ENOMEM);
|
||||
syscall_printf ("-1 = mmap(): ENOMEM");
|
||||
return (caddr_t) -1;
|
||||
ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
|
||||
return MAP_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & MAP_ANONYMOUS)
|
||||
fd = -1;
|
||||
|
||||
/* First check if this mapping matches into the chunk of another
|
||||
already performed mapping. */
|
||||
list *l = mmapped_areas->get_list_by_fd (fd);
|
||||
if (l)
|
||||
{
|
||||
mmap_record *rec;
|
||||
if ((rec = l->match (off, len)) != NULL)
|
||||
{
|
||||
off = rec->map_map (off, len);
|
||||
caddr_t ret = rec->get_address () + off;
|
||||
syscall_printf ("%x = mmap() succeeded", ret);
|
||||
ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Map always in multipliers of `granularity'-sized chunks. */
|
||||
DWORD gran_off = off & ~(granularity - 1);
|
||||
DWORD gran_len = howmany (len, granularity) * granularity;
|
||||
|
||||
fhandler_disk_file fh_paging_file (NULL);
|
||||
fhandler_base *fh;
|
||||
caddr_t base = addr;
|
||||
HANDLE h;
|
||||
|
||||
if ((flags & MAP_ANONYMOUS) || fd == -1)
|
||||
if (fd == -1)
|
||||
{
|
||||
fh_paging_file.set_io_handle (INVALID_HANDLE_VALUE);
|
||||
fh = &fh_paging_file;
|
||||
/* Ensure that fd is recorded as -1 */
|
||||
fd = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -219,12 +416,19 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
|
|||
set_errno (EBADF);
|
||||
syscall_printf ("-1 = mmap(): EBADF");
|
||||
ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
|
||||
return (caddr_t) -1;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
fh = fdtab[fd];
|
||||
if (fh->get_device () == FH_DISK)
|
||||
{
|
||||
DWORD fsiz = GetFileSize (fh->get_handle (), NULL);
|
||||
fsiz -= gran_off;
|
||||
if (gran_len > fsiz)
|
||||
gran_len = fsiz;
|
||||
}
|
||||
}
|
||||
|
||||
h = fh->mmap (&base, len, access, flags, off);
|
||||
h = fh->mmap (&base, gran_len, access, flags, gran_off);
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
|
@ -232,22 +436,22 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
|
|||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
/* Now we should have a successfully mmaped area.
|
||||
/* Now we should have a successfully mmapped area.
|
||||
Need to save it so forked children can reproduce it.
|
||||
*/
|
||||
mmap_record mmap_rec (fd, h, access, off, len, base);
|
||||
gran_len = PAGE_CNT (gran_len) * getpagesize ();
|
||||
mmap_record mmap_rec (fd, h, access, gran_off, gran_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)
|
||||
{
|
||||
fh->munmap (h, base, len);
|
||||
fh->munmap (h, base, gran_len);
|
||||
set_errno (ENOMEM);
|
||||
syscall_printf ("-1 = mmap(): ENOMEM");
|
||||
ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
|
||||
|
@ -257,11 +461,12 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off)
|
|||
}
|
||||
|
||||
/* Insert into the list */
|
||||
l->add_record (mmap_rec);
|
||||
|
||||
syscall_printf ("%x = mmap() succeeded", base);
|
||||
mmap_record *rec = l->add_record (mmap_rec);
|
||||
off = rec->map_map (off, len);
|
||||
caddr_t ret = rec->get_address () + off;
|
||||
syscall_printf ("%x = mmap() succeeded", ret);
|
||||
ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap");
|
||||
return base;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* munmap () removes an mmapped area. It insists that base area
|
||||
|
@ -273,6 +478,14 @@ munmap (caddr_t addr, size_t len)
|
|||
{
|
||||
syscall_printf ("munmap (addr %x, len %d)", addr, len);
|
||||
|
||||
/* Error conditions according to SUSv2 */
|
||||
if (((DWORD)addr % getpagesize ()) || !len)
|
||||
{
|
||||
set_errno (EINVAL);
|
||||
syscall_printf ("-1 = munmap(): Invalid parameters");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetResourceLock(LOCK_MMAP_LIST,WRITE_LOCK|READ_LOCK," munmap");
|
||||
/* Check if a mmap'ed area was ever created */
|
||||
if (mmapped_areas == NULL)
|
||||
|
@ -292,10 +505,11 @@ munmap (caddr_t addr, size_t len)
|
|||
list *l = mmapped_areas->lists[it];
|
||||
if (l != 0)
|
||||
{
|
||||
for (int li = 0; li < l->nrecs; ++li)
|
||||
off_t li = -1;
|
||||
while ((li = l->match(addr, len, li)) >= 0)
|
||||
{
|
||||
mmap_record rec = l->recs[li];
|
||||
if (rec.get_address () == addr && rec.get_size () == len)
|
||||
mmap_record *rec = l->recs + li;
|
||||
if (rec->unmap_map (addr, len))
|
||||
{
|
||||
int fd = l->fd;
|
||||
fhandler_disk_file fh_paging_file (NULL);
|
||||
|
@ -308,17 +522,17 @@ munmap (caddr_t addr, size_t len)
|
|||
}
|
||||
else
|
||||
fh = fdtab[fd];
|
||||
fh->munmap (rec.get_handle (), addr, len);
|
||||
fh->munmap (rec->get_handle (), addr, len);
|
||||
|
||||
/* 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");
|
||||
|
|
Loading…
Reference in New Issue