⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmap.cc

📁 cygwin, 著名的在win32下模拟unix操作系统的东东
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* mmap.cc   Copyright 1996, 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license.  Please consult the file "CYGWIN_LICENSE" fordetails. */#include "winsup.h"#include <unistd.h>#include <stdlib.h>#include <stddef.h>#include <sys/mman.h>#include <errno.h>#include "security.h"#include "fhandler.h"#include "path.h"#include "dtable.h"#include "cygerrno.h"#include "cygheap.h"#include "pinfo.h"#include "sys/cygwin.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 * they can be duplicated after a fork(). */class mmap_record{  private:    int fdesc_;    HANDLE mapping_handle_;    int devtype_;    DWORD access_mode_;    __off64_t offset_;    DWORD size_to_map_;    caddr_t base_address_;    DWORD *map_map_;  public:    mmap_record (int fd, HANDLE h, DWORD ac, __off64_t o, DWORD s, caddr_t b) :       fdesc_ (fd),       mapping_handle_ (h),       devtype_ (0),       access_mode_ (ac),       offset_ (o),       size_to_map_ (s),       base_address_ (b),       map_map_ (NULL)      {	if (fd >= 0 && !cygheap->fdtab.not_open (fd))	  devtype_ = cygheap->fdtab[fd]->get_device ();      }    /* Default Copy constructor/operator=/destructor are ok */    /* Simple accessors */    int get_fd () const { return fdesc_; }    HANDLE get_handle () const { return mapping_handle_; }    DWORD get_device () const { return devtype_; }    DWORD get_access () const { return access_mode_; }    DWORD get_offset () const { return offset_; }    DWORD get_size () const { return size_to_map_; }    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 (wincap.virtual_protect_works_on_shared_pages ())	  {	    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);    __off64_t map_map (__off64_t off, DWORD len);    BOOL unmap_map (caddr_t addr, DWORD len);    void fixup_map (void);    int access (char *address);    fhandler_base *alloc_fh ();    void free_fh (fhandler_base *fh);};DWORDmmap_record::find_empty (DWORD pages){  DWORD mapped_pages = PAGE_CNT (size_to_map_);  DWORD start;  if (pages > mapped_pages)    return (DWORD)-1;  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;}__off64_tmmap_record::map_map (__off64_t 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;    }  debug_printf ("map_map (fd=%d, off=%D, len=%d)", fdesc_, off, len);  len = PAGE_CNT (len);  if (fdesc_ == -1 && !off)    {      off = find_empty (len);      if (off != (DWORD)-1)	{	  if (wincap.virtual_protect_works_on_shared_pages ()	      && !VirtualProtect (base_address_ + off * getpagesize (),				  len * getpagesize (), prot, &old_prot))	    {	      __seterrno ();	      return (__off64_t)-1;	    }	  while (len-- > 0)	    MAP_SET (off + len);	  return off * getpagesize ();	}      return 0L;    }  off -= offset_;  DWORD start = off / getpagesize ();  if (wincap.virtual_protect_works_on_shared_pages ()      && !VirtualProtect (base_address_ + start * getpagesize (),			  len * getpagesize (), prot, &old_prot))    {      __seterrno ();      return (__off64_t)-1;    }  for (; len-- > 0; ++start)    MAP_SET (start);  return off;}BOOLmmap_record::unmap_map (caddr_t addr, DWORD len){  DWORD old_prot;  DWORD off = addr - base_address_;  off /= getpagesize ();  len = PAGE_CNT (len);  if (wincap.virtual_protect_works_on_shared_pages ()      && !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;}voidmmap_record::fixup_map (){  if (!wincap.virtual_protect_works_on_shared_pages ())    return;  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;    }  for (DWORD off = PAGE_CNT (size_to_map_); off > 0; --off)    VirtualProtect (base_address_ + off * getpagesize (),		    getpagesize (),		    MAP_ISSET (off - 1) ? prot : PAGE_NOACCESS,		    &old_prot);}intmmap_record::access (char *address){  if (address < base_address_ || address >= base_address_ + size_to_map_)    return 0;  DWORD off = (address - base_address_) / getpagesize ();  return MAP_ISSET (off);}static fhandler_disk_file fh_paging_file;fhandler_base *mmap_record::alloc_fh (){  if (get_fd () == -1)    {      fh_paging_file.set_io_handle (INVALID_HANDLE_VALUE);      return &fh_paging_file;    }  /* The file descriptor could have been closed or, even     worse, could have been reused for another file before     the call to fork(). This requires creating a fhandler     of the correct type to be sure to call the method of the     correct class. */  return cygheap->fdtab.build_fhandler (-1, get_device ());}voidmmap_record::free_fh (fhandler_base *fh){  if (get_fd () != -1)    cfree (fh);}class list {public:  mmap_record *recs;  int nrecs, maxrecs;  int fd;  DWORD hash;  list ();  ~list ();  mmap_record *add_record (mmap_record r);  void erase (int i);  void erase ();  mmap_record *match (__off64_t off, DWORD len);  long match (caddr_t addr, DWORD len, long start);};list::list (): nrecs (0), maxrecs (10), fd (0), hash (0){  recs = (mmap_record *) malloc (10 * sizeof (mmap_record));}list::~list (){  for (mmap_record *rec = recs; nrecs-- > 0; ++rec)    rec->free_map ();  free (recs);}mmap_record *list::add_record (mmap_record r){  if (nrecs == maxrecs)    {      maxrecs += 5;      recs = (mmap_record *) realloc (recs, maxrecs * sizeof (mmap_record));    }  recs[nrecs] = r;  recs[nrecs].alloc_map ();  return recs + nrecs++;}/* Used in mmap() */mmap_record *list::match (__off64_t 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 ()			 + (PAGE_CNT (recs[i].get_size ()) * getpagesize ()))	  return recs + i;    }  return NULL;}/* Used in munmap() */longlist::match (caddr_t addr, DWORD len, __off32_t start){  for (int i = start + 1; i < nrecs; ++i)    if (addr >= recs[i].get_address ()	&& addr + len <= recs[i].get_address ()			 + (PAGE_CNT (recs[i].get_size ()) * getpagesize ()))      return i;  return -1;}voidlist::erase (int i){  recs[i].free_map ();  for (; i < nrecs-1; i++)    recs[i] = recs[i+1];  nrecs--;}voidlist::erase (){  erase (nrecs-1);}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 0 /* The fd isn't sufficient since it could already be another file. */    if (lists[i]->fd == fd#else /* so we use the name hash value to identify the file unless	 it's not an anonymous mapping. */    if ((fd == -1 && lists[i]->fd == -1)	|| (fd != -1 && lists[i]->hash == cygheap->fdtab[fd]->get_namehash ()))#endif      return lists[i];  return 0;}list *map::add_list (list *l, int fd){  l->fd = fd;  if (fd != -1)    l->hash = cygheap->fdtab[fd]->get_namehash ();  if (nlists == maxlists)    {      maxlists += 5;      lists = (list **) realloc (lists, maxlists * sizeof (list *));    }  lists[nlists++] = l;  return lists[nlists-1];}voidmap::erase (int i){  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 accross a fork(), it * needs to be specially handled by the fork code. */static map *mmapped_areas;extern "C"caddr_tmmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, __off64_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;    }  /* Error conditions according to SUSv2 */  if (off % getpagesize ()      || (!(flags & MAP_SHARED) && !(flags & MAP_PRIVATE))      || ((flags & MAP_SHARED) && (flags & MAP_PRIVATE))      || ((flags & MAP_FIXED) && ((DWORD)addr % granularity))      || !len)    {      set_errno (EINVAL);      syscall_printf ("-1 = mmap(): EINVAL");      return MAP_FAILED;    }  SetResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");  if (mmapped_areas == NULL)    {      /* First mmap call, create STL map */      mmapped_areas = new map;      if (mmapped_areas == NULL)	{	  set_errno (ENOMEM);	  syscall_printf ("-1 = mmap(): ENOMEM");	  ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");	  return MAP_FAILED;	}    }  if (flags & MAP_ANONYMOUS)    fd = -1;  /* Map always in multipliers of `granularity'-sized chunks. */  __off64_t gran_off = off & ~(granularity - 1);  DWORD gran_len = howmany (off + len, granularity) * granularity - gran_off;  fhandler_base *fh;  caddr_t base = addr;  HANDLE h;  if (fd != -1)    {      /* Ensure that fd is open */      cygheap_fdget cfd (fd);      if (cfd < 0)	{	  syscall_printf ("-1 = mmap(): EBADF");	  ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap");	  return MAP_FAILED;	}      fh = cfd;      if (fh->get_device () == FH_DISK)	{	  DWORD high;	  DWORD low = GetFileSize (fh->get_handle (), &high);	  __off64_t fsiz = ((__off64_t)high << 32) + low;	  fsiz -= gran_off;	  if (gran_len > fsiz)	    gran_len = fsiz;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -